1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "hashstream_n_exporter.h"
16 
17 #include <iomanip>
18 #include <sstream>
19 
20 #include "hashstream_entity.h"
21 
22 namespace OHOS {
23 namespace FileManagement {
24 namespace ModuleFileIO {
25 using namespace std;
26 using namespace OHOS::FileManagement::LibN;
27 
GetHashAlgorithm(const string & alg)28 static HASH_ALGORITHM_TYPE GetHashAlgorithm(const string &alg)
29 {
30     return (algorithmMaps.find(alg) != algorithmMaps.end()) ? algorithmMaps.at(alg) : HASH_ALGORITHM_TYPE_UNSUPPORTED;
31 }
32 
GetHsEntity(napi_env env,napi_value hs_entity)33 static tuple<bool, HashStreamEntity*> GetHsEntity(napi_env env, napi_value hs_entity)
34 {
35     auto hsEntity = NClass::GetEntityOf<HashStreamEntity>(env, hs_entity);
36     if (!hsEntity) {
37         return { false, nullptr };
38     }
39     return { true, hsEntity };
40 }
41 
HashFinal(const unique_ptr<unsigned char[]> & hashBuf,size_t hashLen)42 static string HashFinal(const unique_ptr<unsigned char[]> &hashBuf, size_t hashLen)
43 {
44     stringstream ss;
45     for (size_t i = 0; i < hashLen; ++i) {
46         const int hexPerByte = 2;
47         ss << std::uppercase << std::setfill('0') << std::setw(hexPerByte) << std::hex
48            << static_cast<uint32_t>(hashBuf[i]);
49     }
50 
51     return ss.str();
52 }
53 
SetHsEntity(napi_env env,NFuncArg & funcArg,HASH_ALGORITHM_TYPE algType)54 static napi_value SetHsEntity(napi_env env, NFuncArg &funcArg, HASH_ALGORITHM_TYPE algType)
55 {
56     HashStreamEntity* rawPtr = new (std::nothrow) HashStreamEntity();
57     if (rawPtr == nullptr) {
58         HILOGE("Failed to request heap memory.");
59         NError(ENOMEM).ThrowErr(env);
60         return nullptr;
61     }
62     std::unique_ptr<HashStreamEntity> hsEntity(rawPtr);
63     hsEntity->algType = algType;
64 
65     switch (algType) {
66         case HASH_ALGORITHM_TYPE_MD5: {
67             MD5_CTX ctx;
68             MD5_Init(&ctx);
69             hsEntity->md5Ctx = ctx;
70             break;
71         }
72         case HASH_ALGORITHM_TYPE_SHA1: {
73             SHA_CTX ctx;
74             SHA1_Init(&ctx);
75             hsEntity->shaCtx = ctx;
76             break;
77         }
78         case HASH_ALGORITHM_TYPE_SHA256: {
79             SHA256_CTX ctx;
80             SHA256_Init(&ctx);
81             hsEntity->sha256Ctx = ctx;
82             break;
83         }
84         default:
85             break;
86     }
87     if (!NClass::SetEntityFor<HashStreamEntity>(env, funcArg.GetThisVar(), move(hsEntity))) {
88         HILOGE("INNER BUG. Failed to wrap entity for obj hsEntity");
89         NError(EIO).ThrowErr(env);
90         return nullptr;
91     }
92     return funcArg.GetThisVar();
93 }
94 
Constructor(napi_env env,napi_callback_info info)95 napi_value HashStreamNExporter::Constructor(napi_env env, napi_callback_info info)
96 {
97     NFuncArg funcArg(env, info);
98     if (!funcArg.InitArgs(NARG_CNT::ONE)) {
99         HILOGE("Number of arguments unmatched");
100         NError(EINVAL).ThrowErr(env);
101         return nullptr;
102     }
103 
104     auto [succAlg, alg, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
105     if (!succAlg) {
106         HILOGE("Invalid algorithm");
107         NError(EINVAL).ThrowErr(env);
108         return nullptr;
109     }
110 
111     HASH_ALGORITHM_TYPE algType = GetHashAlgorithm(alg.get());
112     if (algType == HASH_ALGORITHM_TYPE_UNSUPPORTED) {
113         HILOGE("Unsupport algorithm");
114         NError(EINVAL).ThrowErr(env);
115         return nullptr;
116     }
117 
118     return SetHsEntity(env, funcArg, algType);
119 }
120 
Digest(napi_env env,napi_callback_info info)121 napi_value HashStreamNExporter::Digest(napi_env env, napi_callback_info info)
122 {
123     NFuncArg funcArg(env, info);
124     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
125         HILOGE("Number of arguments unmatched");
126         NError(EINVAL).ThrowErr(env);
127         return nullptr;
128     }
129     auto [succEntity, hsEntity] = GetHsEntity(env, funcArg.GetThisVar());
130     if (!succEntity) {
131         HILOGE("Failed to get entity of RandomAccessFile");
132         NError(EIO).ThrowErr(env);
133         return nullptr;
134     }
135 
136     string digestStr;
137     switch (hsEntity->algType) {
138         case HASH_ALGORITHM_TYPE_MD5: {
139             auto res = make_unique<unsigned char[]>(MD5_DIGEST_LENGTH);
140             MD5_Final(res.get(), &hsEntity->md5Ctx);
141             digestStr = HashFinal(res, MD5_DIGEST_LENGTH);
142             break;
143         }
144         case HASH_ALGORITHM_TYPE_SHA1: {
145             auto res = make_unique<unsigned char[]>(SHA_DIGEST_LENGTH);
146             SHA1_Final(res.get(), &hsEntity->shaCtx);
147             digestStr = HashFinal(res, SHA_DIGEST_LENGTH);
148             break;
149         }
150         case HASH_ALGORITHM_TYPE_SHA256: {
151             auto res = make_unique<unsigned char[]>(SHA256_DIGEST_LENGTH);
152             SHA256_Final(res.get(), &hsEntity->sha256Ctx);
153             digestStr = HashFinal(res, SHA256_DIGEST_LENGTH);
154             break;
155         }
156         default:
157             break;
158     }
159 
160     return NVal::CreateUTF8String(env, digestStr).val_;
161 }
162 
Update(napi_env env,napi_callback_info info)163 napi_value HashStreamNExporter::Update(napi_env env, napi_callback_info info)
164 {
165     NFuncArg funcArg(env, info);
166     if (!funcArg.InitArgs(NARG_CNT::ONE)) {
167         HILOGE("Number of arguments unmatched");
168         NError(EINVAL).ThrowErr(env);
169         return nullptr;
170     }
171 
172     auto [succ, buf, bufLen] = NVal(env, funcArg[NARG_POS::FIRST]).ToArraybuffer();
173     if (!succ) {
174         HILOGE("illegal array buffer");
175         NError(EINVAL).ThrowErr(env);
176         return nullptr;
177     }
178 
179     auto [succEntity, hsEntity] = GetHsEntity(env, funcArg.GetThisVar());
180     if (!succEntity) {
181         HILOGE("Failed to get entity of RandomAccessFile");
182         NError(EIO).ThrowErr(env);
183         return nullptr;
184     }
185 
186     switch (hsEntity->algType) {
187         case HASH_ALGORITHM_TYPE_MD5:
188             MD5_Update(&hsEntity->md5Ctx, buf, bufLen);
189             break;
190         case HASH_ALGORITHM_TYPE_SHA1:
191             SHA1_Update(&hsEntity->shaCtx, buf, bufLen);
192             break;
193         case HASH_ALGORITHM_TYPE_SHA256:
194             SHA256_Update(&hsEntity->sha256Ctx, buf, bufLen);
195             break;
196         default:
197             break;
198     }
199     return NVal::CreateUndefined(env).val_;
200 }
201 
Export()202 bool HashStreamNExporter::Export()
203 {
204     vector<napi_property_descriptor> props = {
205         NVal::DeclareNapiFunction("digest", Digest),
206         NVal::DeclareNapiFunction("update", Update),
207     };
208     string className = GetClassName();
209     bool succ = false;
210     napi_value classValue = nullptr;
211     tie(succ, classValue) = NClass::DefineClass(exports_.env_, className,
212         HashStreamNExporter::Constructor, move(props));
213     if (!succ) {
214         HILOGE("INNER BUG. Failed to define class");
215         NError(EIO).ThrowErr(exports_.env_);
216         return false;
217     }
218     succ = NClass::SaveClass(exports_.env_, className, classValue);
219     if (!succ) {
220         HILOGE("INNER BUG. Failed to define class");
221         NError(EIO).ThrowErr(exports_.env_);
222         return false;
223     }
224 
225     return exports_.AddProp(className, classValue);
226 }
227 
GetClassName()228 string HashStreamNExporter::GetClassName()
229 {
230     return HashStreamNExporter::className_;
231 }
232 
HashStreamNExporter(napi_env env,napi_value exports)233 HashStreamNExporter::HashStreamNExporter(napi_env env, napi_value exports) : NExporter(env, exports) {}
234 
~HashStreamNExporter()235 HashStreamNExporter::~HashStreamNExporter() {}
236 }
237 }
238 }