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  }