@@ -12,24 +12,28 @@ const {
12
12
RandomBytesJob,
13
13
kCryptoJobAsync,
14
14
kCryptoJobSync,
15
+ secureBuffer,
15
16
} = internalBinding ( 'crypto' ) ;
16
17
17
18
const {
18
19
lazyDOMException,
19
20
} = require ( 'internal/crypto/util' ) ;
20
21
21
- const { kMaxLength } = require ( 'buffer' ) ;
22
+ const { Buffer , kMaxLength } = require ( 'buffer' ) ;
22
23
23
24
const {
24
25
codes : {
25
26
ERR_INVALID_ARG_TYPE ,
26
27
ERR_OUT_OF_RANGE ,
28
+ ERR_OPERATION_FAILED ,
27
29
}
28
30
} = require ( 'internal/errors' ) ;
29
31
30
32
const {
31
33
validateNumber,
34
+ validateBoolean,
32
35
validateCallback,
36
+ validateObject,
33
37
} = require ( 'internal/validators' ) ;
34
38
35
39
const {
@@ -281,10 +285,114 @@ function getRandomValues(data) {
281
285
return data ;
282
286
}
283
287
288
+ // Implements an RFC 4122 version 4 random UUID.
289
+ // To improve performance, random data is generated in batches
290
+ // large enough to cover kBatchSize UUID's at a time. The uuidData
291
+ // and uuid buffers are reused. Each call to randomUUID() consumes
292
+ // 16 bytes from the buffer.
293
+
294
+ const kHexDigits = [
295
+ 48 , 49 , 50 , 51 , 52 , 53 , 54 , 55 ,
296
+ 56 , 57 , 97 , 98 , 99 , 100 , 101 , 102
297
+ ] ;
298
+
299
+ const kBatchSize = 128 ;
300
+ let uuidData ;
301
+ let uuidNotBuffered ;
302
+ let uuid ;
303
+ let uuidBatch = 0 ;
304
+
305
+ function getBufferedUUID ( ) {
306
+ if ( uuidData === undefined ) {
307
+ uuidData = secureBuffer ( 16 * kBatchSize ) ;
308
+ if ( uuidData === undefined )
309
+ throw new ERR_OPERATION_FAILED ( 'Out of memory' ) ;
310
+ }
311
+
312
+ if ( uuidBatch === 0 ) randomFillSync ( uuidData ) ;
313
+ uuidBatch = ( uuidBatch + 1 ) % kBatchSize ;
314
+ return uuidData . slice ( uuidBatch * 16 , ( uuidBatch * 16 ) + 16 ) ;
315
+ }
316
+
317
+ function randomUUID ( options ) {
318
+ if ( options !== undefined )
319
+ validateObject ( options , 'options' ) ;
320
+ const {
321
+ disableEntropyCache = false ,
322
+ } = { ...options } ;
323
+
324
+ validateBoolean ( disableEntropyCache , 'options.disableEntropyCache' ) ;
325
+
326
+ if ( uuid === undefined ) {
327
+ uuid = Buffer . alloc ( 36 , '-' ) ;
328
+ uuid [ 14 ] = 52 ; // '4', identifies the UUID version
329
+ }
330
+
331
+ let uuidBuf ;
332
+ if ( ! disableEntropyCache ) {
333
+ uuidBuf = getBufferedUUID ( ) ;
334
+ } else {
335
+ uuidBuf = uuidNotBuffered ;
336
+ if ( uuidBuf === undefined )
337
+ uuidBuf = uuidNotBuffered = secureBuffer ( 16 ) ;
338
+ if ( uuidBuf === undefined )
339
+ throw new ERR_OPERATION_FAILED ( 'Out of memory' ) ;
340
+ randomFillSync ( uuidBuf ) ;
341
+ }
342
+
343
+ // Variant byte: 10xxxxxx (variant 1)
344
+ uuidBuf [ 8 ] = ( uuidBuf [ 8 ] & 0x3f ) | 0x80 ;
345
+
346
+ // This function is structured the way it is for performance.
347
+ // The uuid buffer stores the serialization of the random
348
+ // bytes from uuidData.
349
+ // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
350
+ let n = 0 ;
351
+ uuid [ 0 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
352
+ uuid [ 1 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
353
+ uuid [ 2 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
354
+ uuid [ 3 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
355
+ uuid [ 4 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
356
+ uuid [ 5 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
357
+ uuid [ 6 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
358
+ uuid [ 7 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
359
+ // -
360
+ uuid [ 9 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
361
+ uuid [ 10 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
362
+ uuid [ 11 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
363
+ uuid [ 12 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
364
+ // -
365
+ // 4, uuid[14] is set already...
366
+ uuid [ 15 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
367
+ uuid [ 16 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
368
+ uuid [ 17 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
369
+ // -
370
+ uuid [ 19 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
371
+ uuid [ 20 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
372
+ uuid [ 21 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
373
+ uuid [ 22 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
374
+ // -
375
+ uuid [ 24 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
376
+ uuid [ 25 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
377
+ uuid [ 26 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
378
+ uuid [ 27 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
379
+ uuid [ 28 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
380
+ uuid [ 29 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
381
+ uuid [ 30 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
382
+ uuid [ 31 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
383
+ uuid [ 32 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
384
+ uuid [ 33 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
385
+ uuid [ 34 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
386
+ uuid [ 35 ] = kHexDigits [ uuidBuf [ n ] & 0xf ] ;
387
+
388
+ return uuid . latin1Slice ( 0 , 36 ) ;
389
+ }
390
+
284
391
module . exports = {
285
392
randomBytes,
286
393
randomFill,
287
394
randomFillSync,
288
395
randomInt,
289
396
getRandomValues,
397
+ randomUUID,
290
398
} ;
0 commit comments