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 "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 constexpr int HUKS_NAPI_UPDATE_MIN_ARGS = 2;
31 constexpr int HUKS_NAPI_UPDATE_MAX_ARGS = 4;
32 
CreateUpdateAsyncContext()33 UpdateAsyncContext CreateUpdateAsyncContext()
34 {
35     UpdateAsyncContext context = static_cast<UpdateAsyncContext>(HksMalloc(sizeof(UpdateAsyncContextT)));
36     if (context != nullptr) {
37         (void)memset_s(context, sizeof(UpdateAsyncContextT), 0, sizeof(UpdateAsyncContextT));
38     }
39     return context;
40 }
41 
DeleteUpdateAsyncContext(napi_env env,UpdateAsyncContext & context)42 void DeleteUpdateAsyncContext(napi_env env, UpdateAsyncContext &context)
43 {
44     if (context == nullptr) {
45         return;
46     }
47 
48     DeleteCommonAsyncContext(env, context->asyncWork, context->callback, context->handle, context->paramSet);
49 
50     if (context->inData != nullptr) {
51         if (context->inData->data != nullptr && context->inData->size != 0) {
52             (void)memset_s(context->inData->data, context->inData->size, 0, context->inData->size);
53         }
54         FreeHksBlob(context->inData);
55     }
56 
57     if (context->outData != nullptr) {
58         if (context->outData->data != nullptr && context->outData->size != 0) {
59             (void)memset_s(context->outData->data, context->outData->size, 0, context->outData->size);
60         }
61         FreeHksBlob(context->outData);
62     }
63 
64     if (context->token != nullptr) {
65         FreeHksBlob(context->token);
66     }
67 
68     HKS_FREE(context);
69     context = nullptr;
70 }
71 
FillContextInDataAndOutData(napi_env env,napi_value * argv,UpdateAsyncContext context,size_t index)72 static int32_t FillContextInDataAndOutData(napi_env env, napi_value *argv, UpdateAsyncContext context, size_t index)
73 {
74     napi_value inData = nullptr;
75     bool hasInData = false;
76     napi_has_named_property(env, argv[index], HKS_OPTIONS_PROPERTY_INDATA.c_str(), &hasInData);
77     napi_status status = napi_get_named_property(env, argv[index], HKS_OPTIONS_PROPERTY_INDATA.c_str(), &inData);
78     if (status == napi_ok && inData != nullptr && hasInData) {
79         napi_value result = GetUint8Array(env, inData, *context->inData);
80         if (result == nullptr) {
81             HKS_LOG_E("could not get inData");
82             return HKS_ERROR_BAD_STATE;
83         }
84     } else {
85         context->inData->size = 0;
86         context->inData->data = nullptr;
87     }
88 
89     context->outData->size = context->inData->size + DATA_SIZE_64KB;
90     context->outData->data = static_cast<uint8_t *>(HksMalloc(context->outData->size));
91     if (context->outData->data == nullptr) {
92         HKS_LOG_E("malloc memory failed");
93         return HKS_ERROR_MALLOC_FAIL;
94     }
95 
96     return HKS_SUCCESS;
97 }
98 
FillContextInDataAndOutBlob(napi_env env,napi_value * argv,UpdateAsyncContext context,size_t index)99 int32_t FillContextInDataAndOutBlob(napi_env env, napi_value *argv, UpdateAsyncContext context, size_t index)
100 {
101     context->outData = static_cast<struct HksBlob *>(HksMalloc(sizeof(HksBlob)));
102     if (context->outData == nullptr) {
103         HKS_LOG_E("could not alloc out blob memory");
104         return HKS_ERROR_MALLOC_FAIL;
105     }
106     (void)memset_s(context->outData, sizeof(HksBlob), 0, sizeof(HksBlob));
107 
108     context->inData = static_cast<struct HksBlob *>(HksMalloc(sizeof(HksBlob)));
109     if (context->inData == nullptr) {
110         HKS_LOG_E("could not alloc in blob memory");
111         return HKS_ERROR_MALLOC_FAIL;
112     }
113     (void)memset_s(context->inData, sizeof(HksBlob), 0, sizeof(HksBlob));
114 
115     int32_t ret = FillContextInDataAndOutData(env, argv, context, index);
116     if (ret != HKS_SUCCESS) {
117         HKS_LOG_E("fill data failed");
118     }
119     return ret;
120 }
121 
GetCallBackFunction(napi_env env,napi_value object,UpdateAsyncContext context)122 static int32_t GetCallBackFunction(napi_env env, napi_value object, UpdateAsyncContext context)
123 {
124     napi_valuetype valueType = napi_undefined;
125     napi_status status = napi_typeof(env, object, &valueType);
126     if (status != napi_ok) {
127         HKS_LOG_E("could not get object type");
128         return HKS_ERROR_INVALID_ARGUMENT;
129     }
130 
131     if (valueType != napi_valuetype::napi_function) {
132         HKS_LOG_I("no callback fun, process as promise func");
133         return HKS_SUCCESS;
134     }
135 
136     napi_ref ref = nullptr;
137     status = napi_create_reference(env, object, 1, &ref);
138     if (status != napi_ok) {
139         HKS_LOG_E("could not create reference");
140         return HKS_ERROR_BAD_STATE;
141     }
142     context->callback = ref;
143     return HKS_SUCCESS;
144 }
145 
GetToken(napi_env env,napi_value object,UpdateAsyncContext context)146 static int32_t GetToken(napi_env env, napi_value object, UpdateAsyncContext context)
147 {
148     context->token = static_cast<struct HksBlob *>(HksMalloc(sizeof(HksBlob)));
149     if (context->token == nullptr) {
150         HKS_LOG_E("could not alloc token blob memory");
151         return HKS_ERROR_MALLOC_FAIL;
152     }
153     (void)memset_s(context->token, sizeof(HksBlob), 0, sizeof(HksBlob));
154 
155     napi_value result = GetUint8Array(env, object, *(context->token));
156     if (result == nullptr) {
157         HKS_LOG_E("could not get token data");
158         return HKS_ERROR_BAD_STATE;
159     }
160 
161     return HKS_SUCCESS;
162 }
163 
GetTokenOrCallback(napi_env env,napi_value * argv,UpdateAsyncContext context,size_t index,size_t maxIndex)164 int32_t GetTokenOrCallback(napi_env env, napi_value *argv, UpdateAsyncContext context,
165     size_t index, size_t maxIndex)
166 {
167     if (index >= maxIndex) { /* only 2 input params */
168         return HKS_SUCCESS;
169     }
170 
171     /*
172      * check wether arg 3 is callback: if true, get callback function and return;
173      * else get token, then check wether has arg 4: if true, get arg 4 as callback function
174      */
175     int32_t ret;
176     napi_valuetype valueType = napi_undefined;
177     napi_status status = napi_typeof(env, argv[index], &valueType);
178     if (status != napi_ok) {
179         HKS_LOG_E("could not get object type");
180         return HKS_ERROR_INVALID_ARGUMENT;
181     }
182 
183     switch (valueType) {
184         case napi_valuetype::napi_function:
185             return GetCallBackFunction(env, argv[index], context); /* return if arg 3 is callback */
186         case napi_valuetype::napi_object: {
187             ret = GetToken(env, argv[index], context);
188             if (ret != HKS_SUCCESS) {
189                 HKS_LOG_E("could not get token value");
190                 return ret;
191             }
192 
193             index++;
194             if (index < maxIndex) { /* has arg 4: can only be callback */
195                 return GetCallBackFunction(env, argv[index], context);
196             }
197             return HKS_SUCCESS;
198         }
199         case napi_valuetype::napi_undefined: {
200             HKS_LOG_I("param %" LOG_PUBLIC "zu is undefined", index);
201             // if param 3 is undefined, ignore this and try to get param 4 as callback func
202             index++;
203             if (index < maxIndex) { /* has arg 4: can only be callback */
204                 return GetCallBackFunction(env, argv[index], context);
205             }
206             return HKS_SUCCESS;
207         }
208         default:
209             HKS_LOG_I("param %" LOG_PUBLIC "zu is invalid type", index);
210             // if param 3 is invalid type, process as redundant params
211             return HKS_SUCCESS;
212     }
213 
214     return HKS_ERROR_BAD_STATE;
215 }
216 
ParseUpdateParams(napi_env env,napi_callback_info info,UpdateAsyncContext context)217 static napi_value ParseUpdateParams(napi_env env, napi_callback_info info, UpdateAsyncContext context)
218 {
219     size_t argc = HUKS_NAPI_UPDATE_MAX_ARGS;
220     napi_value argv[HUKS_NAPI_UPDATE_MAX_ARGS] = { 0 };
221     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
222 
223     if (argc < HUKS_NAPI_UPDATE_MIN_ARGS) {
224         HksNapiThrow(env, HUKS_ERR_CODE_ILLEGAL_ARGUMENT, "no enough params input");
225         HKS_LOG_E("no enough params");
226         return nullptr;
227     }
228 
229     size_t index = 0;
230     napi_value result = GetHandleValue(env, argv[index], context->handle);
231     if (result == nullptr) {
232         HKS_LOG_E("update could not get handle value");
233         return nullptr;
234     }
235 
236     index++;
237     napi_value properties = GetPropertyFromOptions(env, argv[index], HKS_OPTIONS_PROPERTY_PROPERTIES);
238     if (properties == nullptr) {
239         HKS_LOG_E("get properties failed");
240         return nullptr;
241     }
242 
243     if (FillContextInDataAndOutBlob(env, argv, context, index) != HKS_SUCCESS) {
244         HKS_LOG_E("fill in or out blob failed");
245         return nullptr;
246     }
247 
248     index++;
249     if (GetTokenOrCallback(env, argv, context, index, argc) != HKS_SUCCESS) {
250         HKS_LOG_E("get token or callback failed");
251         return nullptr;
252     }
253 
254     if (ParseHksParamSetWithToken(env, context->token, properties, context->paramSet) == nullptr) {
255         HKS_LOG_E("could not get paramset");
256         return nullptr;
257     }
258 
259     return GetInt32(env, 0);
260 }
261 
UpdateFinishAsyncWork(napi_env env,UpdateAsyncContext & context)262 napi_value UpdateFinishAsyncWork(napi_env env, UpdateAsyncContext &context)
263 {
264     napi_value promise = nullptr;
265     if (context->callback == nullptr) {
266         NAPI_CALL(env, napi_create_promise(env, &context->deferred, &promise));
267     }
268 
269     napi_value resourceName;
270     napi_create_string_latin1(env, "UpdateAsyncWork", NAPI_AUTO_LENGTH, &resourceName);
271 
272     napi_create_async_work(
273         env,
274         nullptr,
275         resourceName,
276         [](napi_env env, void *data) {
277             UpdateAsyncContext napiContext = static_cast<UpdateAsyncContext>(data);
278             if (napiContext->isUpdate) {
279                 napiContext->result = HksUpdate(napiContext->handle,
280                     napiContext->paramSet, napiContext->inData, napiContext->outData);
281             } else {
282                 napiContext->result = HksFinish(napiContext->handle,
283                     napiContext->paramSet, napiContext->inData, napiContext->outData);
284             }
285         },
286         [](napi_env env, napi_status status, void *data) {
287             UpdateAsyncContext napiContext = static_cast<UpdateAsyncContext>(data);
288             HksSuccessReturnResult resultData;
289             SuccessReturnResultInit(resultData);
290             resultData.outData = napiContext->outData;
291             HksReturnNapiResult(env, napiContext->callback, napiContext->deferred, napiContext->result, resultData);
292             DeleteUpdateAsyncContext(env, napiContext);
293         },
294         static_cast<void *>(context),
295         &context->asyncWork);
296 
297     napi_status status = napi_queue_async_work(env, context->asyncWork);
298     if (status != napi_ok) {
299         DeleteUpdateAsyncContext(env, context);
300         HKS_LOG_E("could not queue async work");
301         return nullptr;
302     }
303 
304     if (context->callback == nullptr) {
305         return promise;
306     } else {
307         return GetNull(env);
308     }
309 }
310 
HuksNapiUpdateSession(napi_env env,napi_callback_info info)311 napi_value HuksNapiUpdateSession(napi_env env, napi_callback_info info)
312 {
313     UpdateAsyncContext context = CreateUpdateAsyncContext();
314     if (context == nullptr) {
315         HKS_LOG_E("update: could not create context");
316         return nullptr;
317     }
318 
319     context->isUpdate = true;
320     napi_value result = ParseUpdateParams(env, info, context);
321     if (result == nullptr) {
322         HKS_LOG_E("update: could not parse params");
323         DeleteUpdateAsyncContext(env, context);
324         return nullptr;
325     }
326 
327     result = UpdateFinishAsyncWork(env, context);
328     if (result == nullptr) {
329         HKS_LOG_E("update: could not start async work");
330         DeleteUpdateAsyncContext(env, context);
331         return nullptr;
332     }
333     return result;
334 }
335 
HuksNapiFinishSession(napi_env env,napi_callback_info info)336 napi_value HuksNapiFinishSession(napi_env env, napi_callback_info info)
337 {
338     UpdateAsyncContext context = CreateUpdateAsyncContext();
339     if (context == nullptr) {
340         HKS_LOG_E("finish: could not create context");
341         return nullptr;
342     }
343 
344     context->isUpdate = false;
345     napi_value result = ParseUpdateParams(env, info, context);
346     if (result == nullptr) {
347         HKS_LOG_E("finish: could not parse params");
348         DeleteUpdateAsyncContext(env, context);
349         return nullptr;
350     }
351 
352     result = UpdateFinishAsyncWork(env, context);
353     if (result == nullptr) {
354         HKS_LOG_E("finish: could not start async work");
355         DeleteUpdateAsyncContext(env, context);
356         return nullptr;
357     }
358     return result;
359 }
360 }  // namespace HuksNapiItem
361