Mercurial > pub > ImplabJs
comparison src/implab/Uuid.js @ 3:00779cb63b12
formatting
author | cin |
---|---|
date | Tue, 06 Jun 2017 19:45:32 +0300 |
parents | 93fb6c09f2e1 |
children |
comparison
equal
deleted
inserted
replaced
2:7d7059d2a810 | 3:00779cb63b12 |
---|---|
1 // uuid.js | 1 // uuid.js |
2 // | 2 // |
3 // Copyright (c) 2010-2012 Robert Kieffer | 3 // Copyright (c) 2010-2012 Robert Kieffer |
4 // MIT License - http://opensource.org/licenses/mit-license.php | 4 // MIT License - http://opensource.org/licenses/mit-license.php |
5 define( | 5 define([], function () { |
6 [], | 6 'use strict'; |
7 function () { | 7 |
8 'use strict'; | 8 var _window = 'undefined' !== typeof window ? window : null; |
9 | 9 |
10 var _window = 'undefined' !== typeof window ? window : null; | 10 // Unique ID creation requires a high quality random # generator. We |
11 | 11 // feature |
12 // Unique ID creation requires a high quality random # generator. We | 12 // detect to determine the best RNG source, normalizing to a function |
13 // feature | 13 // that |
14 // detect to determine the best RNG source, normalizing to a function | 14 // returns 128-bits of randomness, since that's what's usually required |
15 // that | 15 var _rng, _mathRNG, _nodeRNG, _whatwgRNG, _previousRoot; |
16 // returns 128-bits of randomness, since that's what's usually required | 16 |
17 var _rng, _mathRNG, _nodeRNG, _whatwgRNG, _previousRoot; | 17 function setupBrowser() { |
18 | 18 // Allow for MSIE11 msCrypto |
19 function setupBrowser() { | 19 var _crypto = _window.crypto || _window.msCrypto; |
20 // Allow for MSIE11 msCrypto | 20 |
21 var _crypto = _window.crypto || _window.msCrypto; | 21 if (!_rng && _crypto && _crypto.getRandomValues) { |
22 | 22 // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto |
23 if (!_rng && _crypto && _crypto.getRandomValues) { | |
24 // WHATWG crypto-based RNG - http://wiki.whatwg.org/wiki/Crypto | |
25 // | |
26 // Moderately fast, high quality | |
27 try { | |
28 var _rnds8 = new Uint8Array(16); | |
29 _whatwgRNG = _rng = function whatwgRNG() { | |
30 _crypto.getRandomValues(_rnds8); | |
31 return _rnds8; | |
32 }; | |
33 _rng(); | |
34 } catch (e) { /**/ } | |
35 } | |
36 | |
37 if (!_rng) { | |
38 // Math.random()-based (RNG) | |
39 // | |
40 // If all else fails, use Math.random(). It's fast, but is of | |
41 // unspecified | |
42 // quality. | |
43 var _rnds = new Array(16); | |
44 _mathRNG = _rng = function () { | |
45 for (var i = 0, r; i < 16; i++) { | |
46 if ((i & 0x03) === 0) { | |
47 r = Math.random() * 0x100000000; | |
48 } | |
49 _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff; | |
50 } | |
51 | |
52 return _rnds; | |
53 }; | |
54 if ('undefined' !== typeof console && console.warn) { | |
55 console | |
56 .warn("[SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()"); | |
57 } | |
58 } | |
59 } | |
60 | |
61 function setupNode() { | |
62 // Node.js crypto-based RNG - | |
63 // http://nodejs.org/docs/v0.6.2/api/crypto.html | |
64 // | 23 // |
65 // Moderately fast, high quality | 24 // Moderately fast, high quality |
66 if ('function' === typeof require) { | 25 try { |
67 try { | 26 var _rnds8 = new Uint8Array(16); |
68 var _rb = require('crypto').randomBytes; | 27 _whatwgRNG = _rng = function whatwgRNG() { |
69 _nodeRNG = _rng = _rb && function () { | 28 _crypto.getRandomValues(_rnds8); |
70 return _rb(16); | 29 return _rnds8; |
71 }; | 30 }; |
72 _rng(); | 31 _rng(); |
73 } catch (e) { /**/ } | 32 } catch (e) { /**/ } |
33 } | |
34 | |
35 if (!_rng) { | |
36 // Math.random()-based (RNG) | |
37 // | |
38 // If all else fails, use Math.random(). It's fast, but is of | |
39 // unspecified | |
40 // quality. | |
41 var _rnds = new Array(16); | |
42 _mathRNG = _rng = function () { | |
43 for (var i = 0, r; i < 16; i++) { | |
44 if ((i & 0x03) === 0) { | |
45 r = Math.random() * 0x100000000; | |
46 } | |
47 _rnds[i] = r >>> ((i & 0x03) << 3) & 0xff; | |
48 } | |
49 | |
50 return _rnds; | |
51 }; | |
52 if ('undefined' !== typeof console && console.warn) { | |
53 console | |
54 .warn("[SECURITY] node-uuid: crypto not usable, falling back to insecure Math.random()"); | |
74 } | 55 } |
75 } | 56 } |
76 | 57 } |
77 if (_window) { | 58 |
78 setupBrowser(); | 59 function setupNode() { |
79 } else { | 60 // Node.js crypto-based RNG - |
80 setupNode(); | 61 // http://nodejs.org/docs/v0.6.2/api/crypto.html |
81 } | 62 // |
82 | 63 // Moderately fast, high quality |
83 // Buffer class to use | 64 if ('function' === typeof require) { |
84 var BufferClass = ('function' === typeof Buffer) ? Buffer : Array; | 65 try { |
85 | 66 var _rb = require('crypto').randomBytes; |
86 // Maps for number <-> hex string conversion | 67 _nodeRNG = _rng = _rb && function () { |
87 var _byteToHex = []; | 68 return _rb(16); |
88 var _hexToByte = {}; | 69 }; |
89 for (var i = 0; i < 256; i++) { | 70 _rng(); |
90 _byteToHex[i] = (i + 0x100).toString(16).substr(1); | 71 } catch (e) { /**/ } |
91 _hexToByte[_byteToHex[i]] = i; | 72 } |
92 } | 73 } |
93 | 74 |
94 // **`parse()` - Parse a UUID into it's component bytes** | 75 if (_window) { |
95 function parse(s, buf, offset) { | 76 setupBrowser(); |
96 var i = (buf && offset) || 0, | 77 } else { |
97 ii = 0; | 78 setupNode(); |
98 | 79 } |
99 buf = buf || []; | 80 |
100 s.toLowerCase().replace(/[0-9a-f]{2}/g, function (oct) { | 81 // Buffer class to use |
101 if (ii < 16) { // Don't overflow! | 82 var BufferClass = ('function' === typeof Buffer) ? Buffer : Array; |
102 buf[i + ii++] = _hexToByte[oct]; | 83 |
103 } | 84 // Maps for number <-> hex string conversion |
104 }); | 85 var _byteToHex = []; |
105 | 86 var _hexToByte = {}; |
106 // Zero out remaining bytes if string was short | 87 for (var i = 0; i < 256; i++) { |
107 while (ii < 16) { | 88 _byteToHex[i] = (i + 0x100).toString(16).substr(1); |
108 buf[i + ii++] = 0; | 89 _hexToByte[_byteToHex[i]] = i; |
90 } | |
91 | |
92 // **`parse()` - Parse a UUID into it's component bytes** | |
93 function parse(s, buf, offset) { | |
94 var i = (buf && offset) || 0, | |
95 ii = 0; | |
96 | |
97 buf = buf || []; | |
98 s.toLowerCase().replace(/[0-9a-f]{2}/g, function (oct) { | |
99 if (ii < 16) { // Don't overflow! | |
100 buf[i + ii++] = _hexToByte[oct]; | |
109 } | 101 } |
110 | 102 }); |
111 return buf; | 103 |
112 } | 104 // Zero out remaining bytes if string was short |
113 | 105 while (ii < 16) { |
114 // **`unparse()` - Convert UUID byte array (ala parse()) into a string** | 106 buf[i + ii++] = 0; |
115 function unparse(buf, offset) { | 107 } |
116 var i = offset || 0, | 108 |
117 bth = _byteToHex; | 109 return buf; |
118 return bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + | 110 } |
119 bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' + | 111 |
120 bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] + | 112 // **`unparse()` - Convert UUID byte array (ala parse()) into a string** |
121 bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + | 113 function unparse(buf, offset) { |
122 bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]]; | 114 var i = offset || 0, |
123 } | 115 bth = _byteToHex; |
124 | 116 return bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + |
125 // **`v1()` - Generate time-based UUID** | 117 bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' + |
126 // | 118 bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] + |
127 // Inspired by https://github.com/LiosK/UUID.js | 119 bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + |
128 // and http://docs.python.org/library/uuid.html | 120 bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]]; |
129 | 121 } |
130 // random #'s we need to init node and clockseq | 122 |
131 var _seedBytes = _rng(); | 123 // **`v1()` - Generate time-based UUID** |
132 | 124 // |
133 // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = | 125 // Inspired by https://github.com/LiosK/UUID.js |
134 // 1) | 126 // and http://docs.python.org/library/uuid.html |
135 var _nodeId = [ | 127 |
136 _seedBytes[0] | 0x01, | 128 // random #'s we need to init node and clockseq |
137 _seedBytes[1], | 129 var _seedBytes = _rng(); |
138 _seedBytes[2], | 130 |
139 _seedBytes[3], | 131 // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = |
140 _seedBytes[4], | 132 // 1) |
141 _seedBytes[5] | 133 var _nodeId = [ |
142 ]; | 134 _seedBytes[0] | 0x01, |
143 | 135 _seedBytes[1], |
144 // Per 4.2.2, randomize (14 bit) clockseq | 136 _seedBytes[2], |
145 var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff; | 137 _seedBytes[3], |
146 | 138 _seedBytes[4], |
147 // Previous uuid creation time | 139 _seedBytes[5] |
148 var _lastMSecs = 0, | 140 ]; |
149 _lastNSecs = 0; | 141 |
150 | 142 // Per 4.2.2, randomize (14 bit) clockseq |
151 // See https://github.com/broofa/node-uuid for API details | 143 var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff; |
152 function v1(options, buf, offset) { | 144 |
153 var i = buf && offset || 0; | 145 // Previous uuid creation time |
154 var b = buf || []; | 146 var _lastMSecs = 0, |
155 | 147 _lastNSecs = 0; |
156 options = options || {}; | 148 |
157 | 149 // See https://github.com/broofa/node-uuid for API details |
158 var clockseq = (options.clockseq != null) ? options.clockseq : _clockseq; | 150 function v1(options, buf, offset) { |
159 | 151 var i = buf && offset || 0; |
160 // UUID timestamps are 100 nano-second units since the Gregorian | 152 var b = buf || []; |
161 // epoch, | 153 |
162 // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so | 154 options = options || {}; |
163 // time is handled internally as 'msecs' (integer milliseconds) and | 155 |
164 // 'nsecs' | 156 var clockseq = (options.clockseq != null) ? options.clockseq : _clockseq; |
165 // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 | 157 |
166 // 00:00. | 158 // UUID timestamps are 100 nano-second units since the Gregorian |
167 var msecs = (options.msecs != null) ? options.msecs : new Date() | 159 // epoch, |
168 .getTime(); | 160 // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so |
169 | 161 // time is handled internally as 'msecs' (integer milliseconds) and |
170 // Per 4.2.1.2, use count of uuid's generated during the current | 162 // 'nsecs' |
171 // clock | 163 // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 |
172 // cycle to simulate higher resolution clock | 164 // 00:00. |
173 var nsecs = (options.nsecs != null) ? options.nsecs : _lastNSecs + 1; | 165 var msecs = (options.msecs != null) ? options.msecs : new Date() |
174 | 166 .getTime(); |
175 // Time since last uuid creation (in msecs) | 167 |
176 var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs) / 10000; | 168 // Per 4.2.1.2, use count of uuid's generated during the current |
177 | 169 // clock |
178 // Per 4.2.1.2, Bump clockseq on clock regression | 170 // cycle to simulate higher resolution clock |
179 if (dt < 0 && options.clockseq == null) { | 171 var nsecs = (options.nsecs != null) ? options.nsecs : _lastNSecs + 1; |
180 clockseq = clockseq + 1 & 0x3fff; | 172 |
173 // Time since last uuid creation (in msecs) | |
174 var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs) / 10000; | |
175 | |
176 // Per 4.2.1.2, Bump clockseq on clock regression | |
177 if (dt < 0 && options.clockseq == null) { | |
178 clockseq = clockseq + 1 & 0x3fff; | |
179 } | |
180 | |
181 // Reset nsecs if clock regresses (new clockseq) or we've moved onto | |
182 // a new | |
183 // time interval | |
184 if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) { | |
185 nsecs = 0; | |
186 } | |
187 | |
188 // Per 4.2.1.2 Throw error if too many uuids are requested | |
189 if (nsecs >= 10000) { | |
190 throw new Error( | |
191 'uuid.v1(): Can\'t create more than 10M uuids/sec'); | |
192 } | |
193 | |
194 _lastMSecs = msecs; | |
195 _lastNSecs = nsecs; | |
196 _clockseq = clockseq; | |
197 | |
198 // Per 4.1.4 - Convert from unix epoch to Gregorian epoch | |
199 msecs += 12219292800000; | |
200 | |
201 // `time_low` | |
202 var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000; | |
203 b[i++] = tl >>> 24 & 0xff; | |
204 b[i++] = tl >>> 16 & 0xff; | |
205 b[i++] = tl >>> 8 & 0xff; | |
206 b[i++] = tl & 0xff; | |
207 | |
208 // `time_mid` | |
209 var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff; | |
210 b[i++] = tmh >>> 8 & 0xff; | |
211 b[i++] = tmh & 0xff; | |
212 | |
213 // `time_high_and_version` | |
214 b[i++] = tmh >>> 24 & 0xf | 0x10; // include version | |
215 b[i++] = tmh >>> 16 & 0xff; | |
216 | |
217 // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant) | |
218 b[i++] = clockseq >>> 8 | 0x80; | |
219 | |
220 // `clock_seq_low` | |
221 b[i++] = clockseq & 0xff; | |
222 | |
223 // `node` | |
224 var node = options.node || _nodeId; | |
225 for (var n = 0; n < 6; n++) { | |
226 b[i + n] = node[n]; | |
227 } | |
228 | |
229 return buf ? buf : unparse(b); | |
230 } | |
231 | |
232 // **`v4()` - Generate random UUID** | |
233 | |
234 // See https://github.com/broofa/node-uuid for API details | |
235 function v4(options, buf, offset) { | |
236 // Deprecated - 'format' argument, as supported in v1.2 | |
237 var i = buf && offset || 0; | |
238 | |
239 if (typeof (options) === 'string') { | |
240 buf = (options === 'binary') ? new BufferClass(16) : null; | |
241 options = null; | |
242 } | |
243 options = options || {}; | |
244 | |
245 var rnds = options.random || (options.rng || _rng)(); | |
246 | |
247 // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` | |
248 rnds[6] = (rnds[6] & 0x0f) | 0x40; | |
249 rnds[8] = (rnds[8] & 0x3f) | 0x80; | |
250 | |
251 // Copy bytes to buffer, if provided | |
252 if (buf) { | |
253 for (var ii = 0; ii < 16; ii++) { | |
254 buf[i + ii] = rnds[ii]; | |
181 } | 255 } |
182 | 256 } |
183 // Reset nsecs if clock regresses (new clockseq) or we've moved onto | 257 |
184 // a new | 258 return buf || unparse(rnds); |
185 // time interval | 259 } |
186 if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) { | 260 |
187 nsecs = 0; | 261 // Export public API |
188 } | 262 var uuid = function () { |
189 | 263 return new String(v4()); |
190 // Per 4.2.1.2 Throw error if too many uuids are requested | 264 }; |
191 if (nsecs >= 10000) { | 265 uuid.v1 = v1; |
192 throw new Error( | 266 uuid.v4 = v4; |
193 'uuid.v1(): Can\'t create more than 10M uuids/sec'); | 267 uuid.create = v4; |
194 } | 268 uuid.empty = "00000000-0000-0000-0000-000000000000"; |
195 | 269 uuid.parse = parse; |
196 _lastMSecs = msecs; | 270 uuid.unparse = unparse; |
197 _lastNSecs = nsecs; | 271 uuid.BufferClass = BufferClass; |
198 _clockseq = clockseq; | 272 uuid._rng = _rng; |
199 | 273 uuid._mathRNG = _mathRNG; |
200 // Per 4.1.4 - Convert from unix epoch to Gregorian epoch | 274 uuid._nodeRNG = _nodeRNG; |
201 msecs += 12219292800000; | 275 uuid._whatwgRNG = _whatwgRNG; |
202 | 276 |
203 // `time_low` | 277 return uuid; |
204 var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000; | 278 }); |
205 b[i++] = tl >>> 24 & 0xff; | |
206 b[i++] = tl >>> 16 & 0xff; | |
207 b[i++] = tl >>> 8 & 0xff; | |
208 b[i++] = tl & 0xff; | |
209 | |
210 // `time_mid` | |
211 var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff; | |
212 b[i++] = tmh >>> 8 & 0xff; | |
213 b[i++] = tmh & 0xff; | |
214 | |
215 // `time_high_and_version` | |
216 b[i++] = tmh >>> 24 & 0xf | 0x10; // include version | |
217 b[i++] = tmh >>> 16 & 0xff; | |
218 | |
219 // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant) | |
220 b[i++] = clockseq >>> 8 | 0x80; | |
221 | |
222 // `clock_seq_low` | |
223 b[i++] = clockseq & 0xff; | |
224 | |
225 // `node` | |
226 var node = options.node || _nodeId; | |
227 for (var n = 0; n < 6; n++) { | |
228 b[i + n] = node[n]; | |
229 } | |
230 | |
231 return buf ? buf : unparse(b); | |
232 } | |
233 | |
234 // **`v4()` - Generate random UUID** | |
235 | |
236 // See https://github.com/broofa/node-uuid for API details | |
237 function v4(options, buf, offset) { | |
238 // Deprecated - 'format' argument, as supported in v1.2 | |
239 var i = buf && offset || 0; | |
240 | |
241 if (typeof (options) === 'string') { | |
242 buf = (options === 'binary') ? new BufferClass(16) : null; | |
243 options = null; | |
244 } | |
245 options = options || {}; | |
246 | |
247 var rnds = options.random || (options.rng || _rng)(); | |
248 | |
249 // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` | |
250 rnds[6] = (rnds[6] & 0x0f) | 0x40; | |
251 rnds[8] = (rnds[8] & 0x3f) | 0x80; | |
252 | |
253 // Copy bytes to buffer, if provided | |
254 if (buf) { | |
255 for (var ii = 0; ii < 16; ii++) { | |
256 buf[i + ii] = rnds[ii]; | |
257 } | |
258 } | |
259 | |
260 return buf || unparse(rnds); | |
261 } | |
262 | |
263 // Export public API | |
264 var uuid = function () { | |
265 return new String(v4()); | |
266 }; | |
267 uuid.v1 = v1; | |
268 uuid.v4 = v4; | |
269 uuid.create = v4; | |
270 uuid.empty = "00000000-0000-0000-0000-000000000000"; | |
271 uuid.parse = parse; | |
272 uuid.unparse = unparse; | |
273 uuid.BufferClass = BufferClass; | |
274 uuid._rng = _rng; | |
275 uuid._mathRNG = _mathRNG; | |
276 uuid._nodeRNG = _nodeRNG; | |
277 uuid._whatwgRNG = _whatwgRNG; | |
278 | |
279 return uuid; | |
280 }); |