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