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 "napi_scan_utils.h"
17
18 #include <fcntl.h>
19 #include "ability.h"
20 #include "napi_base_context.h"
21 #include "scan_log.h"
22 #include "scan_util.h"
23 #include "accesstoken_kit.h"
24 #include "tokenid_kit.h"
25
26 namespace OHOS::Scan {
27 static constexpr const int MAX_STRING_LENGTH = 65536;
28 const std::string GLOBAL_ID_DELIMITER = ":";
29 const std::string EXTENSION_CID_DELIMITER = ":";
30 const std::string TASK_EVENT_DELIMITER = "-";
31 std::unordered_map<uint32_t, std::string> NapiScanUtils::scanErrorCodeMap_ = {
32 {E_SCAN_NO_PERMISSION, "SCAN_ERROR_NO_PERMISSION", },
33 {E_SCAN_ERROR_NOT_SYSTEM_APPLICATION, "SCAN_ERROR_NOT_SYSTEM_APPLICATION", },
34 {E_SCAN_INVALID_PARAMETER, "SCAN_ERROR_INVALID_PARAMETER"},
35 {E_SCAN_GENERIC_FAILURE, "SCAN_ERROR_GENERIC_FAILURE"},
36 {E_SCAN_RPC_FAILURE, "SCAN_ERROR_RPC_FAILURE"},
37 {E_SCAN_SERVER_FAILURE, "SCAN_ERROR_SERVER_FAILURE"},
38 {E_SCAN_UNSUPPORTED, "SCAN_ERROR_UNSUPPORTED"},
39 {E_SCAN_CANCELLED, "SCAN_ERROR_CANCELED"},
40 {E_SCAN_DEVICE_BUSY, "SCAN_ERROR_DEVICE_BUSY"},
41 {E_SCAN_INVAL, "SCAN_ERROR_INVALID"},
42 {E_SCAN_JAMMED, "SCAN_ERROR_JAMMED"},
43 {E_SCAN_NO_DOCS, "SCAN_ERROR_NO_DOCS"},
44 {E_SCAN_COVER_OPEN, "SCAN_ERROR_COVER_OPEN"},
45 {E_SCAN_IO_ERROR, "SCAN_ERROR_IO_ERROR"},
46 {E_SCAN_NO_MEM, "SCAN_ERROR_NO_MEMORY"},
47 };
GetValueType(napi_env env,napi_value value)48 napi_valuetype NapiScanUtils::GetValueType(napi_env env, napi_value value)
49 {
50 if (value == nullptr) {
51 return napi_undefined;
52 }
53
54 napi_valuetype valueType = napi_undefined;
55 SCAN_CALL_BASE(env, napi_typeof(env, value, &valueType), napi_undefined);
56 return valueType;
57 }
58
59 /* named property */
HasNamedProperty(napi_env env,napi_value object,const std::string & propertyName)60 bool NapiScanUtils::HasNamedProperty(napi_env env, napi_value object, const std::string &propertyName)
61 {
62 if (object == nullptr) {
63 return false;
64 }
65 bool hasProperty = false;
66 SCAN_CALL_BASE(env, napi_has_named_property(env, object, propertyName.c_str(), &hasProperty), false);
67 return hasProperty;
68 }
69
GetNamedProperty(napi_env env,napi_value object,const std::string & propertyName)70 napi_value NapiScanUtils::GetNamedProperty(napi_env env, napi_value object, const std::string &propertyName)
71 {
72 if (object == nullptr) {
73 return nullptr;
74 }
75 napi_value value = nullptr;
76 bool hasProperty = false;
77 SCAN_CALL(env, napi_has_named_property(env, object, propertyName.c_str(), &hasProperty));
78 if (!hasProperty) {
79 return value;
80 }
81 SCAN_CALL(env, napi_get_named_property(env, object, propertyName.c_str(), &value));
82 return value;
83 }
84
SetNamedProperty(napi_env env,napi_value object,const std::string & name,napi_value value)85 void NapiScanUtils::SetNamedProperty(napi_env env, napi_value object, const std::string &name, napi_value value)
86 {
87 if (object == nullptr) {
88 return;
89 }
90 (void)napi_set_named_property(env, object, name.c_str(), value);
91 }
92
GetPropertyNames(napi_env env,napi_value object)93 std::vector<std::string> NapiScanUtils::GetPropertyNames(napi_env env, napi_value object)
94 {
95 std::vector<std::string> ret;
96 if (object == nullptr) {
97 return ret;
98 }
99 napi_value names = nullptr;
100 SCAN_CALL_BASE(env, napi_get_property_names(env, object, &names), ret);
101 uint32_t length = 0;
102 SCAN_CALL_BASE(env, napi_get_array_length(env, names, &length), ret);
103 for (uint32_t index = 0; index < length; ++index) {
104 napi_value name = nullptr;
105 if (napi_get_element(env, names, index, &name) != napi_ok) {
106 continue;
107 }
108 if (GetValueType(env, name) != napi_string) {
109 continue;
110 }
111 ret.emplace_back(GetStringFromValueUtf8(env, name));
112 }
113 return ret;
114 }
115
116 /* UINT32 */
CreateUint32(napi_env env,uint32_t code)117 napi_value NapiScanUtils::CreateUint32(napi_env env, uint32_t code)
118 {
119 napi_value value = nullptr;
120 if (napi_create_uint32(env, code, &value) != napi_ok) {
121 return nullptr;
122 }
123 return value;
124 }
125
GetUint32FromValue(napi_env env,napi_value value)126 uint32_t NapiScanUtils::GetUint32FromValue(napi_env env, napi_value value)
127 {
128 if (value == nullptr) {
129 return 0;
130 }
131 uint32_t ret = 0;
132 SCAN_CALL_BASE(env, napi_get_value_uint32(env, value, &ret), 0);
133 return ret;
134 }
135
GetUint32Property(napi_env env,napi_value object,const std::string & propertyName)136 uint32_t NapiScanUtils::GetUint32Property(napi_env env, napi_value object, const std::string &propertyName)
137 {
138 if (object == nullptr) {
139 return 0;
140 }
141 if (!HasNamedProperty(env, object, propertyName)) {
142 return 0;
143 }
144 napi_value value = GetNamedProperty(env, object, propertyName);
145 return GetUint32FromValue(env, value);
146 }
147
SetUint32Property(napi_env env,napi_value object,const std::string & name,uint32_t value)148 void NapiScanUtils::SetUint32Property(napi_env env, napi_value object, const std::string &name, uint32_t value)
149 {
150 if (object == nullptr) {
151 return;
152 }
153 napi_value jsValue = CreateUint32(env, value);
154 if (GetValueType(env, jsValue) != napi_number) {
155 return;
156 }
157
158 napi_set_named_property(env, object, name.c_str(), jsValue);
159 }
160
161 /* INT32 */
CreateInt32(napi_env env,int32_t code)162 napi_value NapiScanUtils::CreateInt32(napi_env env, int32_t code)
163 {
164 napi_value value = nullptr;
165 if (napi_create_int32(env, code, &value) != napi_ok) {
166 return nullptr;
167 }
168 return value;
169 }
170
GetInt32FromValue(napi_env env,napi_value value)171 int32_t NapiScanUtils::GetInt32FromValue(napi_env env, napi_value value)
172 {
173 if (value == nullptr) {
174 return 0;
175 }
176 int32_t ret = 0;
177 SCAN_CALL_BASE(env, napi_get_value_int32(env, value, &ret), 0);
178 return ret;
179 }
180
GetInt32Property(napi_env env,napi_value object,const std::string & propertyName)181 int32_t NapiScanUtils::GetInt32Property(napi_env env, napi_value object, const std::string &propertyName)
182 {
183 if (object == nullptr) {
184 return 0;
185 }
186 if (!HasNamedProperty(env, object, propertyName)) {
187 return 0;
188 }
189 napi_value value = GetNamedProperty(env, object, propertyName);
190 return GetInt32FromValue(env, value);
191 }
192
SetInt32Property(napi_env env,napi_value object,const std::string & name,int32_t value)193 void NapiScanUtils::SetInt32Property(napi_env env, napi_value object, const std::string &name, int32_t value)
194 {
195 if (object == nullptr) {
196 return;
197 }
198 napi_value jsValue = CreateInt32(env, value);
199 if (GetValueType(env, jsValue) != napi_number) {
200 return;
201 }
202
203 napi_set_named_property(env, object, name.c_str(), jsValue);
204 }
205
206 /* String UTF8 */
CreateStringUtf8(napi_env env,const std::string & str)207 napi_value NapiScanUtils::CreateStringUtf8(napi_env env, const std::string &str)
208 {
209 napi_value value = nullptr;
210 if (napi_create_string_utf8(env, str.c_str(), strlen(str.c_str()), &value) != napi_ok) {
211 return nullptr;
212 }
213 return value;
214 }
215
GetStringFromValueUtf8(napi_env env,napi_value value)216 std::string NapiScanUtils::GetStringFromValueUtf8(napi_env env, napi_value value)
217 {
218 if (value == nullptr) {
219 return "";
220 }
221 std::string result;
222 std::vector<char> str(MAX_STRING_LENGTH + 1, '\0');
223 size_t length = 0;
224 SCAN_CALL_BASE(env, napi_get_value_string_utf8(env, value, &str[0], MAX_STRING_LENGTH, &length), result);
225 if (length > 0) {
226 return result.append(&str[0], length);
227 }
228 return result;
229 }
230
GetStringPropertyUtf8(napi_env env,napi_value object,const std::string & propertyName)231 std::string NapiScanUtils::GetStringPropertyUtf8(napi_env env, napi_value object, const std::string &propertyName)
232 {
233 if (object == nullptr) {
234 return "";
235 }
236 if (!HasNamedProperty(env, object, propertyName)) {
237 return "";
238 }
239 napi_value value = GetNamedProperty(env, object, propertyName);
240 return GetStringFromValueUtf8(env, value);
241 }
242
SetStringPropertyUtf8(napi_env env,napi_value object,const std::string & name,const std::string & value)243 void NapiScanUtils::SetStringPropertyUtf8(
244 napi_env env, napi_value object, const std::string &name, const std::string &value)
245 {
246 if (object == nullptr) {
247 return;
248 }
249 napi_value jsValue = CreateStringUtf8(env, value);
250 if (GetValueType(env, jsValue) != napi_string) {
251 return;
252 }
253 napi_set_named_property(env, object, name.c_str(), jsValue);
254 }
255
256 /* array buffer */
257
CreateArrayBuffer(napi_env env,size_t length,void ** data)258 napi_value NapiScanUtils::CreateArrayBuffer(napi_env env, size_t length, void **data)
259 {
260 napi_value object = nullptr;
261 SCAN_CALL(env, napi_create_arraybuffer(env, length, data, &object));
262 return object;
263 }
264
ValueIsArrayBuffer(napi_env env,napi_value value)265 bool NapiScanUtils::ValueIsArrayBuffer(napi_env env, napi_value value)
266 {
267 if (value == nullptr) {
268 return false;
269 }
270 bool isArrayBuffer = false;
271 SCAN_CALL_BASE(env, napi_is_arraybuffer(env, value, &isArrayBuffer), false);
272 return isArrayBuffer;
273 }
274
GetInfoFromArrayBufferValue(napi_env env,napi_value value,size_t * length)275 void *NapiScanUtils::GetInfoFromArrayBufferValue(napi_env env, napi_value value, size_t *length)
276 {
277 if (value == nullptr || length == nullptr) {
278 return nullptr;
279 }
280
281 void *data = nullptr;
282 SCAN_CALL(env, napi_get_arraybuffer_info(env, value, &data, length));
283 return data;
284 }
285
286 /* object */
CreateObject(napi_env env)287 napi_value NapiScanUtils::CreateObject(napi_env env)
288 {
289 napi_value object = nullptr;
290 SCAN_CALL(env, napi_create_object(env, &object));
291 return object;
292 }
293
294 /* undefined */
GetUndefined(napi_env env)295 napi_value NapiScanUtils::GetUndefined(napi_env env)
296 {
297 napi_value undefined = nullptr;
298 SCAN_CALL(env, napi_get_undefined(env, &undefined));
299 return undefined;
300 }
301
302 /* function */
CallFunction(napi_env env,napi_value recv,napi_value func,size_t argc,const napi_value * argv)303 napi_value NapiScanUtils::CallFunction(
304 napi_env env, napi_value recv, napi_value func, size_t argc, const napi_value *argv)
305 {
306 if (func == nullptr) {
307 return nullptr;
308 }
309 napi_value res = nullptr;
310 SCAN_CALL(env, napi_call_function(env, recv, func, argc, argv, &res));
311 return res;
312 }
313
314 /* reference */
CreateReference(napi_env env,napi_value callback)315 napi_ref NapiScanUtils::CreateReference(napi_env env, napi_value callback)
316 {
317 if (callback == nullptr) {
318 return nullptr;
319 }
320 napi_ref callbackRef = nullptr;
321 SCAN_CALL(env, napi_create_reference(env, callback, 1, &callbackRef));
322 return callbackRef;
323 }
324
GetReference(napi_env env,napi_ref callbackRef)325 napi_value NapiScanUtils::GetReference(napi_env env, napi_ref callbackRef)
326 {
327 if (callbackRef == nullptr) {
328 return nullptr;
329 }
330 napi_value callback = nullptr;
331 SCAN_CALL(env, napi_get_reference_value(env, callbackRef, &callback));
332 return callback;
333 }
334
DeleteReference(napi_env env,napi_ref callbackRef)335 void NapiScanUtils::DeleteReference(napi_env env, napi_ref callbackRef)
336 {
337 if (env != nullptr && callbackRef != nullptr) {
338 (void)napi_delete_reference(env, callbackRef);
339 }
340 }
341
342 /* boolean */
CreateBoolean(napi_env env,bool value)343 napi_value NapiScanUtils::CreateBoolean(napi_env env, bool value)
344 {
345 napi_value jsValue = nullptr;
346 if (napi_get_boolean(env, value, &jsValue) != napi_ok) {
347 return nullptr;
348 }
349 return jsValue;
350 }
351
GetBooleanFromValue(napi_env env,napi_value value)352 bool NapiScanUtils::GetBooleanFromValue(napi_env env, napi_value value)
353 {
354 if (value == nullptr) {
355 return false;
356 }
357 bool ret = false;
358 SCAN_CALL_BASE(env, napi_get_value_bool(env, value, &ret), 0);
359 return ret;
360 }
361
GetBooleanProperty(napi_env env,napi_value object,const std::string & propertyName)362 bool NapiScanUtils::GetBooleanProperty(napi_env env, napi_value object, const std::string &propertyName)
363 {
364 if (object == nullptr) {
365 return false;
366 }
367 if (!HasNamedProperty(env, object, propertyName)) {
368 return false;
369 }
370 napi_value value = GetNamedProperty(env, object, propertyName);
371 bool ret = false;
372 SCAN_CALL_BASE(env, napi_get_value_bool(env, value, &ret), false);
373 return ret;
374 }
375
SetBooleanProperty(napi_env env,napi_value object,const std::string & name,bool value)376 void NapiScanUtils::SetBooleanProperty(napi_env env, napi_value object, const std::string &name, bool value)
377 {
378 if (object == nullptr) {
379 return;
380 }
381 napi_value jsValue = nullptr;
382 SCAN_CALL_RETURN_VOID(env, napi_get_boolean(env, value, &jsValue));
383 if (GetValueType(env, jsValue) != napi_boolean) {
384 return;
385 }
386
387 napi_set_named_property(env, object, name.c_str(), jsValue);
388 }
389
390 /* define properties */
DefineProperties(napi_env env,napi_value object,const std::initializer_list<napi_property_descriptor> & properties)391 void NapiScanUtils::DefineProperties(
392 napi_env env, napi_value object, const std::initializer_list<napi_property_descriptor> &properties)
393 {
394 napi_property_descriptor descriptors[properties.size()];
395 std::copy(properties.begin(), properties.end(), descriptors);
396
397 (void)napi_define_properties(env, object, properties.size(), descriptors);
398 }
399
ToLower(const std::string & s)400 std::string NapiScanUtils::ToLower(const std::string &s)
401 {
402 std::string res = s;
403 std::transform(res.begin(), res.end(), res.begin(), tolower);
404 return res;
405 }
406
GetValueString(napi_env env,napi_value value)407 std::string NapiScanUtils::GetValueString(napi_env env, napi_value value)
408 {
409 if (value == nullptr) {
410 return "";
411 }
412 std::string resultValue = "";
413 char value_string[256] = { 0 };
414 size_t value_size = 256;
415 size_t result = 0;
416 napi_status status = napi_get_value_string_utf8(env, value, value_string, value_size, &result);
417 if (status == napi_ok && result > 0) {
418 resultValue = value_string;
419 }
420 return resultValue;
421 }
422
GetExtensionId(const std::string & globalId)423 std::string NapiScanUtils::GetExtensionId(const std::string &globalId)
424 {
425 auto pos = globalId.find(GLOBAL_ID_DELIMITER);
426 if (pos == std::string::npos) {
427 return "";
428 }
429 return globalId.substr(0, pos);
430 }
431
GetGlobalId(const std::string & extensionId,const std::string & localId)432 std::string NapiScanUtils::GetGlobalId(const std::string& extensionId, const std::string& localId)
433 {
434 return extensionId + GLOBAL_ID_DELIMITER + localId;
435 }
436
GetLocalId(const std::string & globalId,const std::string & extensionId)437 std::string NapiScanUtils::GetLocalId(const std::string& globalId, const std::string& extensionId)
438 {
439 auto pos = globalId.find(GLOBAL_ID_DELIMITER);
440 if (pos == std::string::npos) {
441 return "";
442 }
443
444 if (globalId.substr(0, pos) != extensionId) {
445 return "";
446 }
447 return globalId.substr(pos + 1);
448 }
449
EncodeExtensionCid(const std::string & extensionId,uint32_t callbackId)450 std::string NapiScanUtils::EncodeExtensionCid(const std::string &extensionId, uint32_t callbackId)
451 {
452 return extensionId + EXTENSION_CID_DELIMITER + std::to_string(callbackId);
453 }
454
DecodeExtensionCid(const std::string & cid,std::string & extensionId,uint32_t & callbackId)455 bool NapiScanUtils::DecodeExtensionCid(const std::string &cid, std::string &extensionId, uint32_t &callbackId)
456 {
457 auto pos = cid.find(EXTENSION_CID_DELIMITER);
458 if (pos == std::string::npos) {
459 return false;
460 }
461 extensionId = cid.substr(0, pos);
462 int32_t callbackIdTmp = 0;
463 if (!ScanUtil::ConvertToInt(cid.substr(pos + 1), callbackIdTmp)) {
464 return false;
465 }
466 callbackId = static_cast<uint32_t>(callbackIdTmp);
467 return true;
468 }
469
OpenFile(const std::string & filePath)470 int32_t NapiScanUtils::OpenFile(const std::string &filePath)
471 {
472 if (!IsPathValid(filePath)) {
473 return SCAN_INVALID_ID;
474 }
475 int32_t fd = open(filePath.c_str(), O_RDONLY);
476 SCAN_HILOGD("fd: %{public}d", fd);
477 if (fd < 0) {
478 SCAN_HILOGE("Failed to open file errno: %{public}s", std::to_string(errno).c_str());
479 return SCAN_INVALID_ID;
480 }
481 return fd;
482 }
483
IsPathValid(const std::string & filePath)484 bool NapiScanUtils::IsPathValid(const std::string &filePath)
485 {
486 auto path = filePath.substr(0, filePath.rfind('/'));
487 char resolvedPath[PATH_MAX + 1] = { 0 };
488 if (path.length() > PATH_MAX || realpath(path.c_str(), resolvedPath) == nullptr ||
489 strncmp(resolvedPath, path.c_str(), path.length()) != 0) {
490 SCAN_HILOGE("invalid file path!");
491 return false;
492 }
493 return true;
494 }
495
GetIdFromFdPath(const std::string & fdPath)496 uint32_t NapiScanUtils::GetIdFromFdPath(const std::string &fdPath)
497 {
498 std::string fd_str = fdPath.substr(fdPath.rfind('/') + 1, fdPath.length());
499 std::stringstream getStrStream(fd_str);
500 uint32_t fd = 0;
501 if (!(getStrStream >> fd)) {
502 SCAN_HILOGD("failed to convert to uint32");
503 }
504 return fd;
505 }
506
GetJsVal(napi_env env,napi_callback_info info,napi_value argv[],size_t length)507 size_t NapiScanUtils::GetJsVal(napi_env env, napi_callback_info info, napi_value argv[], size_t length)
508 {
509 size_t argc = length;
510 napi_value thisVal = nullptr;
511 void *data = nullptr;
512 napi_get_cb_info(env, info, &argc, argv, &thisVal, &data);
513 return argc;
514 }
515
NapiThrowError(napi_env env,uint32_t errCode)516 void NapiScanUtils::NapiThrowError(napi_env env, uint32_t errCode)
517 {
518 std::string message;
519 SetErrorText(errCode, message);
520 napi_value result = nullptr;
521 napi_create_error(env, CreateUint32(env, errCode), CreateStringUtf8(env, message), &result);
522 napi_throw(env, result);
523 }
524
SetErrorText(uint32_t & code,std::string & message)525 void NapiScanUtils::SetErrorText(uint32_t& code, std::string& message)
526 {
527 auto it = scanErrorCodeMap_.find(code);
528 if (it != scanErrorCodeMap_.end()) {
529 message = it->second;
530 } else {
531 SCAN_HILOGD("ErrorText not found");
532 code = E_SCAN_GENERIC_FAILURE;
533 message = "SCAN_ERROR_GENERIC_FAILURE";
534 }
535 }
536
CheckCallerIsSystemApp()537 bool NapiScanUtils::CheckCallerIsSystemApp()
538 {
539 auto callerToken = IPCSkeleton::GetCallingTokenID();
540 auto tokenType = Security::AccessToken::AccessTokenKit::GetTokenTypeFlag(callerToken);
541 if (tokenType == Security::AccessToken::ATokenTypeEnum::TOKEN_NATIVE ||
542 tokenType == Security::AccessToken::ATokenTypeEnum::TOKEN_SHELL) {
543 SCAN_HILOGD("tokenType check passed.");
544 return true;
545 }
546 auto accessTokenId = IPCSkeleton::GetCallingFullTokenID();
547 return Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(accessTokenId);
548 }
549 } // namespace OHOS::Scan
550