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 }); | 
