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