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