1/*
2 * Copyright (c) 2023 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 "hiview_napi_util.h"
17
18#include "hiview_err_code.h"
19#include "hiview_logger.h"
20#include "ipc_skeleton.h"
21#include "tokenid_kit.h"
22
23namespace OHOS {
24namespace HiviewDFX {
25DEFINE_LOG_LABEL(0xD002D03, "HiviewNapiUtil");
26namespace {
27constexpr char FILE_NAME_KEY[] = "name";
28constexpr char FILE_TIME_KEY[] = "mtime";
29constexpr char FILE_SIZE_KEY[] = "size";
30constexpr int32_t BUF_SIZE = 1024;
31}
32
33void HiviewNapiUtil::CreateUndefined(const napi_env env, napi_value& ret)
34{
35    if (napi_get_undefined(env, &ret) != napi_ok) {
36        HIVIEW_LOGE("failed to create undefined value.");
37    }
38}
39
40void HiviewNapiUtil::CreateInt32Value(const napi_env env, int32_t value, napi_value& ret)
41{
42    if (napi_create_int32(env, value, &ret) != napi_ok) {
43        HIVIEW_LOGE("failed to create int32 napi value.");
44    }
45}
46
47void HiviewNapiUtil::CreateInt64Value(const napi_env env, int64_t value, napi_value& ret)
48{
49    if (napi_create_int64(env, value, &ret) != napi_ok) {
50        HIVIEW_LOGE("failed to create int64 napi value.");
51    }
52}
53
54void HiviewNapiUtil::CreateStringValue(const napi_env env, const std::string& value, napi_value& ret)
55{
56    if (napi_create_string_utf8(env, value.c_str(), NAPI_AUTO_LENGTH, &ret) != napi_ok) {
57        HIVIEW_LOGE("failed to create string napi value.");
58    }
59}
60
61void HiviewNapiUtil::CreateErrorByRet(napi_env env, const int32_t retCode, napi_value& ret)
62{
63    auto detail = GetErrorDetailByRet(env, retCode);
64    napi_value napiCode = nullptr;
65    CreateStringValue(env, std::to_string(detail.first), napiCode);
66    napi_value napiStr = nullptr;
67    CreateStringValue(env, detail.second, napiStr);
68    if (napi_create_error(env, napiCode, napiStr, &ret) != napi_ok) {
69        HIVIEW_LOGE("failed to create napi error");
70    }
71}
72
73std::pair<int32_t, std::string> HiviewNapiUtil::GetErrorDetailByRet(napi_env env, const int32_t retCode)
74{
75    HIVIEW_LOGI("origin result code is %{public}d.", retCode);
76    const std::unordered_map<int32_t, std::pair<int32_t, std::string>> errMap = {
77        {HiviewNapiErrCode::ERR_PERMISSION_CHECK, {HiviewNapiErrCode::ERR_PERMISSION_CHECK,
78            "Permission denied. The app does not have the necessary permissions."}},
79        {HiviewNapiErrCode::ERR_INNER_INVALID_LOGTYPE,
80            {HiviewNapiErrCode::ERR_PARAM_CHECK, "Parameter error. The value of logType is invalid."}},
81        {HiviewNapiErrCode::ERR_INNER_READ_ONLY,
82            {HiviewNapiErrCode::ERR_PARAM_CHECK, "Parameter error. The specified logType is read-only."}},
83        {HiviewNapiErrCode::ERR_SOURCE_FILE_NOT_EXIST,
84            {HiviewNapiErrCode::ERR_SOURCE_FILE_NOT_EXIST, "Source file does not exists."}}
85    };
86    return errMap.find(retCode) == errMap.end() ?
87        std::make_pair(HiviewNapiErrCode::ERR_DEFAULT, "Environment is abnormal.") : errMap.at(retCode);
88}
89
90bool HiviewNapiUtil::IsMatchType(napi_env env, const napi_value& value, napi_valuetype type)
91{
92    napi_valuetype paramType;
93    napi_typeof(env, value, &paramType);
94    return paramType == type;
95}
96
97void HiviewNapiUtil::SetNamedProperty(
98    const napi_env env, napi_value& object, const std::string& propertyName, napi_value& propertyValue)
99{
100    if (napi_set_named_property(env, object, propertyName.c_str(), propertyValue) != napi_ok) {
101        HIVIEW_LOGE("set %{public}s property failed", propertyName.c_str());
102    }
103}
104
105bool HiviewNapiUtil::ParseStringValue(
106    const napi_env env, const std::string& paramName, const napi_value& value, std::string& retValue)
107{
108    if (!IsMatchType(env, value, napi_string)) {
109        HIVIEW_LOGE("parameter %{public}s type isn't string", paramName.c_str());
110        ThrowParamTypeError(env, paramName, "string");
111        return false;
112    }
113    char buf[BUF_SIZE] = {0};
114    size_t bufLength = 0;
115    if (napi_get_value_string_utf8(env, value, buf, BUF_SIZE - 1, &bufLength) != napi_ok) {
116        HIVIEW_LOGE("failed to parse napi value of string type.");
117    } else {
118        retValue = std::string {buf};
119    }
120    return true;
121}
122
123void HiviewNapiUtil::CreateJsFileInfo(const napi_env env, const HiviewFileInfo& fileInfo, napi_value& val)
124{
125    napi_value name;
126    CreateStringValue(env, fileInfo.name, name);
127    SetNamedProperty(env, val, FILE_NAME_KEY, name);
128
129    napi_value mtime;
130    CreateInt64Value(env, fileInfo.mtime, mtime);
131    SetNamedProperty(env, val, FILE_TIME_KEY, mtime);
132
133    napi_value size;
134    CreateInt64Value(env, fileInfo.size, size);
135    SetNamedProperty(env, val, FILE_SIZE_KEY, size);
136}
137
138napi_value HiviewNapiUtil::GenerateFileInfoResult(const napi_env env, const std::vector<HiviewFileInfo>& fileInfos)
139{
140    napi_value result;
141    auto length = fileInfos.size();
142    napi_create_array_with_length(env, length, &result);
143    for (decltype(length) i = 0; i < length; ++i) {
144        napi_value item;
145        if (napi_create_object(env, &item) != napi_ok) {
146            HIVIEW_LOGE("failed to create a new napi object.");
147            break;
148        }
149        CreateJsFileInfo(env, fileInfos[i], item);
150        napi_set_element(env, result, i, item);
151    }
152    return result;
153}
154
155bool HiviewNapiUtil::CheckDirPath(const std::string& path)
156{
157    return path.empty() || path.find("..") == std::string::npos;
158}
159
160void HiviewNapiUtil::ThrowErrorByCode(napi_env env, int32_t errCode)
161{
162    auto detail = GetErrorDetailByRet(env, errCode);
163    ThrowError(env, detail.first, detail.second);
164}
165
166void HiviewNapiUtil::ThrowParamContentError(napi_env env, const std::string& paramName)
167{
168    ThrowError(env, HiviewNapiErrCode::ERR_PARAM_CHECK,
169        "Parameter error. The content of " + paramName + " is invalid.");
170}
171
172void HiviewNapiUtil::ThrowParamTypeError(napi_env env, const std::string& paramName, const std::string& paramType)
173{
174    ThrowError(env, HiviewNapiErrCode::ERR_PARAM_CHECK,
175        "Parameter error. The type of " + paramName + " must be " + paramType + ".");
176}
177
178void HiviewNapiUtil::ThrowError(napi_env env, const int32_t code, const std::string& msg)
179{
180    if (napi_throw_error(env, std::to_string(code).c_str(), msg.c_str()) != napi_ok) {
181        HIVIEW_LOGE("failed to throw error, code=%{public}d, msg=%{public}s", code, msg.c_str());
182    }
183}
184
185void HiviewNapiUtil::ThrowSystemAppPermissionError(napi_env env)
186{
187    ThrowError(env, HiviewNapiErrCode::ERR_NON_SYS_APP_PERMISSION,
188        "Permission denied, non-system app called system api.");
189}
190
191bool HiviewNapiUtil::IsSystemAppCall()
192{
193    uint64_t tokenId = IPCSkeleton::GetCallingFullTokenID();
194    return Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(tokenId);
195}
196} // namespace HiviewDFX
197} // namespace OHOS