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> ¶ms, struct HksParamSet *¶mSet)
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 *¶mSet)
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