1 /*
2  * Copyright (c) 2022-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 
16 #include "cm_napi_dialog_common.h"
17 
18 #include <unordered_map>
19 #include "securec.h"
20 
21 #include "cm_log.h"
22 #include "cm_type.h"
23 
24 #define BYTE_SHIFT_16           0x10
25 #define BYTE_SHIFT_8            0x08
26 #define BYTE_SHIFT_6            6
27 #define BASE64_URL_TABLE_SIZE   0x3F
28 #define BASE64_GROUP_NUM        3
29 #define BYTE_INDEX_ZONE         0
30 #define BYTE_INDEX_ONE          1
31 #define BYTE_INDEX_TWO          2
32 #define BYTE_INDEX_THREE        3
33 #define BASE64_PADDING          "="
34 #define BYTE_END_ONE            1
35 #define BYTE_END_TWO            2
36 
37 static const char g_base64Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
38 namespace CMNapi {
39 namespace {
40 constexpr int CM_MAX_DATA_LEN = 0x6400000; // The maximum length is 100M
41 
42 static const std::string DIALOG_NO_PERMISSION_MSG = "the caller has no permission";
43 static const std::string DIALOG_INVALID_PARAMS_MSG = "the input parameters is invalid";
44 static const std::string DIALOG_GENERIC_MSG = "there is an internal error";
45 static const std::string DIALOG_OPERATION_CANCELS_MSG = "the user cancels the installation operation";
46 static const std::string DIALOG_INSTALL_FAILED_MSG = "the user install certificate failed"
47     " in the certificate manager dialog";
48 static const std::string DIALOG_NOT_SUPPORTED_MSG = "the API is not supported on this device";
49 
50 static const std::unordered_map<int32_t, int32_t> DIALOG_CODE_TO_JS_CODE_MAP = {
51     // invalid params
52     { CMR_DIALOG_ERROR_INVALID_ARGUMENT, PARAM_ERROR },
53     // no permission
54     { CMR_DIALOG_ERROR_PERMISSION_DENIED, HAS_NO_PERMISSION },
55     // internal error
56     { CMR_DIALOG_ERROR_INTERNAL, DIALOG_ERROR_GENERIC },
57     // the user cancels the installation operation
58     { CMR_DIALOG_ERROR_OPERATION_CANCELS, DIALOG_ERROR_OPERATION_CANCELED },
59     // the user install certificate failed in the certificate manager dialog
60     { CMR_DIALOG_ERROR_INSTALL_FAILED, DIALOG_ERROR_INSTALL_FAILED },
61     // the API is not supported on this device
62     { CMR_DIALOG_ERROR_NOT_SUPPORTED, DIALOG_ERROR_NOT_SUPPORTED },
63 };
64 
65 static const std::unordered_map<int32_t, std::string> DIALOG_CODE_TO_MSG_MAP = {
66     { CMR_DIALOG_ERROR_INVALID_ARGUMENT, DIALOG_INVALID_PARAMS_MSG },
67     { CMR_DIALOG_ERROR_PERMISSION_DENIED, DIALOG_NO_PERMISSION_MSG },
68     { CMR_DIALOG_ERROR_INTERNAL, DIALOG_GENERIC_MSG },
69     { CMR_DIALOG_ERROR_OPERATION_CANCELS, DIALOG_OPERATION_CANCELS_MSG },
70     { CMR_DIALOG_ERROR_INSTALL_FAILED, DIALOG_INSTALL_FAILED_MSG },
71     { CMR_DIALOG_ERROR_NOT_SUPPORTED, DIALOG_NOT_SUPPORTED_MSG },
72 };
73 }  // namespace
74 
StartUIExtensionAbility(std::shared_ptr<CmUIExtensionRequestContext> asyncContext,OHOS::AAFwk::Want want,std::shared_ptr<CmUIExtensionCallback> uiExtCallback)75 void StartUIExtensionAbility(std::shared_ptr<CmUIExtensionRequestContext> asyncContext,
76     OHOS::AAFwk::Want want, std::shared_ptr<CmUIExtensionCallback> uiExtCallback)
77 {
78     CM_LOG_D("begin StartUIExtensionAbility");
79     auto abilityContext = asyncContext->context;
80     if (abilityContext == nullptr) {
81         CM_LOG_E("abilityContext is null");
82         ThrowError(asyncContext->env, PARAM_ERROR, "abilityContext is null");
83         return;
84     }
85     auto uiContent = abilityContext->GetUIContent();
86     if (uiContent == nullptr) {
87         CM_LOG_E("uiContent is null");
88         ThrowError(asyncContext->env, PARAM_ERROR, "uiContent is null");
89         return;
90     }
91 
92     OHOS::Ace::ModalUIExtensionCallbacks extensionCallbacks = {
93         [uiExtCallback](int32_t releaseCode) { uiExtCallback->OnRelease(releaseCode); },
94         [uiExtCallback](int32_t resultCode, const OHOS::AAFwk::Want& result) {
95             uiExtCallback->OnResult(resultCode, result); },
96         [uiExtCallback](const OHOS::AAFwk::WantParams& request) { uiExtCallback->OnReceive(request); },
97         [uiExtCallback](int32_t errorCode, const std::string& name, const std::string& message) {
98             uiExtCallback->OnError(errorCode, name, message); },
99         [uiExtCallback](const std::shared_ptr<OHOS::Ace::ModalUIExtensionProxy>& uiProxy) {
100             uiExtCallback->OnRemoteReady(uiProxy); },
101         [uiExtCallback]() { uiExtCallback->OnDestroy(); }
102     };
103 
104     OHOS::Ace::ModalUIExtensionConfig uiExtConfig;
105     uiExtConfig.isProhibitBack = false;
106     int32_t sessionId = uiContent->CreateModalUIExtension(want, extensionCallbacks, uiExtConfig);
107     CM_LOG_I("end CreateModalUIExtension");
108     if (sessionId == 0) {
109         CM_LOG_E("CreateModalUIExtension failed");
110         ThrowError(asyncContext->env, PARAM_ERROR, "CreateModalUIExtension failed");
111     }
112     uiExtCallback->SetSessionId(sessionId);
113     return;
114 }
115 
EncodeBase64(const uint8_t * indata,const uint32_t length)116 static std::string EncodeBase64(const uint8_t *indata, const uint32_t length)
117 {
118     std::string encodeStr("");
119     if (indata == nullptr) {
120         CM_LOG_E("input param is invalid");
121         return encodeStr;
122     }
123     int i = 0;
124     while (i < (int)length) {
125         unsigned int octeta = i < (int)length ? *(indata + (i++)) : 0;
126         unsigned int octetb = i < (int)length ? *(indata + (i++)) : 0;
127         unsigned int octetc = i < (int)length ? *(indata + (i++)) : 0;
128 
129         unsigned int triple = (octeta << BYTE_SHIFT_16) + (octetb << BYTE_SHIFT_8) + octetc;
130 
131         encodeStr += g_base64Table[(triple >> BYTE_INDEX_THREE * BYTE_SHIFT_6) & BASE64_URL_TABLE_SIZE];
132         encodeStr += g_base64Table[(triple >> BYTE_INDEX_TWO   * BYTE_SHIFT_6) & BASE64_URL_TABLE_SIZE];
133         encodeStr += g_base64Table[(triple >> BYTE_INDEX_ONE   * BYTE_SHIFT_6) & BASE64_URL_TABLE_SIZE];
134         encodeStr += g_base64Table[(triple >> BYTE_INDEX_ZONE  * BYTE_SHIFT_6) & BASE64_URL_TABLE_SIZE];
135     }
136 
137     switch (BASE64_GROUP_NUM - (i % BASE64_GROUP_NUM)) {
138         case BYTE_END_TWO:
139             encodeStr.replace(encodeStr.length() - BYTE_END_TWO, 1, BASE64_PADDING);
140             encodeStr.replace(encodeStr.length() - BYTE_END_ONE, 1, BASE64_PADDING);
141             break;
142         case BYTE_END_ONE:
143             encodeStr.replace(encodeStr.length() - BYTE_END_ONE, 1, BASE64_PADDING);
144             break;
145         default:
146             break;
147     }
148     return encodeStr;
149 }
150 
ParseCmUIAbilityContextReq(napi_env env,const napi_value & obj,std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> & abilityContext)151 bool ParseCmUIAbilityContextReq(
152     napi_env env, const napi_value& obj, std::shared_ptr<OHOS::AbilityRuntime::AbilityContext>& abilityContext)
153 {
154     bool stageMode = false;
155     napi_status status = OHOS::AbilityRuntime::IsStageContext(env, obj, stageMode);
156     if (status != napi_ok || !stageMode) {
157         CM_LOG_E("not stage mode");
158         return false;
159     }
160 
161     auto context = OHOS::AbilityRuntime::GetStageModeContext(env, obj);
162     if (context == nullptr) {
163         CM_LOG_E("get context failed");
164         return false;
165     }
166 
167     abilityContext = OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::AbilityContext>(context);
168     if (abilityContext == nullptr) {
169         CM_LOG_E("get abilityContext failed");
170         return false;
171     }
172     CM_LOG_I("end ParseUIAbilityContextReq");
173     return true;
174 }
175 
ParseUint32(napi_env env,napi_value object,uint32_t & store)176 napi_value ParseUint32(napi_env env, napi_value object, uint32_t &store)
177 {
178     napi_valuetype type;
179     napi_typeof(env, object, &type);
180     if (type != napi_number) {
181         CM_LOG_E("param type is not number");
182         return nullptr;
183     }
184     uint32_t temp = 0;
185     napi_get_value_uint32(env, object, &temp);
186     store = temp;
187     return GetInt32(env, 0);
188 }
189 
ParseBoolean(napi_env env,napi_value object,bool & status)190 napi_value ParseBoolean(napi_env env, napi_value object, bool &status)
191 {
192     napi_valuetype type;
193     napi_typeof(env, object, &type);
194     if (type != napi_boolean) {
195         CM_LOG_E("param type is not bool");
196         return nullptr;
197     }
198     bool temp = false;
199     napi_get_value_bool(env, object, &temp);
200     status = temp;
201     return GetInt32(env, 0);
202 }
203 
ParseString(napi_env env,napi_value obj,CmBlob * & blob)204 napi_value ParseString(napi_env env, napi_value obj, CmBlob *&blob)
205 {
206     napi_valuetype type = napi_undefined;
207     NAPI_CALL(env, napi_typeof(env, obj, &type));
208     if (type != napi_string) {
209         CM_LOG_E("the type of param is not string");
210         return nullptr;
211     }
212     size_t length = 0;
213     napi_status status = napi_get_value_string_utf8(env, obj, nullptr, 0, &length);
214     if (status != napi_ok) {
215         GET_AND_THROW_LAST_ERROR((env));
216         CM_LOG_E("could not get string length");
217         return nullptr;
218     }
219 
220     if ((length == 0) || (length > CM_MAX_DATA_LEN)) {
221         CM_LOG_E("input string length is 0 or too large, length: %d", length);
222         return nullptr;
223     }
224 
225     char *data = static_cast<char *>(CmMalloc(length + 1));
226     if (data == nullptr) {
227         napi_throw_error(env, nullptr, "could not alloc memory");
228         CM_LOG_E("could not alloc memory");
229         return nullptr;
230     }
231     (void)memset_s(data, length + 1, 0, length + 1);
232 
233     size_t res = 0;
234     status = napi_get_value_string_utf8(env, obj, data, length + 1, &res);
235     if (status != napi_ok) {
236         CmFree(data);
237         GET_AND_THROW_LAST_ERROR((env));
238         CM_LOG_E("could not get string");
239         return nullptr;
240     }
241 
242     blob = static_cast<CmBlob *>(CmMalloc(sizeof(CmBlob)));
243     if (blob == nullptr) {
244         CmFree(data);
245         napi_throw_error(env, nullptr, "could not alloc memory");
246         CM_LOG_E("could not alloc memory");
247         return nullptr;
248     }
249     blob->data = reinterpret_cast<uint8_t *>(data);
250     blob->size = static_cast<uint32_t>((length + 1) & UINT32_MAX);
251 
252     return GetInt32(env, 0);
253 }
254 
GetUint8ArrayToBase64Str(napi_env env,napi_value object,std::string & certArray)255 napi_value GetUint8ArrayToBase64Str(napi_env env, napi_value object, std::string &certArray)
256 {
257     napi_typedarray_type arrayType;
258     napi_value arrayBuffer = nullptr;
259     size_t length = 0;
260     size_t offset = 0;
261     void *certData = nullptr;
262 
263     napi_status status = napi_get_typedarray_info(
264         env, object, &arrayType, &length, static_cast<void **>(&certData), &arrayBuffer, &offset);
265     if (arrayType != napi_uint8_array) {
266         return nullptr;
267     }
268     if (status != napi_ok) {
269         CM_LOG_E("the type of param is not uint8_array");
270         return nullptr;
271     }
272     if (length > CM_MAX_DATA_LEN) {
273         CM_LOG_E("certData is too large, length = %x", length);
274         return nullptr;
275     }
276     uint8_t *data = nullptr;
277     if (length == 0) {
278         CM_LOG_D("The memory length created is only 1 Byte");
279         // The memory length created is only 1 Byte
280         data = static_cast<uint8_t *>(CmMalloc(1));
281     } else {
282         data = static_cast<uint8_t *>(CmMalloc(length));
283     }
284     if (data == nullptr) {
285         CM_LOG_E("Malloc failed");
286         return nullptr;
287     }
288     (void)memset_s(data, length, 0, length);
289     if (memcpy_s(data, length, certData, length) != EOK) {
290         CmFree(data);
291         CM_LOG_E("memcpy_s fail, length = %x", length);
292         return nullptr;
293     }
294     std::string encode = EncodeBase64(data, length);
295     certArray = encode;
296     CmFree(data);
297     return GetInt32(env, 0);
298 }
299 
GetJsErrorMsg(int32_t errCode)300 static const char *GetJsErrorMsg(int32_t errCode)
301 {
302     auto iter = DIALOG_CODE_TO_MSG_MAP.find(errCode);
303     if (iter != DIALOG_CODE_TO_MSG_MAP.end()) {
304         return (iter->second).c_str();
305     }
306     return DIALOG_GENERIC_MSG.c_str();
307 }
308 
TranformErrorCode(int32_t errorCode)309 int32_t TranformErrorCode(int32_t errorCode)
310 {
311     auto iter = DIALOG_CODE_TO_JS_CODE_MAP.find(errorCode);
312     if (iter != DIALOG_CODE_TO_JS_CODE_MAP.end()) {
313         return iter->second;
314     }
315     return DIALOG_ERROR_GENERIC;
316 }
317 
GenerateBusinessError(napi_env env,int32_t errorCode)318 napi_value GenerateBusinessError(napi_env env, int32_t errorCode)
319 {
320     const char *errorMessage = GetJsErrorMsg(errorCode);
321     if (errorMessage == nullptr) {
322         return nullptr;
323     }
324 
325     napi_value businessErrorMsg = nullptr;
326     NAPI_CALL(env, napi_create_object(env, &businessErrorMsg));
327 
328     napi_value code = nullptr;
329     int32_t outputCode = TranformErrorCode(errorCode);
330     NAPI_CALL(env, napi_create_int32(env, outputCode, &code));
331     NAPI_CALL(env, napi_set_named_property(env, businessErrorMsg, BUSINESS_ERROR_PROPERTY_CODE.c_str(), code));
332     napi_value message = nullptr;
333     NAPI_CALL(env, napi_create_string_utf8(env, errorMessage, NAPI_AUTO_LENGTH, &message));
334     NAPI_CALL(env, napi_set_named_property(env, businessErrorMsg, BUSINESS_ERROR_PROPERTY_MESSAGE.c_str(), message));
335     return businessErrorMsg;
336 }
337 
ThrowError(napi_env env,int32_t errorCode,const std::string errMsg)338 void ThrowError(napi_env env, int32_t errorCode, const std::string errMsg)
339 {
340     napi_value paramsError = nullptr;
341     napi_value outCode = nullptr;
342     napi_value message = nullptr;
343     NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, errorCode, &outCode));
344     NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, errMsg.c_str(), NAPI_AUTO_LENGTH, &message));
345     NAPI_CALL_RETURN_VOID(env, napi_create_error(env, nullptr, message, &paramsError));
346     NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, paramsError,
347         BUSINESS_ERROR_PROPERTY_CODE.c_str(), outCode));
348     NAPI_CALL_RETURN_VOID(env, napi_throw(env, paramsError));
349 }
350 
GeneratePromise(napi_env env,napi_deferred deferred,int32_t resultCode,napi_value * result,int32_t length)351 void GeneratePromise(napi_env env, napi_deferred deferred, int32_t resultCode,
352     napi_value *result, int32_t length)
353 {
354     if (length < RESULT_NUMBER) {
355         return;
356     }
357     if (resultCode == CM_SUCCESS) {
358         NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, deferred, result[1]));
359     } else {
360         NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, deferred, result[0]));
361     }
362 }
363 
364 
365 }  // namespace CertManagerNapi
366