• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 "huks_napi_update_finish_session.h"
17 
18 #include <vector>
19 
20 #include "securec.h"
21 
22 #include "hks_api.h"
23 #include "hks_log.h"
24 #include "hks_mem.h"
25 #include "hks_param.h"
26 #include "hks_type.h"
27 #include "huks_napi_common_item.h"
28 
29 namespace HuksNapiItem {
30 namespace {
31 constexpr int HUKS_NAPI_UPDATE_MIN_ARGS = 2;
32 constexpr int HUKS_NAPI_UPDATE_MAX_ARGS = 4;
33 }  // namespace
34 
35 struct UpdateAsyncContextT {
36     napi_async_work asyncWork = nullptr;
37     napi_deferred deferred = nullptr;
38     napi_ref callback = nullptr;
39 
40     int32_t result = 0;
41     struct HksBlob *handle = nullptr;
42     struct HksParamSet *paramSet = nullptr;
43     struct HksBlob *inData = nullptr;
44     struct HksBlob *outData = nullptr;
45     struct HksBlob *token = nullptr;
46     bool isUpdate = false;
47 };
48 using UpdateAsyncContext = UpdateAsyncContextT *;
49 
CreateUpdateAsyncContext()50 static UpdateAsyncContext CreateUpdateAsyncContext()
51 {
52     UpdateAsyncContext context = static_cast<UpdateAsyncContext>(HksMalloc(sizeof(UpdateAsyncContextT)));
53     if (context != nullptr) {
54         (void)memset_s(context, sizeof(UpdateAsyncContextT), 0, sizeof(UpdateAsyncContextT));
55     }
56     return context;
57 }
58 
DeleteUpdateAsyncContext(napi_env env,UpdateAsyncContext & context)59 static void DeleteUpdateAsyncContext(napi_env env, UpdateAsyncContext &context)
60 {
61     if (context == nullptr) {
62         return;
63     }
64 
65     DeleteCommonAsyncContext(env, context->asyncWork, context->callback, context->handle, context->paramSet);
66 
67     if (context->inData != nullptr) {
68         if (context->inData->data != nullptr && context->inData->size != 0) {
69             (void)memset_s(context->inData->data, context->inData->size, 0, context->inData->size);
70         }
71         FreeHksBlob(context->inData);
72     }
73 
74     if (context->outData != nullptr) {
75         if (context->outData->data != nullptr && context->outData->size != 0) {
76             (void)memset_s(context->outData->data, context->outData->size, 0, context->outData->size);
77         }
78         FreeHksBlob(context->outData);
79     }
80 
81     if (context->token != nullptr) {
82         FreeHksBlob(context->token);
83     }
84 
85     HksFree(context);
86     context = nullptr;
87 }
88 
FillContextInDataAndOutData(napi_env env,napi_value * argv,UpdateAsyncContext context,size_t index)89 static int32_t FillContextInDataAndOutData(napi_env env, napi_value *argv, UpdateAsyncContext context, size_t index)
90 {
91     napi_value inData = nullptr;
92     bool hasInData = false;
93     napi_has_named_property(env, argv[index], HKS_OPTIONS_PROPERTY_INDATA.c_str(), &hasInData);
94     napi_status status = napi_get_named_property(env, argv[index], HKS_OPTIONS_PROPERTY_INDATA.c_str(), &inData);
95     if (status == napi_ok && inData != nullptr && hasInData) {
96         napi_value result = GetUint8Array(env, inData, *context->inData);
97         if (result == nullptr) {
98             HKS_LOG_E("could not get inData");
99             return HKS_ERROR_BAD_STATE;
100         }
101     } else {
102         context->inData->size = 0;
103         context->inData->data = nullptr;
104     }
105 
106     context->outData->size = context->inData->size + DATA_SIZE_64KB;
107     context->outData->data = static_cast<uint8_t *>(HksMalloc(context->outData->size));
108     if (context->outData->data == nullptr) {
109         HKS_LOG_E("malloc memory failed");
110         return HKS_ERROR_MALLOC_FAIL;
111     }
112 
113     return HKS_SUCCESS;
114 }
115 
FillContextInDataAndOutBlob(napi_env env,napi_value * argv,UpdateAsyncContext context,size_t index)116 static int32_t FillContextInDataAndOutBlob(napi_env env, napi_value *argv, UpdateAsyncContext context, size_t index)
117 {
118     context->outData = static_cast<struct HksBlob *>(HksMalloc(sizeof(HksBlob)));
119     if (context->outData == nullptr) {
120         HKS_LOG_E("could not alloc out blob memory");
121         return HKS_ERROR_MALLOC_FAIL;
122     }
123     (void)memset_s(context->outData, sizeof(HksBlob), 0, sizeof(HksBlob));
124 
125     context->inData = static_cast<struct HksBlob *>(HksMalloc(sizeof(HksBlob)));
126     if (context->inData == nullptr) {
127         HKS_LOG_E("could not alloc in blob memory");
128         return HKS_ERROR_MALLOC_FAIL;
129     }
130     (void)memset_s(context->inData, sizeof(HksBlob), 0, sizeof(HksBlob));
131 
132     int32_t ret = FillContextInDataAndOutData(env, argv, context, index);
133     if (ret != HKS_SUCCESS) {
134         HKS_LOG_E("fill data failed");
135     }
136     return ret;
137 }
138 
GetCallBackFunction(napi_env env,napi_value object,UpdateAsyncContext context)139 static int32_t GetCallBackFunction(napi_env env, napi_value object, UpdateAsyncContext context)
140 {
141     napi_ref ref = nullptr;
142     napi_status status = napi_create_reference(env, object, 1, &ref);
143     if (status != napi_ok) {
144         HKS_LOG_E("could not create reference");
145         return HKS_ERROR_BAD_STATE;
146     }
147     context->callback = ref;
148     return HKS_SUCCESS;
149 }
150 
GetToken(napi_env env,napi_value object,UpdateAsyncContext context)151 static int32_t GetToken(napi_env env, napi_value object, UpdateAsyncContext context)
152 {
153     context->token = static_cast<struct HksBlob *>(HksMalloc(sizeof(HksBlob)));
154     if (context->token == nullptr) {
155         HKS_LOG_E("could not alloc token blob memory");
156         return HKS_ERROR_MALLOC_FAIL;
157     }
158     (void)memset_s(context->token, sizeof(HksBlob), 0, sizeof(HksBlob));
159 
160     napi_value result = GetUint8Array(env, object, *(context->token));
161     if (result == nullptr) {
162         HKS_LOG_E("could not get token data");
163         return HKS_ERROR_BAD_STATE;
164     }
165 
166     return HKS_SUCCESS;
167 }
168 
GetTokenOrCallback(napi_env env,napi_value * argv,UpdateAsyncContext context,size_t index,size_t maxIndex)169 static int32_t GetTokenOrCallback(napi_env env, napi_value *argv, UpdateAsyncContext context,
170     size_t index, size_t maxIndex)
171 {
172     if (index >= maxIndex) { /* only 2 input params */
173         return HKS_SUCCESS;
174     }
175 
176     /*
177      * check wether arg 3 is callback: if true, get callback function and return;
178      * else get token, then check wether has arg 4: if true, get arg 4 as callback function
179      */
180     int32_t ret;
181     napi_valuetype valueType = napi_undefined;
182     napi_status status = napi_typeof(env, argv[index], &valueType);
183     if (status != napi_ok) {
184         HKS_LOG_E("could not get object type");
185         return HKS_ERROR_INVALID_ARGUMENT;
186     }
187 
188     switch (valueType) {
189         case napi_valuetype::napi_function:
190             return GetCallBackFunction(env, argv[index], context); /* return if arg 3 is callback */
191         case napi_valuetype::napi_object: {
192             ret = GetToken(env, argv[index], context);
193             if (ret != HKS_SUCCESS) {
194                 HKS_LOG_E("could not get token value");
195                 return ret;
196             }
197 
198             index++;
199             if (index < maxIndex) { /* has arg 4: can only be callback */
200                 status = napi_typeof(env, argv[index], &valueType);
201                 if (status != napi_ok) {
202                     HKS_LOG_E("could not get object type");
203                     return HKS_ERROR_INVALID_ARGUMENT;
204                 }
205 
206                 if (valueType != napi_valuetype::napi_function) {
207                     HKS_LOG_E("check param4 failed, param4 is not func");
208                     break;
209                 }
210 
211                 return GetCallBackFunction(env, argv[index], context);
212             }
213             return HKS_SUCCESS;
214         }
215         default:
216             break;
217     }
218 
219     napi_throw_error(env, std::to_string(HUKS_ERR_CODE_ILLEGAL_ARGUMENT).c_str(),
220         "the type of token or callbakc is wrong");
221     HKS_LOG_E("the type of token or callbakc is wrong");
222     return HKS_ERROR_BAD_STATE;
223 }
224 
AddParams(const std::vector<HksParam> & params,struct HksParamSet * & paramSet)225 static int32_t AddParams(const std::vector<HksParam> &params, struct HksParamSet *&paramSet)
226 {
227     const HksParam *param = params.data();
228     size_t paramCount = params.size();
229     if (param == nullptr) {
230         return HKS_SUCCESS;
231     }
232 
233     for (uint32_t i = 0; i < paramCount; ++i) {
234         int32_t ret = HksAddParams(paramSet, param, 1);
235         if (ret != HKS_SUCCESS) {
236             HKS_LOG_E("add param[%" LOG_PUBLIC "u] failed", i);
237             return ret;
238         }
239         param++;
240     }
241     return HKS_SUCCESS;
242 }
243 
GetInputParamSet(napi_env env,napi_value object,struct HksBlob * & token,HksParamSet * & paramSet)244 static int32_t GetInputParamSet(napi_env env, napi_value object, struct HksBlob *&token, HksParamSet *&paramSet)
245 {
246     std::vector<HksParam> params;
247     napi_value result = ParseParams(env, object, params);
248     if (result == nullptr) {
249         HKS_LOG_E("parse params failed");
250         FreeParsedParams(params);
251         return HKS_ERROR_INVALID_ARGUMENT;
252     }
253 
254     HksParamSet *outParamSet = nullptr;
255     int32_t ret;
256     do {
257         ret = HksInitParamSet(&outParamSet);
258         if (ret != HKS_SUCCESS) {
259             HKS_LOG_E("init paramSet failed");
260             break;
261         }
262 
263         if (CheckBlob(token) == HKS_SUCCESS) { /* has token param */
264             HksParam tokenParam = {
265                 .tag = HKS_TAG_AUTH_TOKEN,
266                 .blob = *token
267             };
268             ret = HksAddParams(outParamSet, &tokenParam, 1);
269             if (ret != HKS_SUCCESS) {
270                 HKS_LOG_E("add token param failed.");
271                 break;
272             }
273         }
274 
275         ret = AddParams(params, outParamSet);
276         if (ret != HKS_SUCCESS) {
277             HKS_LOG_E("add params failed");
278             break;
279         }
280 
281         ret = HksBuildParamSet(&outParamSet);
282         if (ret != HKS_SUCCESS) {
283             HKS_LOG_E("build params failed");
284             break;
285         }
286     } while (0);
287     FreeParsedParams(params);
288     if (ret != HKS_SUCCESS) {
289         HksFreeParamSet(&outParamSet);
290     }
291     paramSet = outParamSet;
292     return ret;
293 }
294 
ParseUpdateParams(napi_env env,napi_callback_info info,UpdateAsyncContext context)295 static napi_value ParseUpdateParams(napi_env env, napi_callback_info info, UpdateAsyncContext context)
296 {
297     size_t argc = HUKS_NAPI_UPDATE_MAX_ARGS;
298     napi_value argv[HUKS_NAPI_UPDATE_MAX_ARGS] = { 0 };
299     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
300 
301     if (argc < HUKS_NAPI_UPDATE_MIN_ARGS) {
302         napi_throw_error(env, std::to_string(HUKS_ERR_CODE_ILLEGAL_ARGUMENT).c_str(), "no enough params input");
303         HKS_LOG_E("no enough params");
304         return nullptr;
305     }
306 
307     size_t index = 0;
308     napi_value result = GetHandleValue(env, argv[index], context->handle);
309     if (result == nullptr) {
310         HKS_LOG_E("update could not get handle value");
311         return nullptr;
312     }
313 
314     index++;
315     napi_value properties = GetPropertyFromOptions(env, argv[index], HKS_OPTIONS_PROPERTY_PROPERTIES);
316     if (properties == nullptr) {
317         HKS_LOG_E("get properties failed");
318         return nullptr;
319     }
320 
321     if (FillContextInDataAndOutBlob(env, argv, context, index) != HKS_SUCCESS) {
322         HKS_LOG_E("fill in or out blob failed");
323         return nullptr;
324     }
325 
326     index++;
327     if (GetTokenOrCallback(env, argv, context, index, argc) != HKS_SUCCESS) {
328         HKS_LOG_E("get token or callback failed");
329         return nullptr;
330     }
331 
332     if (GetInputParamSet(env, properties, context->token, context->paramSet) != HKS_SUCCESS) {
333         HKS_LOG_E("could not get paramset");
334         return nullptr;
335     }
336 
337     return GetInt32(env, 0);
338 }
339 
UpdateFinishAsyncWork(napi_env env,UpdateAsyncContext context)340 static napi_value UpdateFinishAsyncWork(napi_env env, UpdateAsyncContext context)
341 {
342     napi_value promise = nullptr;
343     if (context->callback == nullptr) {
344         NAPI_CALL(env, napi_create_promise(env, &context->deferred, &promise));
345     }
346 
347     napi_value resourceName;
348     napi_create_string_latin1(env, "UpdateAsyncWork", NAPI_AUTO_LENGTH, &resourceName);
349 
350     napi_create_async_work(
351         env,
352         nullptr,
353         resourceName,
354         [](napi_env env, void *data) {
355             UpdateAsyncContext napiContext = static_cast<UpdateAsyncContext>(data);
356             if (napiContext->isUpdate) {
357                 napiContext->result = HksUpdate(napiContext->handle,
358                     napiContext->paramSet, napiContext->inData, napiContext->outData);
359             } else {
360                 napiContext->result = HksFinish(napiContext->handle,
361                     napiContext->paramSet, napiContext->inData, napiContext->outData);
362             }
363         },
364         [](napi_env env, napi_status status, void *data) {
365             UpdateAsyncContext napiContext = static_cast<UpdateAsyncContext>(data);
366             HksSuccessReturnResult resultData;
367             SuccessReturnResultInit(resultData);
368             resultData.outData = napiContext->outData;
369             HksReturnNapiResult(env, napiContext->callback, napiContext->deferred, napiContext->result, resultData);
370             DeleteUpdateAsyncContext(env, napiContext);
371         },
372         static_cast<void *>(context),
373         &context->asyncWork);
374 
375     napi_status status = napi_queue_async_work(env, context->asyncWork);
376     if (status != napi_ok) {
377         DeleteUpdateAsyncContext(env, context);
378         HKS_LOG_E("could not queue async work");
379         return nullptr;
380     }
381 
382     if (context->callback == nullptr) {
383         return promise;
384     } else {
385         return GetNull(env);
386     }
387 }
388 
HuksNapiUpdateSession(napi_env env,napi_callback_info info)389 napi_value HuksNapiUpdateSession(napi_env env, napi_callback_info info)
390 {
391     UpdateAsyncContext context = CreateUpdateAsyncContext();
392     if (context == nullptr) {
393         HKS_LOG_E("update: could not create context");
394         return nullptr;
395     }
396 
397     napi_value result = ParseUpdateParams(env, info, context);
398     if (result == nullptr) {
399         HKS_LOG_E("update: could not parse params");
400         DeleteUpdateAsyncContext(env, context);
401         return nullptr;
402     }
403     context->isUpdate = true;
404 
405     result = UpdateFinishAsyncWork(env, context);
406     if (result == nullptr) {
407         HKS_LOG_E("update: could not start async work");
408         DeleteUpdateAsyncContext(env, context);
409         return nullptr;
410     }
411     return result;
412 }
413 
HuksNapiFinishSession(napi_env env,napi_callback_info info)414 napi_value HuksNapiFinishSession(napi_env env, napi_callback_info info)
415 {
416     UpdateAsyncContext context = CreateUpdateAsyncContext();
417     if (context == nullptr) {
418         HKS_LOG_E("finish: could not create context");
419         return nullptr;
420     }
421 
422     napi_value result = ParseUpdateParams(env, info, context);
423     if (result == nullptr) {
424         HKS_LOG_E("finish: could not parse params");
425         DeleteUpdateAsyncContext(env, context);
426         return nullptr;
427     }
428     context->isUpdate = false;
429 
430     result = UpdateFinishAsyncWork(env, context);
431     if (result == nullptr) {
432         HKS_LOG_E("finish: could not start async work");
433         DeleteUpdateAsyncContext(env, context);
434         return nullptr;
435     }
436     return result;
437 }
438 }  // namespace HuksNapiItem
439