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, ¶msError));
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