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 "commonlibrary/ets_utils/js_util_module/util/js_uuid.h"
17 
18 #include <map>
19 #include "securec.h"
20 #include "tools/log.h"
21 
22 #include "napi/native_api.h"
23 #include "napi/native_node_api.h"
24 
25 namespace OHOS::Util {
26 static thread_local std::queue<UUID> g_uuidCache;
27 
CharToHex(char in)28 unsigned char CharToHex(char in)
29 {
30     unsigned char res = 0;  // 0: initialization
31     static const std::map<char, unsigned char> hexMap = {
32         {'0', HEX_ZERO_FLG},
33         {'1', HEX_ONE_FLG},
34         {'2', HEX_TWO_FLG},
35         {'3', HEX_THREE_FLG},
36         {'4', HEX_FOUR_FLG},
37         {'5', HEX_FIVE_FLG},
38         {'6', HEX_SIX_FLG},
39         {'7', HEX_SEVEN_FLG},
40         {'8', HEX_EIGHT_FLG},
41         {'9', HEX_NINE_FLG},
42         {'a', HEX_TEN_FLG},
43         {'b', HEX_ELEVEN_FLG},
44         {'c', HEX_TWELVE_FLG},
45         {'d', HEX_THIRTEEN_FLG},
46         {'e', HEX_FOURTEEN_FLG},
47         {'f', HEX_FIFTEEN_FLG},
48         {'A', HEX_TEN_FLG},
49         {'B', HEX_ELEVEN_FLG},
50         {'C', HEX_TWELVE_FLG},
51         {'D', HEX_THIRTEEN_FLG},
52         {'E', HEX_FOURTEEN_FLG},
53         {'F', HEX_FIFTEEN_FLG}
54     };
55 
56     auto it = hexMap.find(in);
57     if (it != hexMap.end()) {
58         res = it->second;
59     } else {
60         res = HEX_ZERO_FLG;
61     }
62     return res;
63 }
64 
HexToChar(unsigned char in)65 unsigned char HexToChar(unsigned char in)
66 {
67     unsigned char res = '0';
68     switch (in) {
69         case HEX_ZERO_FLG: res = '0'; break;
70         case HEX_ONE_FLG: res = '1'; break;
71         case HEX_TWO_FLG: res = '2'; break;
72         case HEX_THREE_FLG: res = '3'; break;
73         case HEX_FOUR_FLG: res = '4'; break;
74         case HEX_FIVE_FLG: res = '5'; break;
75         case HEX_SIX_FLG: res = '6'; break;
76         case HEX_SEVEN_FLG: res = '7'; break;
77         case HEX_EIGHT_FLG: res = '8'; break;
78         case HEX_NINE_FLG: res = '9'; break;
79         case HEX_TEN_FLG: res = 'a'; break;
80         case HEX_ELEVEN_FLG: res = 'b'; break;
81         case HEX_TWELVE_FLG: res = 'c'; break;
82         case HEX_THIRTEEN_FLG: res = 'd'; break;
83         case HEX_FOURTEEN_FLG: res = 'e'; break;
84         case HEX_FIFTEEN_FLG: res = 'f'; break;
85         default : res = 'x';
86     }
87     return res;
88 }
89 
ConvertBits(std::string & input)90 unsigned char ConvertBits(std::string &input)
91 {
92     unsigned char temp = 0; // 0: initialization
93     if (input[0] == '-') {
94         input.erase(0, 1);
95     }
96     temp = CharToHex(input[0]);
97     temp *= HEX_SIXTEEN_FLG;
98     input.erase(0, 1);
99     temp += CharToHex(input[0]);
100     input.erase(0, 1);
101     return temp;
102 }
103 
GenerateUuid(unsigned char * data,int32_t size)104 bool GenerateUuid(unsigned char *data, int32_t size)
105 {
106     unsigned char buf[UUID_SIZE] = { 0 };  // 0: initialization
107     if (memcpy_s(data, size, buf, size) != EOK) {
108         return false;
109     }
110     RAND_priv_bytes(data, size);
111     data[HEX_SIX_FLG] = (data[HEX_SIX_FLG] & 0x0F) | 0x40; // 0x0F,0x40 Operate the mark
112     int m = 0x8;    // Upper of numerical range
113     int n = 0xb;    // down of numerical range
114     int r = static_cast<int>(data[HEX_EIGHT_FLG]);
115     unsigned char num = static_cast<unsigned char>(r % (n - m + 1) + m);
116     data[HEX_EIGHT_FLG] = (data[HEX_EIGHT_FLG] & 0x0F) | (num << 4);  // 0x0F,4 Operate the mark
117     return true;
118 }
119 
GetUUID(napi_env env,bool entropyCache,UUID & uuid)120 bool GetUUID(napi_env env, bool entropyCache, UUID &uuid)
121 {
122     uint32_t size = g_uuidCache.size();
123     if ((entropyCache == true) && (size != 0)) {
124         uuid = g_uuidCache.front();
125         g_uuidCache.pop();
126     } else {
127         if (size > MAX_CACHE_MASK) {
128             for (uint32_t i = 0; i < size; i++) {
129                 g_uuidCache.pop();
130             }
131         }
132         bool res = GenerateUuid(uuid.elements, sizeof(uuid.elements));
133         if (!res) {
134             napi_throw_error(env, "-1", "uuid generate failed");
135             return false;
136         }
137         g_uuidCache.push(uuid);
138         res = GenerateUuid(uuid.elements, sizeof(uuid.elements));
139         if (!res) {
140             napi_throw_error(env, "-1", "uuid generate failed");
141             return false;
142         }
143     }
144     return true;
145 }
146 
GetStringUUID(napi_env env,bool entropyCache)147 std::string GetStringUUID(napi_env env, bool entropyCache)
148 {
149     UUID uuid;
150     std::string uuidString = "";
151     if (!GetUUID(env, entropyCache, uuid)) {
152         uuidString = '0';
153     } else {
154         uuidString = GetFormatUUID(uuid);
155     }
156     return uuidString;
157 }
158 
GetFormatUUID(const UUID & uuid)159 std::string GetFormatUUID(const UUID &uuid)
160 {
161     std::string format = "";
162     for (size_t i = 0; i < sizeof(uuid.elements); i++) {
163         unsigned char value = uuid.elements[i];
164         if (i >= HEX_FOUR_FLG && i % 2 == 0 && i <= HEX_TEN_FLG) {  // 2: step value
165             format += "-";
166         }
167         format += HexToChar(value >> HEX_FOUR_FLG);
168         unsigned char high = value & 0xF0;  // Operate the mark
169         if (high == 0) {
170             format += HexToChar(value);
171         } else {
172             format += HexToChar(value % (value & high));
173         }
174     }
175     return format;
176 }
177 
GetBinaryUUID(napi_env env,bool entropyCache)178 napi_value GetBinaryUUID(napi_env env, bool entropyCache)
179 {
180     UUID uuid;
181     if (!GetUUID(env, entropyCache, uuid)) {
182         return nullptr;
183     }
184     void *data = nullptr;
185     napi_value arrayBuffer = nullptr;
186     size_t bufferSize = sizeof(uuid.elements);
187     napi_create_arraybuffer(env, bufferSize, &data, &arrayBuffer);
188     if (memcpy_s(data, bufferSize, uuid.elements, bufferSize) != EOK) {
189         HILOG_ERROR("get uuid memcpy_s failed");
190         return nullptr;
191     }
192     napi_value result = nullptr;
193     napi_create_typedarray(env, napi_uint8_array, bufferSize, arrayBuffer, 0, &result);
194     return result;
195 }
196 
DoParseUUID(napi_env env,napi_value src)197 napi_value DoParseUUID(napi_env env, napi_value src)
198 {
199     size_t outLen = 16; // 16: the length of UUID
200     std::string buffer = "";
201     size_t bufferSize = 0;  // 0: initialization
202     napi_status status = napi_ok;
203     status = napi_get_value_string_utf8(env, src, nullptr, 0, &bufferSize);
204     if (status != napi_ok) {
205         HILOG_ERROR("can not get src size");
206         return nullptr;
207     }
208     buffer.resize(bufferSize);
209     status = napi_get_value_string_utf8(env, src, buffer.data(), bufferSize + 1, &bufferSize);
210     if (status != napi_ok) {
211         HILOG_ERROR("can not get src value");
212         return nullptr;
213     }
214     void *data = nullptr;
215     napi_value arrayBuffer = nullptr;
216     napi_create_arraybuffer(env, outLen, &data, &arrayBuffer);
217     unsigned char *count = static_cast<unsigned char*>(data);
218     for (size_t i = 0; !buffer.empty() && i < outLen; i++) {
219         *count = ConvertBits(buffer);
220         count++;
221     }
222     napi_value result = nullptr;
223     napi_create_typedarray(env, napi_uint8_array, outLen, arrayBuffer, 0, &result);
224     return result;
225 }
226 }