Mercurial > pub > ImplabJs
comparison src/implab/Uuid.js @ 0:fc2517695ee1
Initial commit, draft import of existing work
| author | cin |
|---|---|
| date | Thu, 01 Jun 2017 13:20:03 +0300 |
| parents | |
| children | 93fb6c09f2e1 |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:fc2517695ee1 |
|---|---|
| 1 // uuid.js | |
| 2 // | |
| 3 // Copyright (c) 2010-2012 Robert Kieffer | |
| 4 // MIT License - http://opensource.org/licenses/mit-license.php | |
| 5 define( | |
| 6 [], | |
| 7 function () { | |
| 8 'use strict'; | |
| 9 | |
| 10 var _window = 'undefined' !== typeof window ? window : null; | |
| 11 | |
| 12 // Unique ID creation requires a high quality random # generator. We | |
| 13 // feature | |
| 14 // detect to determine the best RNG source, normalizing to a function | |
| 15 // that | |
| 16 // returns 128-bits of randomness, since that's what's usually required | |
| 17 var _rng, _mathRNG, _nodeRNG, _whatwgRNG, _previousRoot; | |
| 18 | |
| 19 function setupBrowser() { | |
| 20 // Allow for MSIE11 msCrypto | |
| 21 var _crypto = _window.crypto || _window.msCrypto; | |
| 22 | |
| 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 // | |
| 65 // Moderately fast, high quality | |
| 66 if ('function' === typeof require) { | |
| 67 try { | |
| 68 var _rb = require('crypto').randomBytes; | |
| 69 _nodeRNG = _rng = _rb && function () { | |
| 70 return _rb(16); | |
| 71 }; | |
| 72 _rng(); | |
| 73 } catch (e) {} | |
| 74 } | |
| 75 } | |
| 76 | |
| 77 if (_window) { | |
| 78 setupBrowser(); | |
| 79 } else { | |
| 80 setupNode(); | |
| 81 } | |
| 82 | |
| 83 // Buffer class to use | |
| 84 var BufferClass = ('function' === typeof Buffer) ? Buffer : Array; | |
| 85 | |
| 86 // Maps for number <-> hex string conversion | |
| 87 var _byteToHex = []; | |
| 88 var _hexToByte = {}; | |
| 89 for (var i = 0; i < 256; i++) { | |
| 90 _byteToHex[i] = (i + 0x100).toString(16).substr(1); | |
| 91 _hexToByte[_byteToHex[i]] = i; | |
| 92 } | |
| 93 | |
| 94 // **`parse()` - Parse a UUID into it's component bytes** | |
| 95 function parse(s, buf, offset) { | |
| 96 var i = (buf && offset) || 0, | |
| 97 ii = 0; | |
| 98 | |
| 99 buf = buf || []; | |
| 100 s.toLowerCase().replace(/[0-9a-f]{2}/g, function (oct) { | |
| 101 if (ii < 16) { // Don't overflow! | |
| 102 buf[i + ii++] = _hexToByte[oct]; | |
| 103 } | |
| 104 }); | |
| 105 | |
| 106 // Zero out remaining bytes if string was short | |
| 107 while (ii < 16) { | |
| 108 buf[i + ii++] = 0; | |
| 109 } | |
| 110 | |
| 111 return buf; | |
| 112 } | |
| 113 | |
| 114 // **`unparse()` - Convert UUID byte array (ala parse()) into a string** | |
| 115 function unparse(buf, offset) { | |
| 116 var i = offset || 0, | |
| 117 bth = _byteToHex; | |
| 118 return bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + | |
| 119 bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + '-' + | |
| 120 bth[buf[i++]] + bth[buf[i++]] + '-' + bth[buf[i++]] + | |
| 121 bth[buf[i++]] + '-' + bth[buf[i++]] + bth[buf[i++]] + | |
| 122 bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]] + bth[buf[i++]]; | |
| 123 } | |
| 124 | |
| 125 // **`v1()` - Generate time-based UUID** | |
| 126 // | |
| 127 // Inspired by https://github.com/LiosK/UUID.js | |
| 128 // and http://docs.python.org/library/uuid.html | |
| 129 | |
| 130 // random #'s we need to init node and clockseq | |
| 131 var _seedBytes = _rng(); | |
| 132 | |
| 133 // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = | |
| 134 // 1) | |
| 135 var _nodeId = [ | |
| 136 _seedBytes[0] | 0x01, | |
| 137 _seedBytes[1], | |
| 138 _seedBytes[2], | |
| 139 _seedBytes[3], | |
| 140 _seedBytes[4], | |
| 141 _seedBytes[5] | |
| 142 ]; | |
| 143 | |
| 144 // Per 4.2.2, randomize (14 bit) clockseq | |
| 145 var _clockseq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff; | |
| 146 | |
| 147 // Previous uuid creation time | |
| 148 var _lastMSecs = 0, | |
| 149 _lastNSecs = 0; | |
| 150 | |
| 151 // See https://github.com/broofa/node-uuid for API details | |
| 152 function v1(options, buf, offset) { | |
| 153 var i = buf && offset || 0; | |
| 154 var b = buf || []; | |
| 155 | |
| 156 options = options || {}; | |
| 157 | |
| 158 var clockseq = (options.clockseq != null) ? options.clockseq : _clockseq; | |
| 159 | |
| 160 // UUID timestamps are 100 nano-second units since the Gregorian | |
| 161 // epoch, | |
| 162 // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so | |
| 163 // time is handled internally as 'msecs' (integer milliseconds) and | |
| 164 // 'nsecs' | |
| 165 // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 | |
| 166 // 00:00. | |
| 167 var msecs = (options.msecs != null) ? options.msecs : new Date() | |
| 168 .getTime(); | |
| 169 | |
| 170 // Per 4.2.1.2, use count of uuid's generated during the current | |
| 171 // clock | |
| 172 // cycle to simulate higher resolution clock | |
| 173 var nsecs = (options.nsecs != null) ? options.nsecs : _lastNSecs + 1; | |
| 174 | |
| 175 // Time since last uuid creation (in msecs) | |
| 176 var dt = (msecs - _lastMSecs) + (nsecs - _lastNSecs) / 10000; | |
| 177 | |
| 178 // Per 4.2.1.2, Bump clockseq on clock regression | |
| 179 if (dt < 0 && options.clockseq == null) { | |
| 180 clockseq = clockseq + 1 & 0x3fff; | |
| 181 } | |
| 182 | |
| 183 // Reset nsecs if clock regresses (new clockseq) or we've moved onto | |
| 184 // a new | |
| 185 // time interval | |
| 186 if ((dt < 0 || msecs > _lastMSecs) && options.nsecs == null) { | |
| 187 nsecs = 0; | |
| 188 } | |
| 189 | |
| 190 // Per 4.2.1.2 Throw error if too many uuids are requested | |
| 191 if (nsecs >= 10000) { | |
| 192 throw new Error( | |
| 193 'uuid.v1(): Can\'t create more than 10M uuids/sec'); | |
| 194 } | |
| 195 | |
| 196 _lastMSecs = msecs; | |
| 197 _lastNSecs = nsecs; | |
| 198 _clockseq = clockseq; | |
| 199 | |
| 200 // Per 4.1.4 - Convert from unix epoch to Gregorian epoch | |
| 201 msecs += 12219292800000; | |
| 202 | |
| 203 // `time_low` | |
| 204 var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000; | |
| 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 }); |
