Comparing version 1.2.0 to 1.3.0
{ | ||
"name" : "node-uuid", | ||
"description" : "Simple, fast generation of RFC4122 (v1 and v4) UUIDs.", | ||
"description" : "Rigorous implementation of RFC4122 (v1 and v4) UUIDs.", | ||
"url" : "http://github.com/broofa/node-uuid", | ||
@@ -13,3 +13,3 @@ "keywords" : ["uuid", "guid", "rfc4122"], | ||
"main" : "./uuid.js", | ||
"version" : "1.2.0" | ||
"version" : "1.3.0" | ||
} |
256
README.md
# node-uuid | ||
Simple, fast generation of [RFC4122 (v1 and v4)](http://www.ietf.org/rfc/rfc4122.txt) UUIDS. It runs in node.js and all major browsers. | ||
Simple, fast generation of [RFC4122](http://www.ietf.org/rfc/rfc4122.txt) UUIDS. | ||
## Installation | ||
Features: | ||
npm install node-uuid | ||
* Generate RFC4122 version 1 or version 4 UUIDs | ||
* Runs in node.js and all browsers. | ||
* Cryptographically strong random # generation on supporting platforms | ||
* 1.1K minified and gzip'ed | ||
### In browser | ||
## Getting Started | ||
Install it in your browser: | ||
```html | ||
@@ -15,170 +20,177 @@ <script src="uuid.js"></script> | ||
### In node.js | ||
Or in node.js: | ||
``` | ||
npm install node-uuid | ||
``` | ||
```javascript | ||
var uuid = require('node-uuid'); | ||
uuid.v1(); // -> v1 uuid | ||
uuid.v4(); // -> v4 uuid | ||
``` | ||
// ... or if you just need to generate uuids of one type and don't need helpers ... | ||
var uuid = require('node-uuid').v1; | ||
uuid(); // -> v1 uuid | ||
Then create some ids ... | ||
// ... or ... | ||
var uuid = require('node-uuid').v4; | ||
uuid(); // -> v4 uuid | ||
```javascript | ||
// Generate a v1 (time-based) id | ||
uuid.v1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a' | ||
// Generate a v4 (random) id | ||
uuid.v4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1' | ||
``` | ||
## Usage | ||
## API | ||
### Generate a String UUID | ||
### uuid.v1([`options` [, `buffer` [, `offset`]]]) | ||
Generate and return a RFC4122 v1 (timestamp-based) UUID. | ||
* `options` - (Object) Optional uuid state to apply. Properties may include: | ||
* `node` - (Array) Node id as Array of 6 bytes (per 4.1.6). Default: Randomnly generated ID. See note 1. | ||
* `clockseq` - (Number between 0 - 0x3fff) RFC clock sequence. Default: An internally maintained clockseq is used. | ||
* `msecs` - (Number | Date) Time in milliseconds since unix Epoch. Default: The current time is used. See note 2. | ||
* `nsecs` - (Number between 0-9999) additional time, in 100-nanosecond. Ignored if `msecs` is unspecified. Default: internal uuid counter is used, as per 4.2.1.2. | ||
* `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written. | ||
* `offset` - (Number) Starting index in `buffer` at which to begin writing. | ||
Returns `buffer`, if specified, otherwise the string form of the UUID | ||
Notes: | ||
1. The randomly generated node id is only guaranteed to stay constant for the lifetime of the current JS runtime. (Future versions of this module may use persistent storage mechanisms to extend this guarantee.) | ||
1. Specifying the `msecs` option bypasses the internal logic for ensuring id uniqueness. In this case you may want to also provide `clockseq` and `nsecs` options as well. | ||
Example: Generate string UUID with fully-specified options | ||
```javascript | ||
var id = uuid.v4([options, [buffer, [offset]]]); // -> '92329d39-6f5c-4520-abfc-aab64544e172' | ||
uuid.v1({ | ||
node: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab], | ||
clockseq: 0x1234, | ||
msecs: new Date('2011-11-01').getTime(), | ||
nsecs: 5678 | ||
}); // -> "710b962e-041c-11e1-9234-0123456789ab" | ||
``` | ||
### Generate a Binary UUID | ||
Example: In-place generation of two binary IDs | ||
```javascript | ||
// Simple form - allocates a Buffer/Array for you | ||
var buffer = uuid.v4('binary'); | ||
// node.js -> <Buffer 08 50 05 c8 9c b2 4c 07 ac 07 d1 4f b9 f5 04 51> | ||
// browser -> [8, 80, 5, 200, 156, 178, 76, 7, 172, 7, 209, 79, 185, 245, 4, 81] | ||
// Generate two ids in an array | ||
var arr = new Array(32); // -> [] | ||
uuid.v1(null, arr, 0); // -> [02 a2 ce 90 14 32 11 e1 85 58 0b 48 8e 4f c1 15] | ||
uuid.v1(null, arr, 16); // -> [02 a2 ce 90 14 32 11 e1 85 58 0b 48 8e 4f c1 15 02 a3 1c b0 14 32 11 e1 85 58 0b 48 8e 4f c1 15] | ||
// Provide your own Buffer or Array | ||
var buffer = new Array(16); | ||
uuid.v4('binary', buffer); // -> [8, 80, 5, 200, 156, 178, 76, 7, 172, 7, 209, 79, 185, 245, 4, 81] | ||
var buffer = new Buffer(16); | ||
uuid.v4('binary', buffer); // -> <Buffer 08 50 05 c8 9c b2 4c 07 ac 07 d1 4f b9 f5 04 51> | ||
// Optionally use uuid.unparse() to get stringify the ids | ||
uuid.unparse(buffer); // -> '02a2ce90-1432-11e1-8558-0b488e4fc115' | ||
uuid.unparse(buffer, 16) // -> '02a31cb0-1432-11e1-8558-0b488e4fc115' | ||
``` | ||
// Let node-uuid decide whether to use Buffer or Array | ||
var buffer = new uuid.BufferClass(16); | ||
uuid.v4('binary', buffer); // -> see above, depending on the environment | ||
### uuid.v4([`options` [, `buffer` [, `offset`]]]) | ||
// Provide your own Buffer/Array, plus specify offset | ||
// (e.g. here we fill an array with 3 uuids) | ||
var buffer = new Buffer(16 * 3); | ||
uuid.v4('binary', buffer, 0); | ||
uuid.v4('binary', buffer, 16); | ||
uuid.v4('binary', buffer, 32); | ||
``` | ||
Generate and return a RFC4122 v4 UUID. | ||
### Options | ||
* `options` - (Object) Optional uuid state to apply. Properties may include: | ||
There are several options that can be passed to `v1()` and `v4()`: | ||
* `random` - (Number[16]) Array of 16 numbers (0-255) to use in place of randomly generated values | ||
* `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written. | ||
* `offset` - (Number) Starting index in `buffer` at which to begin writing. | ||
Returns `buffer`, if specified, otherwise the string form of the UUID | ||
Example: Generate string UUID with fully-specified options | ||
```javascript | ||
var options = { | ||
format: (String), // (v1/v4) 'binary' or 'string' | ||
random: (Array), // (v1/v4) array of four 32bit random #'s to use instead of rnds | ||
time: (Number), // (v1) timestamp to use (in UNIX epoch, in msec) | ||
timesubms: (Number), // (v1) number of 100ns intervals since msec time | ||
clockseq: (Number), // (v1) clockseq to use | ||
node: (Array) // (v1) node. Array of hexoctets, e.g. a MAC-address | ||
}; | ||
uuid.v4({ | ||
random: [ | ||
0x10, 0x91, 0x56, 0xbe, 0xc4, 0xfb, 0xc1, 0xea, | ||
0x71, 0xb4, 0xef, 0xe1, 0x67, 0x1c, 0x58, 0x36 | ||
] | ||
}); | ||
// -> "109156be-c4fb-41ea-b1b4-efe1671c5836" | ||
``` | ||
If `options` is a string it is interpreted as the `format` option. | ||
Example: Generate two IDs in a single buffer | ||
Using the `options` parameter you can get the UUIDs that would sort first and last for a given millisecond timestamp. | ||
This is useful whenever you need to find UUIDs that have been generated during a certain timespan. | ||
```javascript | ||
var buffer = new Array(32); // (or 'new Buffer' in node.js) | ||
uuid.v4(null, buffer, 0); | ||
uuid.v4(null, buffer, 16); | ||
``` | ||
### uuid.parse(id[, buffer[, offset]]) | ||
### uuid.unparse(buffer[, offset]) | ||
Parse and unparse UUIDs | ||
* `id` - (String) UUID(-like) string | ||
* `buffer` - (Array | Buffer) Array or buffer where UUID bytes are to be written. Default: A new Array or Buffer is used | ||
* `offset` - (Number) Starting index in `buffer` at which to begin writing. Default: 0 | ||
Example parsing and unparsing a UUID string | ||
```javascript | ||
var now = new Date().getTime(); | ||
var first = uuid.v1({ | ||
time: now, | ||
timesubms: 0, | ||
clockseq: 0, | ||
node: [0, 0, 0, 0, 0, 0] | ||
}); | ||
var last = uuid.v1({ | ||
time: now, | ||
timesubms: 9999, | ||
clockseq: 0x3fff, // 14bit | ||
node: [0xff, 0xff, 0xff, 0xff, 0xff, 0xff] | ||
}); | ||
// first: 038ee0a0-11df-11e1-8000-000000000000 | ||
// last: 038f07af-11df-11e1-bfff-ffffffffffff | ||
var bytes = uuid.parse('797ff043-11eb-11e1-80d6-510998755d10'); // -> <Buffer 79 7f f0 43 11 eb 11 e1 80 d6 51 09 98 75 5d 10> | ||
var string = uuid.unparse(bytes); // -> '797ff043-11eb-11e1-80d6-510998755d10' | ||
``` | ||
### Helpers | ||
### uuid.noConflict() | ||
node-uuid provides helper-functions for converting UUIDs between buffer/array and string representations: | ||
(Browsers only) Set `uuid` property back to it's previous value. | ||
Returns the node-uuid object. | ||
Example: | ||
```javascript | ||
var binary = uuid.parse('797ff043-11eb-11e1-80d6-510998755d10'); | ||
// -> <Buffer 79 7f f0 43 11 eb 11 e1 80 d6 51 09 98 75 5d 10> | ||
var string = uuid.unparse(binary); | ||
// -> '797ff043-11eb-11e1-80d6-510998755d10' | ||
var myUuid = uuid.noConflict(); | ||
myUuid.v1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a' | ||
``` | ||
## Deprecated APIs | ||
## Testing | ||
Support for the following v1.2 APIs is available in v1.3, but is deprecated and will be removed in the next major version. | ||
test/test.js generates performance data (similar to test/benchmark.js). It also verifies the syntax of 100K string UUIDs, and logs the distribution of hex digits found therein. For example: | ||
### uuid([format [, buffer [, offset]]]) | ||
- - - Performance Data - - - | ||
uuid.v4(): 1470588 uuids/second | ||
uuid.v4('binary'): 1041666 uuids/second | ||
uuid.v4('binary', buffer): 3125000 uuids/second | ||
uuid.v1(): 869565 uuids/second | ||
uuid.v1('binary'): 625000 uuids/second | ||
uuid.v1('binary', buffer): 1123595 uuids/second | ||
uuid() has become uuid.v4(), and the `format` argument is now implicit in the `buffer` argument. (i.e. if you specify a buffer, the format is assumed to be binary). | ||
- - - Distribution of Hex Digits (% deviation from ideal) - - - | ||
0 |================================| 187378 (-0.07%) | ||
1 |================================| 186972 (-0.28%) | ||
2 |================================| 187274 (-0.12%) | ||
3 |================================| 187392 (-0.06%) | ||
4 |==================================================| 286998 (-0.17%) | ||
5 |================================| 187525 (0.01%) | ||
6 |================================| 188019 (0.28%) | ||
7 |================================| 187541 (0.02%) | ||
8 |=====================================| 212941 (0.21%) | ||
9 |====================================| 212308 (-0.09%) | ||
a |====================================| 211923 (-0.27%) | ||
b |=====================================| 212605 (0.05%) | ||
c |================================| 187608 (0.06%) | ||
d |================================| 188473 (0.52%) | ||
e |================================| 187547 (0.03%) | ||
f |================================| 187496 (0%) | ||
### uuid.BufferClass | ||
Note that the increased values for 4 and 8-B are expected as part of the RFC4122 syntax (and are accounted for in the deviation calculation). BTW, if someone wants to do the calculation to determine what a statistically significant deviation would be, I'll gladly add that to the test. | ||
The class of container created when generating binary uuid data if no buffer argument is specified. This is expected to go away, with no replacement API. | ||
### In browser | ||
## Testing | ||
Open test/test.html | ||
In node.js | ||
### In node.js | ||
``` | ||
> cd test | ||
> node uuid.js | ||
``` | ||
node test/test.js | ||
In Browser | ||
node.js users can also run the node-uuid vs. uuid vs. uuid-js benchmark: | ||
``` | ||
open test/test.html | ||
``` | ||
npm install uuid uuid-js | ||
node test/benchmark.js | ||
### Benchmarking | ||
## Performance | ||
Requires node.js | ||
### In node.js | ||
``` | ||
npm install uuid uuid-js | ||
node test/benchmark.js | ||
``` | ||
node-uuid is designed to be fast. That said, the target platform is node.js, where it is screaming fast. Here's what I get on an Intel Core i7 950 @ 3.07GHz for the test/benchmark.js script: | ||
For a more complete discussion of node-uuid performance, please see the `benchmark/README.md` file, and the [benchmark wiki](https://github.com/broofa/node-uuid/wiki/Benchmark) | ||
# v4 | ||
nodeuuid.v4(): 1577287 uuids/second | ||
nodeuuid.v4('binary'): 1033057 uuids/second | ||
nodeuuid.v4('binary', buffer): 3012048 uuids/second | ||
uuid(): 266808 uuids/second | ||
uuid('binary'): 302480 uuids/second | ||
uuidjs.create(4): 360750 uuids/second | ||
# v1 | ||
nodeuuid.v1(): 905797 uuids/second | ||
nodeuuid.v1('binary'): 557413 uuids/second | ||
nodeuuid.v1('binary', buffer): 1240694 uuids/second | ||
uuidjs.create(1): 201369 uuids/second | ||
For browser performance [checkout the JSPerf tests](http://jsperf.com/node-uuid-performance). | ||
The uuid() entries are for Nikhil Marathe's [uuid module](https://bitbucket.org/nikhilm/uuidjs), the uuidjs() entries are for Patrick Negri's [uuid-js module](https://github.com/pnegri/uuid-js), and they are provided for comparison. uuid is a wrapper around the native libuuid library, uuid-js is a pure javascript implementation based on [UUID.js](https://github.com/LiosK/UUID.js) by LiosK. | ||
## Release notes | ||
### In browser | ||
v1.3: Includes | ||
node-uuid performance varies dramatically across browsers. For comprehensive test results, please [checkout the JSPerf tests](http://jsperf.com/node-uuid-performance). | ||
* Support for version 1 ids, thanks to [@ctavan](https://github.com/ctavan)! | ||
* Support for node.js crypto API | ||
* De-emphasizing performance in favor of a) cryptographic quality PRNGs where available and b) more manageable code |
152
test/test.js
if (!this.uuid) { | ||
// node.js | ||
uuid = require('../uuid'); | ||
} | ||
var N = 1e5; | ||
// | ||
// x-platform log/assert shims | ||
// | ||
function log(msg) { | ||
function _log(msg, type) { | ||
type = type || 'log'; | ||
if (typeof(document) != 'undefined') { | ||
document.write('<div>' + msg.replace(/\n/g, '<br />') + '</div>'); | ||
document.write('<div class="' + type + '">' + msg.replace(/\n/g, '<br />') + '</div>'); | ||
} | ||
if (typeof(console) != 'undefined') { | ||
console.log(msg); | ||
console[type](msg); | ||
} | ||
} | ||
// Get %'age an actual value differs from the ideal value | ||
function divergence(actual, ideal) { | ||
return Math.round(100*100*(actual - ideal)/ideal)/100; | ||
function log(msg) {_log(msg, 'log');} | ||
function warn(msg) {_log(msg, 'warn');} | ||
function error(msg) {_log(msg, 'error');} | ||
function assert(res, msg) { | ||
if (!res) { | ||
error('Fail: ' + msg); | ||
} else { | ||
log('Pass: ' + msg); | ||
} | ||
} | ||
function rate(msg, t) { | ||
log(msg + ': ' + (N / (Date.now() - t) * 1e3 | 0) + ' uuids/second'); | ||
// | ||
// Unit tests | ||
// | ||
function compare(name, ids) { | ||
ids = ids.map(function(id) { | ||
return id.split('-').reverse().join('-'); | ||
}).sort(); | ||
var sorted = ([].concat(ids)).sort(); | ||
assert(sorted.toString() == ids.toString(), name + ' have expected order'); | ||
} | ||
// Verify ordering of v1 ids created using default behavior | ||
compare('uuids with current time', [ | ||
uuid.v1(), | ||
uuid.v1(), | ||
uuid.v1(), | ||
uuid.v1(), | ||
uuid.v1() | ||
]); | ||
// Verify ordering of v1 ids created with explicit times | ||
var t = 1321644961388; // "Fri Nov 18 2011 11:36:01.388 GMT-0800 (PST)" | ||
compare('uuids with time option', [ | ||
uuid.v1({msecs: t - 10*3600*1000}), | ||
uuid.v1({msecs: t - 1}), | ||
uuid.v1({msecs: t}), | ||
uuid.v1({msecs: t + 1}), | ||
uuid.v1({msecs: t + 28*24*3600*1000}), | ||
]); | ||
var id = uuid.v1({ | ||
msecs: 1321651533573, | ||
nsecs: 5432, | ||
clockseq: 0x385c, | ||
node: [ 0x61, 0xcd, 0x3c, 0xbb, 0x32, 0x10 ] | ||
}); | ||
assert(id == 'd9428888-122b-11e1-b85c-61cd3cbb3210', 'Explicit options produce expected id'); | ||
// Check that there is exactly 1 tick between lastUUID and firstUUID of the | ||
// next millisecond interval (this test is sloppy since it fails if time_mid | ||
// or time_hi change when we changed the time by one ms. If we want to include | ||
// that case, we cannot use parseInt() since our integers become | ||
// > 32bit): | ||
var u0 = uuid.v1({msecs: t, nsecs: 9999}); | ||
var u1 = uuid.v1({msecs: t + 1}); | ||
var before = u0.split('-')[0], after = u1.split('-')[0]; | ||
var dt = parseInt(after, 16) - parseInt(before, 16); | ||
assert(dt === 1, '1ns separation between adjacent uuids'); | ||
// | ||
// Per tests | ||
// | ||
var generators = { | ||
@@ -35,25 +99,11 @@ v1: uuid.v1, | ||
// Test time order of v1 uuids | ||
var ids = []; | ||
while (ids.length < 1e4) ids.push(uuid.v1()); | ||
var sorted = ([].concat(ids)).sort(); | ||
if (sorted.toString() !== ids.toString()) { | ||
log('Sort order of 10000 v1 uuids was incorrect!'); | ||
var N = 1e4; | ||
// Get %'age an actual value differs from the ideal value | ||
function divergence(actual, ideal) { | ||
return Math.round(100*100*(actual - ideal)/ideal)/100; | ||
} | ||
// Perf tests | ||
log('- - - Performance Data - - -'); | ||
for (var version in generators) { | ||
log('\n' + version + ' UUIDs'); | ||
var generator = generators[version]; | ||
var buf = new uuid.BufferClass(16); | ||
for (var i = 0, t = Date.now(); i < N; i++) generator(); | ||
rate('uuid.' + version + '()', t); | ||
for (var i = 0, t = Date.now(); i < N; i++) generator('binary'); | ||
rate('uuid.' + version + '(\'binary\')', t); | ||
for (var i = 0, t = Date.now(); i < N; i++) generator('binary', buf); | ||
rate('uuid.' + version + '(\'binary\', buffer)', t); | ||
function rate(msg, t) { | ||
log(msg + ': ' + (N / (Date.now() - t) * 1e3 | 0) + ' uuids\/second'); | ||
} | ||
@@ -66,4 +116,4 @@ | ||
log('- - - Checking ' + N + ' ' + version + ' uuids - - -'); | ||
for (var i = 0; i < N; i++) { | ||
log('\nSanity check ' + N + ' ' + version + ' uuids'); | ||
for (var i = 0, ok = 0; i < N; i++) { | ||
id = generator(); | ||
@@ -75,18 +125,21 @@ if (!format.test(id)) { | ||
if (id != uuid.unparse(uuid.parse(id))) { | ||
throw Error(id + ' does not parse/unparse'); | ||
assert(fail, id + ' is not a valid id'); | ||
} | ||
// Count digits for our randomness check | ||
var digits = id.replace(/-/g, '').split(''); | ||
for (var j = digits.length-1; j >= 0; j--) { | ||
var c = digits[j]; | ||
max = Math.max(max, counts[c] = (counts[c] || 0) + 1); | ||
if (version == 'v4') { | ||
var digits = id.replace(/-/g, '').split(''); | ||
for (var j = digits.length-1; j >= 0; j--) { | ||
var c = digits[j]; | ||
max = Math.max(max, counts[c] = (counts[c] || 0) + 1); | ||
} | ||
} | ||
} | ||
// Only check randomness for v4 UUIDs | ||
// Check randomness for v4 UUIDs | ||
if (version == 'v4') { | ||
log('\nv4 PRNG quality check: Distribution of Hex Digits (% deviation from ideal) - - -'); | ||
// Pick (empirically chosen) limit that we get worried about randomness. | ||
var limit = 2*100*Math.sqrt(1/N); // (Purely empirical choice, this!) | ||
log('\nChecking v4 randomness. Distribution of Hex Digits (% deviation from ideal)'); | ||
// Check randomness | ||
for (var i = 0; i < 16; i++) { | ||
@@ -114,5 +167,22 @@ var c = i.toString(16); | ||
log(c + ' |' + bar + '| ' + counts[c] + ' (' + d + '%)'); | ||
assert(Math.abs(d) < limit, c + ' |' + bar + '| ' + counts[c] + ' (' + d + '% < ' + limit + '%)'); | ||
} | ||
} | ||
} | ||
// Perf tests | ||
for (var version in generators) { | ||
log('\nPerformance testing ' + version + ' UUIDs'); | ||
var generator = generators[version]; | ||
var buf = new uuid.BufferClass(16); | ||
for (var i = 0, t = Date.now(); i < N; i++) generator(); | ||
rate('uuid.' + version + '()', t); | ||
for (var i = 0, t = Date.now(); i < N; i++) generator('binary'); | ||
rate('uuid.' + version + '(\'binary\')', t); | ||
for (var i = 0, t = Date.now(); i < N; i++) generator('binary', buf); | ||
rate('uuid.' + version + '(\'binary\', buffer)', t); | ||
} | ||
288
uuid.js
@@ -7,56 +7,68 @@ /* | ||
(function() { | ||
// Use WHATWG crypto api if available, otherwise shim it | ||
var _global = this; | ||
// Random number generator (feature-detected below) | ||
var _rng; | ||
// node.js 'crypto' API | ||
// http://nodejs.org/docs/v0.6.2/api/crypto.html#randomBytes | ||
try { | ||
_rng = require('crypto').randomBytes; | ||
} catch (e) {} | ||
// WHATWG crypto api, available in Chrome | ||
// http://wiki.whatwg.org/wiki/Crypto | ||
// | ||
// (Create a static _rnds array here as well, which lets us avoid per-uuid | ||
// array creation) | ||
var crypto, _rnds; | ||
if (crypto && crypto.getRandomValues) { | ||
_rnds = new Uint32Array(4); | ||
} else { | ||
_rnds = new Array(4); | ||
// Math.random does not have the cryptographic-quality guarantee for | ||
// randomness that crypto.getRandomValues has, but it's the best we have. | ||
crypto = { | ||
getRandomValues: function(arr) { | ||
for (var i = 0, l = arr.length; i < l; i++) { | ||
_rnds[i] = Math.random() * 0x100000000; | ||
} | ||
if (!_rng && _global.crypto && crypto.getRandomValues) { | ||
var _rnds = new Uint32Array(4), _rndBytes = new Array(16); | ||
var _rng = function() { | ||
// Get 32-bit rnds | ||
crypto.getRandomValues(_rnds); | ||
// Unpack into byte array | ||
for (var c = 0 ; c < 16; c++) { | ||
_rndBytes[c] = _rnds[c >> 2] >>> ((c & 0x03) * 8) & 0xff; | ||
} | ||
return _rndBytes; | ||
}; | ||
} | ||
// Use node.js Buffer class if available, otherwise use the Array class | ||
// Math.random - least desirable option since it does not guarantee | ||
// cryptographic quality. | ||
if (!_rng) { | ||
var _rndBytes = new Array(16); | ||
_rng = function() { | ||
var r, b = _rndBytes, i = 0; | ||
for (var i = 0, r; i < 16; i++) { | ||
if ((i & 0x03) == 0) r = Math.random() * 0x100000000; | ||
b[i] = r >>> ((i & 0x03) << 3) & 0xff; | ||
} | ||
return b; | ||
}; | ||
} | ||
// Buffer class to use | ||
var BufferClass = typeof(Buffer) == 'function' ? Buffer : Array; | ||
// Maps for number <-> hex string conversion | ||
var _octetToHex = []; | ||
var _hexToOctet = {}; | ||
var _byteToHex = []; | ||
var _hexToByte = {}; | ||
for (var i = 0; i < 256; i++) { | ||
_octetToHex[i] = (i + 0x100).toString(16).substr(1); | ||
_hexToOctet[_octetToHex[i]] = i; | ||
_byteToHex[i] = (i + 0x100).toString(16).substr(1); | ||
_hexToByte[_byteToHex[i]] = i; | ||
} | ||
/** | ||
* Parse a uuid string into it's component octets. | ||
* | ||
* This is a loose parser. It parses the first 16 octet pairs as hex | ||
* values. If fewer than 16 are found, any remaining entries in the array | ||
* are set to zero. | ||
* | ||
* @param s (String) string to parse. | ||
* @param buf (Array|Buffer) Optional buffer to capture parsed values in | ||
* @param offset (Number) Optional starting offset into buf | ||
*/ | ||
/** See docs at https://github.com/broofa/node-uuid */ | ||
function parse(s, buf, offset) { | ||
var buf = buf || new BufferClass(16), | ||
i = offset || 0, | ||
ii = 0; | ||
s.toLowerCase().replace(/[0-9a-f]{2}/g, function(octet) { | ||
var i = (buf && offset) || 0, ii = 0; | ||
buf = buf || []; | ||
s.toLowerCase().replace(/[0-9a-f]{2}/g, function(byte) { | ||
if (ii < 16) { // Don't overflow! | ||
buf[i + ii++] = _hexToOctet[octet]; | ||
buf[i + ii++] = _hexToByte[byte]; | ||
} | ||
}); | ||
// Zero out remaining octets if string was short | ||
// Zero out remaining bytes if string was short | ||
while (ii < 16) { | ||
@@ -69,42 +81,18 @@ buf[i + ii] = 0; | ||
/** | ||
* Generate a uuid string from octet array | ||
* | ||
* @param buf (Array|Buffer) Optional buffer to pull octets from | ||
* @param offset (Number) Optional starting offset into buf | ||
*/ | ||
/** See docs at https://github.com/broofa/node-uuid */ | ||
function unparse(buf, offset) { | ||
var oth = _octetToHex, | ||
b = buf, | ||
i = offset || 0; | ||
return oth[b[i + 0]] + oth[b[i + 1]] + | ||
oth[b[i + 2]] + oth[b[i + 3]] + '-' + | ||
oth[b[i + 4]] + oth[b[i + 5]] + '-' + | ||
oth[b[i + 6]] + oth[b[i + 7]] + '-' + | ||
oth[b[i + 8]] + oth[b[i + 9]] + '-' + | ||
oth[b[i + 10]] + oth[b[i + 11]] + | ||
oth[b[i + 12]] + oth[b[i + 13]] + | ||
oth[b[i + 14]] + oth[b[i + 15]]; | ||
var i = offset || 0, bth = _byteToHex; | ||
return bth[buf[i++]] + bth[buf[i++]] + | ||
bth[buf[i++]] + bth[buf[i++]] + '-' + | ||
bth[buf[i++]] + bth[buf[i++]] + '-' + | ||
bth[buf[i++]] + bth[buf[i++]] + '-' + | ||
bth[buf[i++]] + bth[buf[i++]] + '-' + | ||
bth[buf[i++]] + bth[buf[i++]] + | ||
bth[buf[i++]] + bth[buf[i++]] + | ||
bth[buf[i++]] + bth[buf[i++]]; | ||
} | ||
/** | ||
* Create and return octets for a 48-bit node id: | ||
* 47 bits random, 1 bit (multicast) set to 1 | ||
*/ | ||
function _randomNodeId() { | ||
crypto.getRandomValues(_rnds); | ||
// Pre allocate array for constructing uuids | ||
var _buffer = new BufferClass(16); | ||
return [ | ||
_rnds[0] & 0xff | 0x01, // Set multicast bit, per 4.1.6 and 4.5 | ||
_rnds[0] >>> 8 & 0xff, | ||
_rnds[0] >>> 16 & 0xff, | ||
_rnds[0] >>> 24 & 0xff, | ||
_rnds[1] & 0xff, | ||
_rnds[1] >>> 8 & 0xff | ||
]; | ||
} | ||
// Pre-allocate arrays to avoid per-uuid array creation | ||
var _buf = new BufferClass(16); | ||
// | ||
@@ -120,71 +108,70 @@ // v1 UUID support | ||
// Per 4.1.4 - UUID time has 100ns resolution | ||
// Per 4.2.1.2 - Count of uuids may be used with low resolution clocks | ||
var UUIDS_PER_TICK = 10000; | ||
// random #'s we need to init node and clockseq | ||
var _seedBytes = _rng(10); | ||
// Per 4.5, use a random node id | ||
var _nodeId = _randomNodeId(); | ||
// Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1) | ||
var _nodeId = [ | ||
_seedBytes[0] | 0x01, | ||
_seedBytes[1], _seedBytes[2], _seedBytes[3], _seedBytes[4], _seedBytes[5] | ||
]; | ||
// Per 4.2.2, use 14 bit random unsigned integer to initialize clock_seq | ||
var _clockSeq = _rnds[2] & 0x3fff; | ||
// Per 4.2.2, randomize (14 bit) clockseq | ||
var _clockSeq = (_seedBytes[6] << 8 | _seedBytes[7]) & 0x3fff; | ||
// Time of previous uuid creation | ||
// Previous uuid creation time | ||
var _last = 0; | ||
// # of UUIDs that have been created during current millisecond time tick | ||
// Count of UUIDs created during current time tick | ||
var _count = 0; | ||
/** | ||
* See docs at https://github.com/broofa/node-uuid | ||
*/ | ||
/** See docs at https://github.com/broofa/node-uuid */ | ||
function v1(options, buf, offset) { | ||
options = typeof(options) == 'string' ? {format: options} : options || {}; | ||
var b = options.format != 'binary' ? _buf : | ||
(buf ? buf : new BufferClass(16)); | ||
var i = buf && offset || 0; | ||
var b = buf || _buffer; | ||
// JS Numbers don't have sufficient resolution for keeping time in | ||
// 100-nanosecond units, as spec'ed by the RFC, so we kind of kludge things | ||
// here by tracking time in JS-msec units, with a second var for the | ||
// additional 100-nanosecond units to add to the millisecond-based time. | ||
options = options || {}; | ||
// JS Numbers aren't capable of representing time in the RFC-specified | ||
// 100-nanosecond units. To deal with this, we represent time as the usual | ||
// JS milliseconds, plus an additional 100-nanosecond unit offset. | ||
var msecs = 0; // JS time (msecs since Unix epoch) | ||
var nsecs = 0; // Additional time (100-nanosecond units), added to msecs | ||
var nsecs = 0; // additional 100-nanosecond units to add to msecs | ||
// Get msecs & nsecs | ||
if (options.msecs == null) { | ||
// Per 4.2.1.2, use uuid count to simulate higher resolution clock | ||
// Get current time and simulate higher clock resolution | ||
if (options.msecs != null) { | ||
// Explicit time specified. Not that this turns off the internal logic | ||
// around uuid count and clock sequence used insure uniqueness | ||
msecs = (+options.msecs) + EPOCH_OFFSET; | ||
nsecs = options.nsecs || 0; | ||
} else { | ||
// No time options - Follow the RFC logic (4.2.1.2) for maintaining | ||
// clock seq and uuid count to help insure UUID uniqueness. | ||
msecs = new Date().getTime() + EPOCH_OFFSET; | ||
_count = (msecs == _last) ? _count + 1 : 0; | ||
// Per 4.2.1.2 If generator overruns, throw an error | ||
// (*Highly* unlikely - requires generating > 10M uuids/sec) | ||
if (_count == UUIDS_PER_TICK) { | ||
throw new Error('uuid.v1(): Can\'t create more than 10M uuids/sec'); | ||
} | ||
// Per 4.2.1.2, if time regresses bump the clock sequence. | ||
if (msecs < _last) { | ||
// Clock regression - Per 4.2.1.2, increment clock seq | ||
_clockSeq++; | ||
_count = 0; | ||
} else { | ||
// Per 4.2.1.2, use a count of uuid's generated during the current | ||
// clock cycle to simulate higher resolution clock | ||
_count = (msecs == _last) ? _count + 1 : 0; | ||
} | ||
_last = msecs; | ||
_last = msecs; | ||
// Per 4.2.1.2 If generator creates more than one id per uuid 100-ns | ||
// interval, throw an error | ||
// (Requires generating > 10M uuids/sec. While unlikely, it's not | ||
// entirely inconceivable given the benchmark results we're getting) | ||
if (_count >= 10000) { | ||
throw new Error('uuid.v1(): Can\'t create more than 10M uuids/sec'); | ||
} | ||
nsecs = _count; | ||
} else { | ||
msecs = options.msecs + EPOCH_OFFSET; | ||
nsecs = options.nsecs || 0; | ||
} | ||
// Per 4.1.4, timestamp composition | ||
// time is uuid epoch time in _msecs_ | ||
var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000; | ||
var tmh = ((msecs / 0x100000000) * 10000) & 0xfffffff; | ||
var tm = tmh & 0xffff, th = tmh >> 16; | ||
var thav = (th & 0xfff) | 0x1000; // Set version, per 4.1.3 | ||
// Clock sequence | ||
var cs = options.clockseq != null ? options.clockseq : _clockSeq; | ||
// time_low | ||
var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000; | ||
b[i++] = tl >>> 24 & 0xff; | ||
@@ -196,12 +183,16 @@ b[i++] = tl >>> 16 & 0xff; | ||
// time_mid | ||
b[i++] = tm >>> 8 & 0xff; | ||
b[i++] = tm & 0xff; | ||
var tmh = (msecs / 0x100000000 * 10000) & 0xfffffff; | ||
b[i++] = tmh >>> 8 & 0xff; | ||
b[i++] = tmh & 0xff; | ||
// time_high_and_version | ||
b[i++] = thav >>> 8 & 0xff; | ||
b[i++] = thav & 0xff; | ||
b[i++] = tmh >>> 24 & 0xf | 0x10; // include version | ||
b[i++] = tmh >>> 16 & 0xff; | ||
// clock_seq_hi_and_reserved (include variant, per 4.2.2) | ||
b[i++] = (cs >>> 8) | 0x80; | ||
// Clock sequence | ||
var cs = options.clockseq != null ? options.clockseq : _clockSeq; | ||
// clock_seq_hi_and_reserved (Per 4.2.2 - include variant) | ||
b[i++] = cs >>> 8 | 0x80; | ||
// clock_seq_low | ||
@@ -216,3 +207,3 @@ b[i++] = cs & 0xff; | ||
return options.format == null ? unparse(b) : b; | ||
return buf ? buf : unparse(b); | ||
} | ||
@@ -224,28 +215,30 @@ | ||
/** | ||
* See docs at https://github.com/broofa/node-uuid | ||
*/ | ||
/** See docs at https://github.com/broofa/node-uuid */ | ||
function v4(options, buf, offset) { | ||
options = typeof(options) == 'string' ? {format: options} : options || {}; | ||
var b = options.format != 'binary' ? _buf : | ||
(buf ? buf : new BufferClass(16)); | ||
// Deprecated - 'format' argument, as supported in v1.2 | ||
var i = buf && offset || 0; | ||
if (typeof(options) == 'string') { | ||
buf = options == 'binary' ? new BufferClass(16) : null; | ||
options = null; | ||
} | ||
var rnds = options.random || crypto.getRandomValues(_rnds); | ||
var rnds = options && options.random || _rng(16); | ||
// Per 4.4, set bits for version and clock_seq_hi_and_reserved | ||
rnds[6] = (rnds[6] & 0x0f) | 0x40; | ||
rnds[8] = (rnds[8] & 0x3f) | 0x80; | ||
// v4 ideas are all random bits | ||
for (var c = 0 ; c < 16; c++) { | ||
var ri = c >> 2, | ||
rb = (c & 0x03) * 8; | ||
b[i + c] = _rnds[ri] >>> rb & 0xff; | ||
// Copy bytes to buffer, if provided | ||
if (buf) { | ||
for (var ii = 0; ii < 16; ii++) { | ||
buf[i + ii] = rnds[ii]; | ||
} | ||
} | ||
// ... except for this | ||
b[i + 6] = (b[i + 6] & 0x0f) | 0x40; // Per RFC4122 sect. 4.1.3 | ||
b[i + 8] = (b[i + 8] & 0x3f) | 0x80; // Per RFC4122 sect. 4.4 | ||
return options.format == null ? unparse(b) : b; | ||
return buf || unparse(rnds); | ||
} | ||
// | ||
// Export API | ||
// | ||
var uuid = v4; | ||
@@ -261,4 +254,9 @@ uuid.v1 = v1; | ||
} else { | ||
this.uuid = uuid; | ||
var _previousRoot = _global.uuid; | ||
uuid.noConflict = function() { | ||
_global.uuid = _previousRoot; | ||
return uuid; | ||
} | ||
_global.uuid = uuid; | ||
} | ||
}()); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
31664
13
196
454
2