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_grant.h"
17
18 #include "securec.h"
19
20 #include "cert_manager_api.h"
21 #include "cm_log.h"
22 #include "cm_mem.h"
23 #include "cm_type.h"
24 #include "cm_napi_common.h"
25 #include "cm_util.h"
26
27 namespace CMNapi {
28 namespace {
29 constexpr int CM_NAPI_GRANT_ARGS_CNT = 3;
30 constexpr int CM_NAPI_IS_AUTHED_ARGS_CNT = 2;
31 constexpr int CM_NAPI_CALLBACK_ARG_CNT = 1;
32
33 constexpr uint32_t OUT_AUTH_URI_SIZE = 1000;
34 constexpr uint32_t OUT_AUTH_LIST_SIZE = 512;
35 constexpr uint32_t OUT_UINT32_STRING_SIZE = 16;
36 } // namespace
37
38 struct GrantAsyncContextT {
39 napi_async_work asyncWork = nullptr;
40 napi_deferred deferred = nullptr;
41 napi_ref callback = nullptr;
42
43 int32_t errCode = 0;
44 uint32_t appUid = 0;
45 struct CmBlob *keyUri = nullptr;
46 struct CmBlob *authUri = nullptr;
47 struct CmAppUidList *uidList = nullptr;
48 };
49 using GrantAsyncContext = GrantAsyncContextT *;
50
InitGrantAsyncContext(void)51 static GrantAsyncContext InitGrantAsyncContext(void)
52 {
53 GrantAsyncContext context = static_cast<GrantAsyncContext>(CmMalloc(sizeof(GrantAsyncContextT)));
54 if (context != nullptr) {
55 (void)memset_s(context, sizeof(GrantAsyncContextT), 0, sizeof(GrantAsyncContextT));
56 }
57 return context;
58 }
59
FreeGrantAsyncContext(napi_env env, GrantAsyncContext &context)60 static void FreeGrantAsyncContext(napi_env env, GrantAsyncContext &context)
61 {
62 if (context == nullptr) {
63 return;
64 }
65
66 DeleteNapiContext(env, context->asyncWork, context->callback);
67 FreeCmBlob(context->keyUri);
68 FreeCmBlob(context->authUri);
69 if (context->uidList != nullptr) {
70 CM_FREE_PTR(context->uidList->appUid);
71 CM_FREE_PTR(context->uidList);
72 }
73 CM_FREE_PTR(context);
74 }
75
ParseString2Uint32(napi_env env, napi_value object, uint32_t &value)76 static napi_value ParseString2Uint32(napi_env env, napi_value object, uint32_t &value)
77 {
78 struct CmBlob *blob = nullptr;
79 napi_value result = ParseString(env, object, blob);
80 if (result == nullptr ||
81 CmIsNumeric(reinterpret_cast<char *>(blob->data), static_cast<size_t>(blob->size), &value) != CM_SUCCESS) {
82 CM_LOG_E("parse string to uint32 failed");
83 if (blob != nullptr) {
84 CM_FREE_PTR(blob->data);
85 CmFree(blob);
86 }
87 return nullptr;
88 }
89
90 CM_FREE_PTR(blob->data);
91 CM_FREE_PTR(blob);
92 return GetInt32(env, 0);
93 }
94
ParseGrantUidParams(napi_env env, napi_callback_info info, GrantAsyncContext context)95 static napi_value ParseGrantUidParams(napi_env env, napi_callback_info info, GrantAsyncContext context)
96 {
97 size_t argc = CM_NAPI_GRANT_ARGS_CNT;
98 napi_value argv[CM_NAPI_GRANT_ARGS_CNT] = { nullptr };
99 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
100
101 if ((argc != CM_NAPI_GRANT_ARGS_CNT) && (argc != (CM_NAPI_GRANT_ARGS_CNT - CM_NAPI_CALLBACK_ARG_CNT))) {
102 ThrowError(env, PARAM_ERROR, "arguments count invalid when grant or remove uid");
103 CM_LOG_E("arguments count is not expected when grant or remove uid");
104 return nullptr;
105 }
106
107 size_t index = 0;
108 napi_value result = ParseString(env, argv[index], context->keyUri);
109 if (result == nullptr) {
110 ThrowError(env, PARAM_ERROR, "keyUri type error");
111 CM_LOG_E("get uri failed when grant or remove uid");
112 return nullptr;
113 }
114
115 index++;
116 result = ParseString2Uint32(env, argv[index], context->appUid);
117 if (result == nullptr) {
118 ThrowError(env, PARAM_ERROR, "appUid type error");
119 CM_LOG_E("get app uid failed when grant or remove uid ");
120 return nullptr;
121 }
122
123 index++;
124 if (index < argc) {
125 int32_t ret = GetCallback(env, argv[index], context->callback);
126 if (ret != CM_SUCCESS) {
127 ThrowError(env, PARAM_ERROR, "Get callback type failed.");
128 CM_LOG_E("get callback function failed when grant or remove uid");
129 return nullptr;
130 }
131 }
132
133 return GetInt32(env, 0);
134 }
135
ParseRemoveUidParams(napi_env env, napi_callback_info info, GrantAsyncContext context)136 static napi_value ParseRemoveUidParams(napi_env env, napi_callback_info info, GrantAsyncContext context)
137 {
138 return ParseGrantUidParams(env, info, context);
139 }
140
ParseIsAuthedParams(napi_env env, napi_callback_info info, GrantAsyncContext context)141 static napi_value ParseIsAuthedParams(napi_env env, napi_callback_info info, GrantAsyncContext context)
142 {
143 size_t argc = CM_NAPI_IS_AUTHED_ARGS_CNT;
144 napi_value argv[CM_NAPI_IS_AUTHED_ARGS_CNT] = { nullptr };
145 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
146
147 if ((argc != CM_NAPI_IS_AUTHED_ARGS_CNT) && (argc != (CM_NAPI_IS_AUTHED_ARGS_CNT - CM_NAPI_CALLBACK_ARG_CNT))) {
148 ThrowError(env, PARAM_ERROR, "arguments count invalid, arguments count need between 1 and 2.");
149 CM_LOG_E("arguments count is not expected when using isAuthed");
150 return nullptr;
151 }
152
153 size_t index = 0;
154 napi_value result = ParseString(env, argv[index], context->keyUri);
155 if (result == nullptr) {
156 ThrowError(env, PARAM_ERROR, "keyUri is not a string or the length is 0 or too long.");
157 CM_LOG_E("get uri failed when using isAuthed");
158 return nullptr;
159 }
160
161 index++;
162 if (index < argc) {
163 int32_t ret = GetCallback(env, argv[index], context->callback);
164 if (ret != CM_SUCCESS) {
165 ThrowError(env, PARAM_ERROR, "Get callback failed, callback must be a function.");
166 CM_LOG_E("get callback function failed when using isAuthed");
167 return nullptr;
168 }
169 }
170
171 return GetInt32(env, 0);
172 }
173
174
ParseGetUidListParams(napi_env env, napi_callback_info info, GrantAsyncContext context)175 static napi_value ParseGetUidListParams(napi_env env, napi_callback_info info, GrantAsyncContext context)
176 {
177 return ParseIsAuthedParams(env, info, context);
178 }
179
GrantUidExecute(napi_env env, void *data)180 static void GrantUidExecute(napi_env env, void *data)
181 {
182 GrantAsyncContext context = static_cast<GrantAsyncContext>(data);
183 context->authUri = static_cast<CmBlob *>(CmMalloc(sizeof(CmBlob)));
184 if (context->authUri == nullptr) {
185 CM_LOG_E("malloc authUri failed");
186 context->errCode = CMR_ERROR_MALLOC_FAIL;
187 return;
188 }
189 (void)memset_s(context->authUri, sizeof(CmBlob), 0, sizeof(CmBlob));
190
191 context->authUri->data = static_cast<uint8_t *>(CmMalloc(OUT_AUTH_URI_SIZE));
192 if (context->authUri->data == nullptr) {
193 CM_LOG_E("malloc authUri.data failed");
194 context->errCode = CMR_ERROR_MALLOC_FAIL;
195 return;
196 }
197 (void)memset_s(context->authUri->data, OUT_AUTH_URI_SIZE, 0, OUT_AUTH_URI_SIZE);
198 context->authUri->size = OUT_AUTH_URI_SIZE;
199
200 context->errCode = CmGrantAppCertificate(context->keyUri, context->appUid, context->authUri);
201 }
202
ConvertResultAuthUri(napi_env env, const CmBlob *authUri)203 static napi_value ConvertResultAuthUri(napi_env env, const CmBlob *authUri)
204 {
205 napi_value result = nullptr;
206 NAPI_CALL(env, napi_create_object(env, &result));
207
208 napi_value authUriNapi = nullptr;
209 NAPI_CALL(env, napi_create_string_latin1(env,
210 reinterpret_cast<const char *>(authUri->data), NAPI_AUTO_LENGTH, &authUriNapi));
211 NAPI_CALL(env, napi_set_named_property(env, result, "uri", authUriNapi));
212
213 return result;
214 }
215
GrantUidComplete(napi_env env, napi_status status, void *data)216 static void GrantUidComplete(napi_env env, napi_status status, void *data)
217 {
218 GrantAsyncContext context = static_cast<GrantAsyncContext>(data);
219 napi_value result[RESULT_NUMBER] = { nullptr };
220 if (context->errCode == CM_SUCCESS) {
221 napi_create_uint32(env, 0, &result[0]);
222 result[1] = ConvertResultAuthUri(env, context->authUri);
223 } else {
224 result[0] = GenerateBusinessError(env, context->errCode);
225 napi_get_undefined(env, &result[1]);
226 }
227
228 if (context->deferred != nullptr) {
229 GeneratePromise(env, context->deferred, context->errCode, result, CM_ARRAY_SIZE(result));
230 } else {
231 GenerateCallback(env, context->callback, result, CM_ARRAY_SIZE(result), context->errCode);
232 }
233 FreeGrantAsyncContext(env, context);
234 }
235
RemoveUidExecute(napi_env env, void *data)236 static void RemoveUidExecute(napi_env env, void *data)
237 {
238 GrantAsyncContext context = static_cast<GrantAsyncContext>(data);
239 context->errCode = CmRemoveGrantedApp(context->keyUri, context->appUid);
240 }
241
RemoveOrIsAuthedComplete(napi_env env, napi_status status, void *data)242 static void RemoveOrIsAuthedComplete(napi_env env, napi_status status, void *data)
243 {
244 GrantAsyncContext context = static_cast<GrantAsyncContext>(data);
245 napi_value result[RESULT_NUMBER] = { nullptr };
246 if (context->errCode == CM_SUCCESS) {
247 napi_create_uint32(env, 0, &result[0]);
248 napi_get_boolean(env, true, &result[1]);
249 } else if (context->errCode == CMR_ERROR_AUTH_CHECK_FAILED) {
250 napi_create_uint32(env, 0, &result[0]);
251 napi_get_boolean(env, false, &result[1]);
252 context->errCode = CM_SUCCESS;
253 } else {
254 result[0] = GenerateBusinessError(env, context->errCode);
255 napi_get_undefined(env, &result[1]);
256 }
257
258 if (context->deferred != nullptr) {
259 GeneratePromise(env, context->deferred, context->errCode, result, CM_ARRAY_SIZE(result));
260 } else {
261 GenerateCallback(env, context->callback, result, CM_ARRAY_SIZE(result), context->errCode);
262 }
263 FreeGrantAsyncContext(env, context);
264 }
265
IsAuthedExecute(napi_env env, void *data)266 static void IsAuthedExecute(napi_env env, void *data)
267 {
268 GrantAsyncContext context = static_cast<GrantAsyncContext>(data);
269 context->errCode = CmIsAuthorizedApp(context->keyUri);
270 }
271
GetUidListExecute(napi_env env, void *data)272 static void GetUidListExecute(napi_env env, void *data)
273 {
274 GrantAsyncContext context = static_cast<GrantAsyncContext>(data);
275 context->uidList = static_cast<CmAppUidList *>(CmMalloc(sizeof(CmAppUidList)));
276 if (context->uidList == nullptr) {
277 CM_LOG_E("malloc uid list failed");
278 context->errCode = CMR_ERROR_MALLOC_FAIL;
279 return;
280 }
281 (void)memset_s(context->uidList, sizeof(CmAppUidList), 0, sizeof(CmAppUidList));
282
283 uint32_t uidListSize = OUT_AUTH_LIST_SIZE * sizeof(uint32_t);
284 context->uidList->appUid = static_cast<uint32_t *>(CmMalloc(uidListSize));
285 if (context->uidList->appUid == nullptr) {
286 CM_LOG_E("malloc uid_list.appUid failed");
287 context->errCode = CMR_ERROR_MALLOC_FAIL;
288 return;
289 }
290 (void)memset_s(context->uidList->appUid, uidListSize, 0, uidListSize);
291 context->uidList->appUidCount = OUT_AUTH_LIST_SIZE;
292
293 context->errCode = CmGetAuthorizedAppList(context->keyUri, context->uidList);
294 }
295
ConvertResultAuthList(napi_env env, const CmAppUidList *appUidList)296 static napi_value ConvertResultAuthList(napi_env env, const CmAppUidList *appUidList)
297 {
298 napi_value result = nullptr;
299 NAPI_CALL(env, napi_create_object(env, &result));
300
301 napi_value uidListArray = nullptr;
302 NAPI_CALL(env, napi_create_array(env, &uidListArray));
303
304 for (uint32_t i = 0; i < appUidList->appUidCount; ++i) {
305 char uidStr[OUT_UINT32_STRING_SIZE] = {0};
306 if (snprintf_s(uidStr, sizeof(uidStr), sizeof(uidStr) - 1, "%u", appUidList->appUid[i]) < 0) {
307 CM_LOG_E("uid to string failed");
308 return result;
309 }
310
311 napi_value element = nullptr;
312 NAPI_CALL(env, napi_create_string_latin1(env, static_cast<const char *>(uidStr), NAPI_AUTO_LENGTH, &element));
313 NAPI_CALL(env, napi_set_element(env, uidListArray, i, element));
314 }
315
316 NAPI_CALL(env, napi_set_named_property(env, result, "appUidList", uidListArray));
317 return result;
318 }
319
GetUidListComplete(napi_env env, napi_status status, void *data)320 static void GetUidListComplete(napi_env env, napi_status status, void *data)
321 {
322 GrantAsyncContext context = static_cast<GrantAsyncContext>(data);
323 napi_value result[RESULT_NUMBER] = { nullptr };
324 if (context->errCode == CM_SUCCESS) {
325 napi_create_uint32(env, 0, &result[0]);
326 result[1] = ConvertResultAuthList(env, context->uidList);
327 } else {
328 result[0] = GenerateBusinessError(env, context->errCode);
329 napi_get_undefined(env, &result[1]);
330 }
331
332 if (context->deferred != nullptr) {
333 GeneratePromise(env, context->deferred, context->errCode, result, CM_ARRAY_SIZE(result));
334 } else {
335 GenerateCallback(env, context->callback, result, CM_ARRAY_SIZE(result), context->errCode);
336 }
337 FreeGrantAsyncContext(env, context);
338 }
339
GrantUidAsyncWork(napi_env env, GrantAsyncContext context)340 static napi_value GrantUidAsyncWork(napi_env env, GrantAsyncContext context)
341 {
342 napi_value promise = nullptr;
343 GenerateNapiPromise(env, context->callback, &context->deferred, &promise);
344
345 napi_value resourceName = nullptr;
346 NAPI_CALL(env, napi_create_string_latin1(env, "grantAppCertificate", NAPI_AUTO_LENGTH, &resourceName));
347
348 NAPI_CALL(env, napi_create_async_work(
349 env, nullptr, resourceName,
350 GrantUidExecute,
351 GrantUidComplete,
352 static_cast<void *>(context),
353 &context->asyncWork));
354
355 napi_status status = napi_queue_async_work(env, context->asyncWork);
356 if (status != napi_ok) {
357 ThrowError(env, INNER_FAILURE, "queue asyncWork error");
358 CM_LOG_E("get async work failed when granting uid");
359 return nullptr;
360 }
361 return promise;
362 }
363
RemoveUidAsyncWork(napi_env env, GrantAsyncContext context)364 static napi_value RemoveUidAsyncWork(napi_env env, GrantAsyncContext context)
365 {
366 napi_value promise = nullptr;
367 GenerateNapiPromise(env, context->callback, &context->deferred, &promise);
368
369 napi_value resourceName = nullptr;
370 NAPI_CALL(env, napi_create_string_latin1(env, "removeGrantedAppCertificate", NAPI_AUTO_LENGTH, &resourceName));
371
372 NAPI_CALL(env, napi_create_async_work(
373 env, nullptr, resourceName,
374 RemoveUidExecute,
375 RemoveOrIsAuthedComplete,
376 static_cast<void *>(context),
377 &context->asyncWork));
378
379 napi_status status = napi_queue_async_work(env, context->asyncWork);
380 if (status != napi_ok) {
381 ThrowError(env, INNER_FAILURE, "queue asyncWork error");
382 CM_LOG_E("queue async work failed when removing uid");
383 return nullptr;
384 }
385 return promise;
386 }
387
IsAuthedAsyncWork(napi_env env, GrantAsyncContext context)388 static napi_value IsAuthedAsyncWork(napi_env env, GrantAsyncContext context)
389 {
390 napi_value promise = nullptr;
391 GenerateNapiPromise(env, context->callback, &context->deferred, &promise);
392
393 napi_value resourceName = nullptr;
394 NAPI_CALL(env, napi_create_string_latin1(env, "isAuthorizedApp", NAPI_AUTO_LENGTH, &resourceName));
395
396 NAPI_CALL(env, napi_create_async_work(
397 env, nullptr, resourceName,
398 IsAuthedExecute,
399 RemoveOrIsAuthedComplete,
400 static_cast<void *>(context),
401 &context->asyncWork));
402
403 napi_status status = napi_queue_async_work(env, context->asyncWork);
404 if (status != napi_ok) {
405 ThrowError(env, INNER_FAILURE, "queue asyncWork error");
406 CM_LOG_E("queue async work failed when using isAuthed");
407 return nullptr;
408 }
409 return promise;
410 }
411
GetUidListAsyncWork(napi_env env, GrantAsyncContext context)412 static napi_value GetUidListAsyncWork(napi_env env, GrantAsyncContext context)
413 {
414 napi_value promise = nullptr;
415 GenerateNapiPromise(env, context->callback, &context->deferred, &promise);
416
417 napi_value resourceName = nullptr;
418 NAPI_CALL(env, napi_create_string_latin1(env, "getAuthorizedAppList", NAPI_AUTO_LENGTH, &resourceName));
419
420 NAPI_CALL(env, napi_create_async_work(
421 env, nullptr, resourceName,
422 GetUidListExecute,
423 GetUidListComplete,
424 static_cast<void *>(context),
425 &context->asyncWork));
426
427 napi_status status = napi_queue_async_work(env, context->asyncWork);
428 if (status != napi_ok) {
429 ThrowError(env, INNER_FAILURE, "queue asyncWork error");
430 CM_LOG_E("queue async work failed when getting authed uid list");
431 return nullptr;
432 }
433 return promise;
434 }
435
CMNapiGrantPublicCertificate(napi_env env, napi_callback_info info)436 napi_value CMNapiGrantPublicCertificate(napi_env env, napi_callback_info info)
437 {
438 GrantAsyncContext context = InitGrantAsyncContext();
439 if (context == nullptr) {
440 CM_LOG_E("init grant uid context failed");
441 return nullptr;
442 }
443
444 napi_value result = ParseGrantUidParams(env, info, context);
445 if (result == nullptr) {
446 CM_LOG_E("parse grant uid params failed");
447 FreeGrantAsyncContext(env, context);
448 return nullptr;
449 }
450
451 result = GrantUidAsyncWork(env, context);
452 if (result == nullptr) {
453 CM_LOG_E("start grant uid async work failed");
454 FreeGrantAsyncContext(env, context);
455 return nullptr;
456 }
457
458 return result;
459 }
460
CMNapiIsAuthorizedApp(napi_env env, napi_callback_info info)461 napi_value CMNapiIsAuthorizedApp(napi_env env, napi_callback_info info)
462 {
463 GrantAsyncContext context = InitGrantAsyncContext();
464 if (context == nullptr) {
465 CM_LOG_E("init is authed uid context failed");
466 return nullptr;
467 }
468
469 napi_value result = ParseIsAuthedParams(env, info, context);
470 if (result == nullptr) {
471 CM_LOG_E("parse is authed uid params failed");
472 FreeGrantAsyncContext(env, context);
473 return nullptr;
474 }
475
476 result = IsAuthedAsyncWork(env, context);
477 if (result == nullptr) {
478 CM_LOG_E("start is authed uid async work failed");
479 FreeGrantAsyncContext(env, context);
480 return nullptr;
481 }
482
483 return result;
484 }
485
CMNapiGetAuthorizedAppList(napi_env env, napi_callback_info info)486 napi_value CMNapiGetAuthorizedAppList(napi_env env, napi_callback_info info)
487 {
488 GrantAsyncContext context = InitGrantAsyncContext();
489 if (context == nullptr) {
490 CM_LOG_E("init get authed uid list context failed");
491 return nullptr;
492 }
493
494 napi_value result = ParseGetUidListParams(env, info, context);
495 if (result == nullptr) {
496 CM_LOG_E("parse get uid list params failed");
497 FreeGrantAsyncContext(env, context);
498 return nullptr;
499 }
500
501 result = GetUidListAsyncWork(env, context);
502 if (result == nullptr) {
503 CM_LOG_E("start get uid list async work failed");
504 FreeGrantAsyncContext(env, context);
505 return nullptr;
506 }
507
508 return result;
509 }
510
CMNapiRemoveGrantedPublic(napi_env env, napi_callback_info info)511 napi_value CMNapiRemoveGrantedPublic(napi_env env, napi_callback_info info)
512 {
513 GrantAsyncContext context = InitGrantAsyncContext();
514 if (context == nullptr) {
515 CM_LOG_E("init remove uid context failed");
516 return nullptr;
517 }
518
519 napi_value result = ParseRemoveUidParams(env, info, context);
520 if (result == nullptr) {
521 CM_LOG_E("parse remove uid params failed");
522 FreeGrantAsyncContext(env, context);
523 return nullptr;
524 }
525
526 result = RemoveUidAsyncWork(env, context);
527 if (result == nullptr) {
528 CM_LOG_E("start remove uid async work failed");
529 FreeGrantAsyncContext(env, context);
530 return nullptr;
531 }
532
533 return result;
534 }
535 } // namespace CMNapi
536
537