1/*
2 * Copyright (c) 2021-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 "dh_utils_tool.h"
17
18#include <algorithm>
19#include <iomanip>
20#include <iostream>
21#include <random>
22#include <sstream>
23#include <string>
24#include <sys/time.h>
25#include <vector>
26#include <zlib.h>
27
28#include "openssl/sha.h"
29#include "parameter.h"
30
31#include "device_manager.h"
32#include "dm_device_info.h"
33
34#include "constants.h"
35#include "distributed_hardware_errno.h"
36#include "distributed_hardware_log.h"
37
38namespace OHOS {
39namespace DistributedHardware {
40namespace {
41    constexpr int32_t MS_ONE_SECOND = 1000;
42    constexpr int32_t WORD_WIDTH_8 = 8;
43    constexpr int32_t WORD_WIDTH_4 = 4;
44    constexpr int32_t WIDTH = 4;
45    constexpr unsigned char MASK = 0x0F;
46    constexpr int32_t DOUBLE_TIMES = 2;
47    constexpr int32_t COMPRESS_SLICE_SIZE = 1024;
48    const std::string PARAM_KEY_OS_TYPE = "OS_TYPE";
49}
50
51int64_t GetCurrentTime()
52{
53    struct timeval tv {
54        0
55    };
56    gettimeofday(&tv, nullptr);
57    return tv.tv_sec * MS_ONE_SECOND + tv.tv_usec / MS_ONE_SECOND;
58}
59
60std::string GetRandomID()
61{
62    static std::random_device rd;
63    static std::uniform_int_distribution<uint64_t> dist(0ULL, 0xFFFFFFFFFFFFFFFFULL);
64    uint64_t ab = dist(rd);
65    uint64_t cd = dist(rd);
66    uint32_t a;
67    uint32_t b;
68    uint32_t c;
69    uint32_t d;
70    std::stringstream ss;
71    ab = (ab & 0xFFFFFFFFFFFF0FFFULL) | 0x0000000000004000ULL;
72    cd = (cd & 0x3FFFFFFFFFFFFFFFULL) | 0x8000000000000000ULL;
73    a = (ab >> 32U);
74    b = (ab & 0xFFFFFFFFU);
75    c = (cd >> 32U);
76    d = (cd & 0xFFFFFFFFU);
77    ss << std::hex << std::nouppercase << std::setfill('0');
78    ss << std::setw(WORD_WIDTH_8) << (a);
79    ss << std::setw(WORD_WIDTH_4) << (b >> 16U);
80    ss << std::setw(WORD_WIDTH_4) << (b & 0xFFFFU);
81    ss << std::setw(WORD_WIDTH_4) << (c >> 16U);
82    ss << std::setw(WORD_WIDTH_4) << (c & 0xFFFFU);
83    ss << std::setw(WORD_WIDTH_8) << d;
84
85    return ss.str();
86}
87
88std::string GetUUIDByDm(const std::string &networkId)
89{
90    if (!IsIdLengthValid(networkId)) {
91        return "";
92    }
93    std::string uuid = "";
94    auto ret = DeviceManager::GetInstance().GetUuidByNetworkId(DH_FWK_PKG_NAME, networkId, uuid);
95    return (ret == DH_FWK_SUCCESS) ? uuid : "";
96}
97
98std::string GetUDIDByDm(const std::string &networkId)
99{
100    if (!IsIdLengthValid(networkId)) {
101        return "";
102    }
103    std::string udid = "";
104    auto ret = DeviceManager::GetInstance().GetUdidByNetworkId(DH_FWK_PKG_NAME, networkId, udid);
105    return (ret == DH_FWK_SUCCESS) ? udid : "";
106}
107
108std::string GetDeviceIdByUUID(const std::string &uuid)
109{
110    if (!IsIdLengthValid(uuid)) {
111        DHLOGE("uuid is invalid!");
112        return "";
113    }
114    return Sha256(uuid);
115}
116
117std::string Sha256(const std::string& in)
118{
119    unsigned char out[SHA256_DIGEST_LENGTH * DOUBLE_TIMES + 1] = {0};
120    SHA256_CTX ctx;
121    SHA256_Init(&ctx);
122    SHA256_Update(&ctx, in.data(), in.size());
123    SHA256_Final(&out[SHA256_DIGEST_LENGTH], &ctx);
124    // here we translate sha256 hash to hexadecimal. each 8-bit char will be presented by two characters([0-9a-f])
125    const char* hexCode = "0123456789abcdef";
126    for (int32_t i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
127        unsigned char value = out[SHA256_DIGEST_LENGTH + i];
128        // uint8_t is 2 digits in hexadecimal.
129        out[i * DOUBLE_TIMES] = hexCode[(value >> WIDTH) & MASK];
130        out[i * DOUBLE_TIMES + 1] = hexCode[value & MASK];
131    }
132    out[SHA256_DIGEST_LENGTH * DOUBLE_TIMES] = 0;
133    return std::string(reinterpret_cast<char*>(out));
134}
135
136DeviceInfo GetLocalDeviceInfo()
137{
138    DeviceInfo devInfo { "", "", "", "", "", "", 0 };
139    DmDeviceInfo info;
140    auto ret = DeviceManager::GetInstance().GetLocalDeviceInfo(DH_FWK_PKG_NAME, info);
141    if (ret != DH_FWK_SUCCESS) {
142        DHLOGE("GetLocalNodeDeviceInfo failed, errCode = %{public}d", ret);
143        return devInfo;
144    }
145    devInfo.networkId = info.networkId;
146    devInfo.uuid = GetUUIDByDm(info.networkId);
147    devInfo.deviceId = GetDeviceIdByUUID(devInfo.uuid);
148    devInfo.udid = GetUDIDByDm(info.networkId);
149    devInfo.udidHash = Sha256(devInfo.udid);
150    devInfo.deviceName = info.deviceName;
151    devInfo.deviceType = info.deviceTypeId;
152    return devInfo;
153}
154
155std::string GetLocalNetworkId()
156{
157    DmDeviceInfo info;
158    auto ret = DeviceManager::GetInstance().GetLocalDeviceInfo(DH_FWK_PKG_NAME, info);
159    if (ret != DH_FWK_SUCCESS) {
160        DHLOGE("GetLocalNodeDeviceInfo failed, errCode = %{public}d", ret);
161        return "";
162    }
163    return info.networkId;
164}
165
166bool IsUInt8(const cJSON* jsonObj, const std::string& key)
167{
168    const cJSON* value = cJSON_GetObjectItem(jsonObj, key.c_str());
169    if (value == NULL || !cJSON_IsNumber(value)) {
170        return false;
171    }
172    return (value->valuedouble >= 0 && value->valuedouble <= UINT8_MAX);
173}
174
175bool IsUInt16(const cJSON* jsonObj, const std::string& key)
176{
177    const cJSON* value = cJSON_GetObjectItem(jsonObj, key.c_str());
178    if (value == NULL || !cJSON_IsNumber(value)) {
179        return false;
180    }
181    return (value->valuedouble >= 0 && value->valuedouble <= UINT16_MAX);
182}
183
184bool IsInt32(const cJSON* jsonObj, const std::string& key)
185{
186    const cJSON* value = cJSON_GetObjectItem(jsonObj, key.c_str());
187    if (value == NULL || !cJSON_IsNumber(value)) {
188        return false;
189    }
190    return (value->valuedouble >= INT32_MIN && value->valuedouble <= INT32_MAX);
191}
192
193bool IsUInt32(const cJSON* jsonObj, const std::string& key)
194{
195    const cJSON* value = cJSON_GetObjectItem(jsonObj, key.c_str());
196    if (value == NULL || !cJSON_IsNumber(value)) {
197        return false;
198    }
199    return (value->valuedouble >= 0 && value->valuedouble <= UINT32_MAX);
200}
201
202bool IsBool(const cJSON* jsonObj, const std::string& key)
203{
204    const cJSON* value = cJSON_GetObjectItem(jsonObj, key.c_str());
205    return (value != NULL && cJSON_IsBool(value));
206}
207
208bool IsString(const cJSON* jsonObj, const std::string& key)
209{
210    const cJSON* value = cJSON_GetObjectItem(jsonObj, key.c_str());
211    if (value == NULL || !cJSON_IsString(value)) {
212        return false;
213    }
214    return (strlen(value->valuestring) > MIN_MESSAGE_LEN && strlen(value->valuestring) <= MAX_MESSAGE_LEN);
215}
216
217bool IsArray(const cJSON* jsonObj, const std::string& key)
218{
219    const cJSON* value = cJSON_GetObjectItem(jsonObj, key.c_str());
220    if (value == NULL || !cJSON_IsArray(value)) {
221        return false;
222    }
223    return ((uint32_t)cJSON_GetArraySize(value) >= 0 && (uint32_t)cJSON_GetArraySize(value) <= MAX_ARR_SIZE);
224}
225
226std::string Compress(const std::string& data)
227{
228    z_stream strm;
229    strm.zalloc = Z_NULL;
230    strm.zfree = Z_NULL;
231    strm.opaque = Z_NULL;
232    deflateInit(&strm, Z_DEFAULT_COMPRESSION);
233
234    strm.next_in = reinterpret_cast<Bytef*>(const_cast<char *>(data.data()));
235    strm.avail_in = data.size();
236    std::string out;
237    std::vector<Bytef> temp_out(COMPRESS_SLICE_SIZE, 0);
238
239    do {
240        strm.next_out = temp_out.data();
241        strm.avail_out = COMPRESS_SLICE_SIZE;
242        deflate(&strm, Z_FINISH);
243        out.append(reinterpret_cast<char*>(temp_out.data()), COMPRESS_SLICE_SIZE - strm.avail_out);
244    } while (strm.avail_out == 0);
245
246    deflateEnd(&strm);
247    return out;
248}
249
250std::string Decompress(const std::string& data)
251{
252    z_stream strm;
253    strm.zalloc = Z_NULL;
254    strm.zfree = Z_NULL;
255    strm.opaque = Z_NULL;
256    strm.avail_in = 0;
257    strm.next_in = Z_NULL;
258    inflateInit(&strm);
259
260    strm.next_in = reinterpret_cast<Bytef*>(const_cast<char *>(data.data()));
261    strm.avail_in = data.size();
262    std::string out;
263    std::vector<Bytef> temp_out(COMPRESS_SLICE_SIZE, 0);
264
265    do {
266        strm.next_out = temp_out.data();
267        strm.avail_out = COMPRESS_SLICE_SIZE;
268        inflate(&strm, Z_NO_FLUSH);
269        out.append(reinterpret_cast<char*>(temp_out.data()), COMPRESS_SLICE_SIZE - strm.avail_out);
270    } while (strm.avail_out == 0);
271
272    inflateEnd(&strm);
273    return out;
274}
275
276bool GetSysPara(const char *key, bool &value)
277{
278    if (key == nullptr) {
279        DHLOGE("GetSysPara: key is nullptr");
280        return false;
281    }
282    char paraValue[20] = {0}; // 20 for system parameter
283    auto res = GetParameter(key, "false", paraValue, sizeof(paraValue));
284    if (res <= 0) {
285        DHLOGD("GetSysPara fail, key:%{public}s res:%{public}d", key, res);
286        return false;
287    }
288    DHLOGI("GetSysPara: key:%{public}s value:%{public}s", key, paraValue);
289    std::stringstream valueStr;
290    valueStr << paraValue;
291    valueStr >> std::boolalpha >> value;
292    return true;
293}
294
295bool IsIdLengthValid(const std::string &inputID)
296{
297    if (inputID.empty() || inputID.length() > MAX_ID_LEN) {
298        DHLOGE("On parameter length error, maybe empty or beyond MAX_ID_LEN!");
299        return false;
300    }
301    return true;
302}
303
304bool IsMessageLengthValid(const std::string &inputMessage)
305{
306    if (inputMessage.empty() || inputMessage.length() > MAX_MESSAGE_LEN) {
307        DHLOGE("On parameter error, maybe empty or beyond MAX_MESSAGE_LEN!");
308        return false;
309    }
310    return true;
311}
312
313bool IsJsonLengthValid(const std::string &inputJsonStr)
314{
315    if (inputJsonStr.empty() || inputJsonStr.length() > MAX_JSON_SIZE) {
316        DHLOGE("On parameter error, maybe empty or beyond MAX_JSON_SIZE");
317        return false;
318    }
319    return true;
320}
321
322bool IsArrayLengthValid(const std::vector<std::string> &inputArray)
323{
324    if (inputArray.empty() || inputArray.size() > MAX_ARR_SIZE) {
325        DHLOGE("On parameter error, maybe empty or beyond MAX_ARR_SIZE");
326        return false;
327    }
328    return true;
329}
330
331bool IsKeySizeValid(const std::string &inputKey)
332{
333    if (inputKey.empty() || inputKey.length() > MAX_KEY_SIZE) {
334        DHLOGE("On parameter error, maybe empty or beyond MAX_KEY_SIZE");
335        return false;
336    }
337    return true;
338}
339
340bool IsHashSizeValid(const std::string &inputHashValue)
341{
342    if (inputHashValue.empty() || inputHashValue.length() > MAX_HASH_SIZE) {
343        DHLOGE("On parameter error, maybe empty or beyond MAX_HASH_SIZE");
344        return false;
345    }
346    return true;
347}
348
349int32_t GetDeviceSystemType(const std::string &extraData)
350{
351    cJSON *jsonObj = cJSON_Parse(extraData.c_str());
352    if (jsonObj == NULL) {
353        DHLOGE("jsonStr parse failed");
354        return ERR_DH_FWK_INVALID_OSTYPE;
355    }
356    cJSON *paramKey = cJSON_GetObjectItem(jsonObj, PARAM_KEY_OS_TYPE.c_str());
357    if (paramKey == NULL || !cJSON_IsNumber(paramKey)) {
358        DHLOGE("paramKey is null or paramKey is invaild type!");
359        cJSON_Delete(jsonObj);
360        return ERR_DH_FWK_INVALID_OSTYPE;
361    }
362    int32_t osType = paramKey->valueint;
363    cJSON_Delete(jsonObj);
364    return osType;
365}
366} // namespace DistributedHardware
367} // namespace OHOS
368