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 #include "iservice_registry.h"
24 #include "bundle_mgr_proxy.h"
25 #include "system_ability_definition.h"
26
27 #define BYTE_SHIFT_16 0x10
28 #define BYTE_SHIFT_8 0x08
29 #define BYTE_SHIFT_6 0x06
30 #define BASE64_URL_TABLE_SIZE 0x3F
31 #define BASE64_GROUP_NUM 3
32 #define BYTE_INDEX_ZONE 0
33 #define BYTE_INDEX_ONE 1
34 #define BYTE_INDEX_TWO 2
35 #define BYTE_INDEX_THREE 3
36 #define BASE64_PADDING "="
37 #define BYTE_END_ONE 1
38 #define BYTE_END_TWO 2
39
40 static const char g_base64Table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
41 namespace CMNapi {
42 namespace {
43 constexpr int CM_MAX_DATA_LEN = 0x6400000; // The maximum length is 100M
44
45 static const std::string DIALOG_NO_PERMISSION_MSG = "the caller has no permission";
46 static const std::string DIALOG_INVALID_PARAMS_MSG = "the input parameters is invalid";
47 static const std::string DIALOG_GENERIC_MSG = "there is an internal error";
48 static const std::string DIALOG_OPERATION_CANCELS_MSG = "the user cancels the installation operation";
49 static const std::string DIALOG_INSTALL_FAILED_MSG = "the user install certificate failed"
50 " in the certificate manager dialog";
51 static const std::string DIALOG_NOT_SUPPORTED_MSG = "the API is not supported on this device";
52
53 static const std::string DIALOG_OPERATION_FAILED_MSG = "the user operation failed "
54 "in the certification manager dialog: ";
55 static const std::string PARSE_CERT_FAILED_MSG = "parse the certificate failed.";
56 static const std::string ADVANCED_SECURITY_MSG = "the device enters advanced security mode.";
57 static const std::string INCORRECT_FORMAT_MSG = "the certificate is in an invalid format.";
58 static const std::string MAX_QUANTITY_REACHED_MSG = "the number of certificates or credentials "
59 "reaches the maxinum allowed.";
60 static const std::string SA_INTERNAL_ERROR_MSG = "sa internal error.";
61 static const std::string NOT_EXIST_MSG = "the certificate dose not exist.";
62 static const std::string NOT_ENTERPRISE_DEVICE_MSG = "The operation does not comply with the device security policy,"
63 "such as the device does not allow users to manage the ca certificate of the global user.";
64
65 static const std::unordered_map<int32_t, int32_t> DIALOG_CODE_TO_JS_CODE_MAP = {
66 // no permission
67 { CMR_DIALOG_ERROR_PERMISSION_DENIED, HAS_NO_PERMISSION },
68 // internal error
69 { CMR_DIALOG_ERROR_INTERNAL, DIALOG_ERROR_GENERIC },
70 // the user cancels the installation operation
71 { CMR_DIALOG_ERROR_OPERATION_CANCELS, DIALOG_ERROR_OPERATION_CANCELED },
72 // the user install certificate failed in the certificate manager dialog
73 { CMR_DIALOG_ERROR_INSTALL_FAILED, DIALOG_ERROR_INSTALL_FAILED },
74 // the API is not supported on this device
75 { CMR_DIALOG_ERROR_NOT_SUPPORTED, DIALOG_ERROR_NOT_SUPPORTED },
76 // The input parameter is invalid
77 { CMR_DIALOG_ERROR_PARAM_INVALID, PARAM_ERROR },
78
79 { CMR_DIALOG_ERROR_PARSE_CERT_FAILED, DIALOG_ERROR_INSTALL_FAILED },
80 { CMR_DIALOG_ERROR_ADVANCED_SECURITY, DIALOG_ERROR_INSTALL_FAILED },
81 { CMR_DIALOG_ERROR_INCORRECT_FORMAT, DIALOG_ERROR_INSTALL_FAILED },
82 { CMR_DIALOG_ERROR_MAX_QUANTITY_REACHED, DIALOG_ERROR_INSTALL_FAILED },
83 { CMR_DIALOG_ERROR_SA_INTERNAL_ERROR, DIALOG_ERROR_INSTALL_FAILED },
84 { CMR_DIALOG_ERROR_NOT_EXIST, DIALOG_ERROR_INSTALL_FAILED },
85 { CMR_DIALOG_ERROR_NOT_ENTERPRISE_DEVICE, DIALOG_ERROR_NOT_COMPLY_SECURITY_POLICY },
86 };
87
88 static const std::unordered_map<int32_t, std::string> DIALOG_CODE_TO_MSG_MAP = {
89 { CMR_DIALOG_ERROR_PERMISSION_DENIED, DIALOG_NO_PERMISSION_MSG },
90 { CMR_DIALOG_ERROR_INTERNAL, DIALOG_GENERIC_MSG },
91 { CMR_DIALOG_ERROR_OPERATION_CANCELS, DIALOG_OPERATION_CANCELS_MSG },
92 { CMR_DIALOG_ERROR_INSTALL_FAILED, DIALOG_INSTALL_FAILED_MSG },
93 { CMR_DIALOG_ERROR_NOT_SUPPORTED, DIALOG_NOT_SUPPORTED_MSG },
94 { CMR_DIALOG_ERROR_NOT_ENTERPRISE_DEVICE, NOT_ENTERPRISE_DEVICE_MSG },
95 { CMR_DIALOG_ERROR_PARAM_INVALID, DIALOG_INVALID_PARAMS_MSG },
96
97 { CMR_DIALOG_ERROR_PARSE_CERT_FAILED, DIALOG_OPERATION_FAILED_MSG + PARSE_CERT_FAILED_MSG },
98 { CMR_DIALOG_ERROR_ADVANCED_SECURITY, DIALOG_OPERATION_FAILED_MSG + ADVANCED_SECURITY_MSG },
99 { CMR_DIALOG_ERROR_INCORRECT_FORMAT, DIALOG_OPERATION_FAILED_MSG + INCORRECT_FORMAT_MSG },
100 { CMR_DIALOG_ERROR_MAX_QUANTITY_REACHED, DIALOG_OPERATION_FAILED_MSG + MAX_QUANTITY_REACHED_MSG },
101 { CMR_DIALOG_ERROR_SA_INTERNAL_ERROR, DIALOG_OPERATION_FAILED_MSG + SA_INTERNAL_ERROR_MSG },
102 { CMR_DIALOG_ERROR_NOT_EXIST, DIALOG_OPERATION_FAILED_MSG + NOT_EXIST_MSG },
103 };
104 } // namespace
105
StartUIExtensionAbility(std::shared_ptr<CmUIExtensionRequestContext> asyncContext,OHOS::AAFwk::Want want,std::shared_ptr<CmUIExtensionCallback> uiExtCallback)106 void StartUIExtensionAbility(std::shared_ptr<CmUIExtensionRequestContext> asyncContext,
107 OHOS::AAFwk::Want want, std::shared_ptr<CmUIExtensionCallback> uiExtCallback)
108 {
109 CM_LOG_D("begin StartUIExtensionAbility");
110 auto abilityContext = asyncContext->context;
111 if (abilityContext == nullptr) {
112 CM_LOG_E("abilityContext is null");
113 ThrowError(asyncContext->env, PARAM_ERROR, "abilityContext is null");
114 return;
115 }
116 auto uiContent = abilityContext->GetUIContent();
117 if (uiContent == nullptr) {
118 CM_LOG_E("uiContent is null");
119 ThrowError(asyncContext->env, PARAM_ERROR, "uiContent is null");
120 return;
121 }
122
123 OHOS::Ace::ModalUIExtensionCallbacks extensionCallbacks = {
124 [uiExtCallback](int32_t releaseCode) { uiExtCallback->OnRelease(releaseCode); },
125 [uiExtCallback](int32_t resultCode, const OHOS::AAFwk::Want& result) {
126 uiExtCallback->OnResult(resultCode, result); },
127 [uiExtCallback](const OHOS::AAFwk::WantParams& request) { uiExtCallback->OnReceive(request); },
128 [uiExtCallback](int32_t errorCode, const std::string& name, const std::string& message) {
129 uiExtCallback->OnError(errorCode, name, message); },
130 [uiExtCallback](const std::shared_ptr<OHOS::Ace::ModalUIExtensionProxy>& uiProxy) {
131 uiExtCallback->OnRemoteReady(uiProxy); },
132 [uiExtCallback]() { uiExtCallback->OnDestroy(); }
133 };
134
135 OHOS::Ace::ModalUIExtensionConfig uiExtConfig;
136 uiExtConfig.isProhibitBack = false;
137 int32_t sessionId = uiContent->CreateModalUIExtension(want, extensionCallbacks, uiExtConfig);
138 CM_LOG_I("end CreateModalUIExtension");
139 if (sessionId == 0) {
140 CM_LOG_E("CreateModalUIExtension failed");
141 ThrowError(asyncContext->env, PARAM_ERROR, "CreateModalUIExtension failed");
142 }
143 uiExtCallback->SetSessionId(sessionId);
144 return;
145 }
146
EncodeBase64(const uint8_t * indata,const uint32_t length)147 static std::string EncodeBase64(const uint8_t *indata, const uint32_t length)
148 {
149 std::string encodeStr("");
150 if (indata == nullptr) {
151 CM_LOG_E("input param is invalid");
152 return encodeStr;
153 }
154 int i = 0;
155 while (i < (int)length) {
156 unsigned int octeta = i < (int)length ? *(indata + (i++)) : 0;
157 unsigned int octetb = i < (int)length ? *(indata + (i++)) : 0;
158 unsigned int octetc = i < (int)length ? *(indata + (i++)) : 0;
159
160 unsigned int triple = (octeta << BYTE_SHIFT_16) + (octetb << BYTE_SHIFT_8) + octetc;
161
162 encodeStr += g_base64Table[(triple >> BYTE_INDEX_THREE * BYTE_SHIFT_6) & BASE64_URL_TABLE_SIZE];
163 encodeStr += g_base64Table[(triple >> BYTE_INDEX_TWO * BYTE_SHIFT_6) & BASE64_URL_TABLE_SIZE];
164 encodeStr += g_base64Table[(triple >> BYTE_INDEX_ONE * BYTE_SHIFT_6) & BASE64_URL_TABLE_SIZE];
165 encodeStr += g_base64Table[(triple >> BYTE_INDEX_ZONE * BYTE_SHIFT_6) & BASE64_URL_TABLE_SIZE];
166 }
167
168 switch (BASE64_GROUP_NUM - (i % BASE64_GROUP_NUM)) {
169 case BYTE_END_TWO:
170 encodeStr.replace(encodeStr.length() - BYTE_END_TWO, 1, BASE64_PADDING);
171 encodeStr.replace(encodeStr.length() - BYTE_END_ONE, 1, BASE64_PADDING);
172 break;
173 case BYTE_END_ONE:
174 encodeStr.replace(encodeStr.length() - BYTE_END_ONE, 1, BASE64_PADDING);
175 break;
176 default:
177 break;
178 }
179 return encodeStr;
180 }
181
ParseCmUIAbilityContextReq(napi_env env,const napi_value & obj,std::shared_ptr<OHOS::AbilityRuntime::AbilityContext> & abilityContext)182 bool ParseCmUIAbilityContextReq(
183 napi_env env, const napi_value& obj, std::shared_ptr<OHOS::AbilityRuntime::AbilityContext>& abilityContext)
184 {
185 bool stageMode = false;
186 napi_status status = OHOS::AbilityRuntime::IsStageContext(env, obj, stageMode);
187 if (status != napi_ok || !stageMode) {
188 CM_LOG_E("not stage mode");
189 return false;
190 }
191
192 auto context = OHOS::AbilityRuntime::GetStageModeContext(env, obj);
193 if (context == nullptr) {
194 CM_LOG_E("get context failed");
195 return false;
196 }
197
198 abilityContext = OHOS::AbilityRuntime::Context::ConvertTo<OHOS::AbilityRuntime::AbilityContext>(context);
199 if (abilityContext == nullptr) {
200 CM_LOG_E("get abilityContext failed");
201 return false;
202 }
203 CM_LOG_I("end ParseUIAbilityContextReq");
204 return true;
205 }
206
ParseUint32(napi_env env,napi_value object,uint32_t & store)207 napi_value ParseUint32(napi_env env, napi_value object, uint32_t &store)
208 {
209 napi_valuetype type;
210 napi_typeof(env, object, &type);
211 if (type != napi_number) {
212 CM_LOG_E("param type is not number");
213 return nullptr;
214 }
215 uint32_t temp = 0;
216 napi_get_value_uint32(env, object, &temp);
217 store = temp;
218 return GetInt32(env, 0);
219 }
220
ParseBoolean(napi_env env,napi_value object,bool & status)221 napi_value ParseBoolean(napi_env env, napi_value object, bool &status)
222 {
223 napi_valuetype type;
224 napi_typeof(env, object, &type);
225 if (type != napi_boolean) {
226 CM_LOG_E("param type is not bool");
227 return nullptr;
228 }
229 bool temp = false;
230 napi_get_value_bool(env, object, &temp);
231 status = temp;
232 return GetInt32(env, 0);
233 }
234
ParseString(napi_env env,napi_value obj,CmBlob * & blob)235 napi_value ParseString(napi_env env, napi_value obj, CmBlob *&blob)
236 {
237 napi_valuetype type = napi_undefined;
238 NAPI_CALL(env, napi_typeof(env, obj, &type));
239 if (type != napi_string) {
240 CM_LOG_E("the type of param is not string");
241 return nullptr;
242 }
243 size_t length = 0;
244 napi_status status = napi_get_value_string_utf8(env, obj, nullptr, 0, &length);
245 if (status != napi_ok) {
246 GET_AND_THROW_LAST_ERROR((env));
247 CM_LOG_E("could not get string length");
248 return nullptr;
249 }
250
251 if ((length == 0) || (length > CM_MAX_DATA_LEN)) {
252 CM_LOG_E("input string length is 0 or too large, length: %d", length);
253 return nullptr;
254 }
255
256 char *data = static_cast<char *>(CmMalloc(length + 1));
257 if (data == nullptr) {
258 napi_throw_error(env, nullptr, "could not alloc memory");
259 CM_LOG_E("could not alloc memory");
260 return nullptr;
261 }
262 (void)memset_s(data, length + 1, 0, length + 1);
263
264 size_t res = 0;
265 status = napi_get_value_string_utf8(env, obj, data, length + 1, &res);
266 if (status != napi_ok) {
267 CmFree(data);
268 GET_AND_THROW_LAST_ERROR((env));
269 CM_LOG_E("could not get string");
270 return nullptr;
271 }
272
273 blob = static_cast<CmBlob *>(CmMalloc(sizeof(CmBlob)));
274 if (blob == nullptr) {
275 CmFree(data);
276 napi_throw_error(env, nullptr, "could not alloc memory");
277 CM_LOG_E("could not alloc memory");
278 return nullptr;
279 }
280 blob->data = reinterpret_cast<uint8_t *>(data);
281 blob->size = static_cast<uint32_t>((length + 1) & UINT32_MAX);
282
283 return GetInt32(env, 0);
284 }
285
GetUint8ArrayToBase64Str(napi_env env,napi_value object,std::string & certArray)286 napi_value GetUint8ArrayToBase64Str(napi_env env, napi_value object, std::string &certArray)
287 {
288 napi_typedarray_type arrayType;
289 napi_value arrayBuffer = nullptr;
290 size_t length = 0;
291 size_t offset = 0;
292 void *certData = nullptr;
293
294 napi_status status = napi_get_typedarray_info(
295 env, object, &arrayType, &length, static_cast<void **>(&certData), &arrayBuffer, &offset);
296 if (arrayType != napi_uint8_array) {
297 return nullptr;
298 }
299 if (status != napi_ok) {
300 CM_LOG_E("the type of param is not uint8_array");
301 return nullptr;
302 }
303 if (length > CM_MAX_DATA_LEN) {
304 CM_LOG_E("certData is too large, length = %x", length);
305 return nullptr;
306 }
307 uint8_t *data = nullptr;
308 if (length == 0) {
309 CM_LOG_D("The memory length created is only 1 Byte");
310 // The memory length created is only 1 Byte
311 data = static_cast<uint8_t *>(CmMalloc(1));
312 } else {
313 data = static_cast<uint8_t *>(CmMalloc(length));
314 }
315 if (data == nullptr) {
316 CM_LOG_E("Malloc failed");
317 return nullptr;
318 }
319 (void)memset_s(data, length, 0, length);
320 if (memcpy_s(data, length, certData, length) != EOK) {
321 CmFree(data);
322 CM_LOG_E("memcpy_s fail, length = %x", length);
323 return nullptr;
324 }
325 std::string encode = EncodeBase64(data, length);
326 certArray = encode;
327 CmFree(data);
328 return GetInt32(env, 0);
329 }
330
GetJsErrorMsg(int32_t errCode)331 static const char *GetJsErrorMsg(int32_t errCode)
332 {
333 auto iter = DIALOG_CODE_TO_MSG_MAP.find(errCode);
334 if (iter != DIALOG_CODE_TO_MSG_MAP.end()) {
335 return (iter->second).c_str();
336 }
337 return DIALOG_GENERIC_MSG.c_str();
338 }
339
TranformErrorCode(int32_t errorCode)340 int32_t TranformErrorCode(int32_t errorCode)
341 {
342 auto iter = DIALOG_CODE_TO_JS_CODE_MAP.find(errorCode);
343 if (iter != DIALOG_CODE_TO_JS_CODE_MAP.end()) {
344 return iter->second;
345 }
346 return DIALOG_ERROR_GENERIC;
347 }
348
GenerateBusinessError(napi_env env,int32_t errorCode)349 napi_value GenerateBusinessError(napi_env env, int32_t errorCode)
350 {
351 const char *errorMessage = GetJsErrorMsg(errorCode);
352 if (errorMessage == nullptr) {
353 return nullptr;
354 }
355
356 napi_value code = nullptr;
357 int32_t outputCode = TranformErrorCode(errorCode);
358 NAPI_CALL(env, napi_create_int32(env, outputCode, &code));
359 napi_value message = nullptr;
360 NAPI_CALL(env, napi_create_string_utf8(env, errorMessage, NAPI_AUTO_LENGTH, &message));
361
362 napi_value businessErrorMsg = nullptr;
363 NAPI_CALL(env, napi_create_error(env, nullptr, message, &businessErrorMsg));
364 NAPI_CALL(env, napi_set_named_property(env, businessErrorMsg, BUSINESS_ERROR_PROPERTY_CODE.c_str(), code));
365 return businessErrorMsg;
366 }
367
ThrowError(napi_env env,int32_t errorCode,const std::string errMsg)368 void ThrowError(napi_env env, int32_t errorCode, const std::string errMsg)
369 {
370 napi_value paramsError = nullptr;
371 napi_value outCode = nullptr;
372 napi_value message = nullptr;
373 NAPI_CALL_RETURN_VOID(env, napi_create_int32(env, errorCode, &outCode));
374 NAPI_CALL_RETURN_VOID(env, napi_create_string_utf8(env, errMsg.c_str(), NAPI_AUTO_LENGTH, &message));
375 NAPI_CALL_RETURN_VOID(env, napi_create_error(env, nullptr, message, ¶msError));
376 NAPI_CALL_RETURN_VOID(env, napi_set_named_property(env, paramsError,
377 BUSINESS_ERROR_PROPERTY_CODE.c_str(), outCode));
378 NAPI_CALL_RETURN_VOID(env, napi_throw(env, paramsError));
379 }
380
GeneratePromise(napi_env env,napi_deferred deferred,int32_t resultCode,napi_value * result,int32_t length)381 void GeneratePromise(napi_env env, napi_deferred deferred, int32_t resultCode,
382 napi_value *result, int32_t length)
383 {
384 if (length < RESULT_NUMBER) {
385 return;
386 }
387 if (resultCode == CM_SUCCESS) {
388 NAPI_CALL_RETURN_VOID(env, napi_resolve_deferred(env, deferred, result[1]));
389 } else {
390 NAPI_CALL_RETURN_VOID(env, napi_reject_deferred(env, deferred, result[0]));
391 }
392 }
393
GetBundleMgrProxy()394 static OHOS::sptr<OHOS::AppExecFwk::BundleMgrProxy> GetBundleMgrProxy()
395 {
396 auto systemAbilityManager = OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
397 if (!systemAbilityManager) {
398 CM_LOG_E("fail to get system ability mgr.");
399 return nullptr;
400 }
401
402 auto remoteObject = systemAbilityManager->GetSystemAbility(OHOS::BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
403 if (!remoteObject) {
404 CM_LOG_E("fail to get bundle manager proxy.");
405 return nullptr;
406 }
407 return OHOS::iface_cast<OHOS::AppExecFwk::BundleMgrProxy>(remoteObject);
408 }
409
GetCallerLabelName(std::shared_ptr<CmUIExtensionRequestContext> asyncContext)410 int32_t GetCallerLabelName(std::shared_ptr<CmUIExtensionRequestContext> asyncContext)
411 {
412 OHOS::sptr<OHOS::AppExecFwk::BundleMgrProxy> bundleMgrProxy = GetBundleMgrProxy();
413 if (bundleMgrProxy == nullptr) {
414 CM_LOG_E("Failed to get bundle manager proxy.");
415 return CM_FAILURE;
416 }
417
418 OHOS::AppExecFwk::BundleInfo bundleInfo;
419 int32_t flags = static_cast<int32_t>(OHOS::AppExecFwk::GetBundleInfoFlag::GET_BUNDLE_INFO_DEFAULT) |
420 static_cast<int32_t>(OHOS::AppExecFwk::GetBundleInfoFlag::GET_BUNDLE_INFO_WITH_APPLICATION) |
421 static_cast<int32_t>(OHOS::AppExecFwk::GetBundleInfoFlag::GET_BUNDLE_INFO_WITH_HAP_MODULE) |
422 static_cast<int32_t>(OHOS::AppExecFwk::GetBundleInfoFlag::GET_BUNDLE_INFO_WITH_ABILITY);
423 int32_t resCode = bundleMgrProxy->GetBundleInfoForSelf(flags, bundleInfo);
424 if (resCode != CM_SUCCESS) {
425 CM_LOG_E("Failed to get bundleInfo, resCode is %d", resCode);
426 return CM_FAILURE;
427 }
428
429 if (asyncContext->context->GetResourceManager() == nullptr) {
430 CM_LOG_E("context get resourcemanager faild");
431 return CMR_ERROR_NULL_POINTER;
432 }
433
434 resCode = asyncContext->context->GetResourceManager()->GetStringById(bundleInfo.applicationInfo.labelId,
435 asyncContext->labelName);
436 if (resCode != CM_SUCCESS) {
437 CM_LOG_E("getStringById is faild, resCode is %d", resCode);
438 return CM_FAILURE;
439 }
440 return CM_SUCCESS;
441 }
442
443
444 } // namespace CertManagerNapi
445