1 /*
2  * Copyright (c) 2022 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 
16 #include "hash.h"
17 
18 #include <cstring>
19 #include <string_view>
20 #include <tuple>
21 
22 #include "create_streamhash.h"
23 #include "filemgmt_libhilog.h"
24 #include "hash_file.h"
25 
26 namespace OHOS {
27 namespace FileManagement {
28 namespace ModuleFileIO {
29 using namespace std;
30 using namespace OHOS::FileManagement::LibN;
31 
GetHashAlgorithm(const string & alg)32 static HASH_ALGORITHM_TYPE GetHashAlgorithm(const string &alg)
33 {
34     return (algorithmMaps.find(alg) != algorithmMaps.end()) ? algorithmMaps.at(alg) : HASH_ALGORITHM_TYPE_UNSUPPORTED;
35 }
36 
GetHashArgs(napi_env env,const NFuncArg & funcArg)37 static tuple<bool, unique_ptr<char[]>, HASH_ALGORITHM_TYPE, bool> GetHashArgs(napi_env env, const NFuncArg &funcArg)
38 {
39     bool isPromise = false;
40     auto [resGetFirstArg, path, unused] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8StringPath();
41     if (!resGetFirstArg) {
42         HILOGE("Invalid path");
43         NError(EINVAL).ThrowErr(env);
44         return { false, nullptr, HASH_ALGORITHM_TYPE_UNSUPPORTED, isPromise };
45     }
46 
47     auto [resGetSecondArg, alg, ignore] = NVal(env, funcArg[NARG_POS::SECOND]).ToUTF8String();
48     if (!resGetSecondArg) {
49         HILOGE("Invalid algorithm");
50         NError(EINVAL).ThrowErr(env);
51         return { false, nullptr, HASH_ALGORITHM_TYPE_UNSUPPORTED, isPromise };
52     }
53 
54     HASH_ALGORITHM_TYPE algType = GetHashAlgorithm(alg.get());
55     if (algType == HASH_ALGORITHM_TYPE_UNSUPPORTED) {
56         HILOGE("Invalid algorithm");
57         NError(EINVAL).ThrowErr(env);
58         return { false, nullptr, HASH_ALGORITHM_TYPE_UNSUPPORTED, isPromise };
59     }
60 
61     if (funcArg.GetArgc() == NARG_CNT::THREE && !NVal(env, funcArg[NARG_POS::THIRD]).TypeIs(napi_function)) {
62         HILOGE("Invalid callback");
63         NError(EINVAL).ThrowErr(env);
64         return { false, nullptr, HASH_ALGORITHM_TYPE_UNSUPPORTED, isPromise };
65     }
66 
67     isPromise = funcArg.GetArgc() == NARG_CNT::TWO;
68     return { true, move(path), algType, isPromise };
69 }
70 
Async(napi_env env,napi_callback_info info)71 napi_value Hash::Async(napi_env env, napi_callback_info info)
72 {
73     NFuncArg funcArg(env, info);
74     if (!funcArg.InitArgs(NARG_CNT::TWO, NARG_CNT::THREE)) {
75         HILOGE("Number of arguments unmatched");
76         NError(EINVAL).ThrowErr(env);
77         return nullptr;
78     }
79 
80     auto [succ, fpath, algType, isPromise] = GetHashArgs(env, funcArg);
81     if (!succ) {
82         HILOGE("Failed to get hash args");
83         return nullptr;
84     }
85 
86     auto arg = make_shared<string>();
87     auto cbExec = [fpath = string(fpath.release()), arg, algType = algType, env = env]() -> NError {
88         int ret = EIO;
89         string &res = *arg;
90         if (algType == HASH_ALGORITHM_TYPE_MD5) {
91             tie(ret, res) = DistributedFS::HashFile::HashWithMD5(fpath);
92         } else if (algType == HASH_ALGORITHM_TYPE_SHA1) {
93             tie(ret, res) = DistributedFS::HashFile::HashWithSHA1(fpath);
94         } else if (algType == HASH_ALGORITHM_TYPE_SHA256) {
95             tie(ret, res) = DistributedFS::HashFile::HashWithSHA256(fpath);
96         }
97         return NError(ret);
98     };
99 
100     auto cbComplete = [arg](napi_env env, NError err) -> NVal {
101         if (err) {
102             return { NVal(env, err.GetNapiErr(env)) };
103         }
104 
105         return { NVal::CreateUTF8String(env, *arg) };
106     };
107 
108     NVal thisVar(env, funcArg.GetThisVar());
109     if (isPromise) {
110         return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_HASH_NAME, cbExec, cbComplete).val_;
111     } else {
112         NVal cb(env, funcArg[NARG_POS::THIRD]);
113         return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_HASH_NAME, cbExec, cbComplete).val_;
114     }
115 }
116 
Export()117 bool HashNExporter::Export()
118 {
119     return exports_.AddProp({
120         NVal::DeclareNapiFunction("hash", Hash::Async),
121         NVal::DeclareNapiFunction("createHash", CreateStreamHash::Hash),
122     });
123 }
124 
GetClassName()125 string HashNExporter::GetClassName()
126 {
127     return HashNExporter::className_;
128 }
129 
HashNExporter(napi_env env,napi_value exports)130 HashNExporter::HashNExporter(napi_env env, napi_value exports) : NExporter(env, exports) {}
131 
132 } // namespace ModuleFileIO
133 } // namespace FileManagement
134 } // namespace OHOS