@@ -7,14 +7,27 @@ const {
7
7
} = primordials ;
8
8
9
9
const { AsyncWrap, Providers } = internalBinding ( 'async_wrap' ) ;
10
- const { kMaxLength } = require ( 'buffer' ) ;
11
- const { randomBytes : _randomBytes } = internalBinding ( 'crypto' ) ;
12
10
const {
13
- ERR_INVALID_ARG_TYPE ,
14
- ERR_INVALID_CALLBACK ,
15
- ERR_OUT_OF_RANGE
16
- } = require ( 'internal/errors' ) . codes ;
17
- const { validateNumber } = require ( 'internal/validators' ) ;
11
+ Buffer,
12
+ kMaxLength,
13
+ } = require ( 'buffer' ) ;
14
+ const {
15
+ randomBytes : _randomBytes ,
16
+ secureBuffer,
17
+ } = internalBinding ( 'crypto' ) ;
18
+ const {
19
+ codes : {
20
+ ERR_INVALID_ARG_TYPE ,
21
+ ERR_INVALID_CALLBACK ,
22
+ ERR_OUT_OF_RANGE ,
23
+ ERR_OPERATION_FAILED ,
24
+ }
25
+ } = require ( 'internal/errors' ) ;
26
+ const {
27
+ validateBoolean,
28
+ validateNumber,
29
+ validateObject,
30
+ } = require ( 'internal/validators' ) ;
18
31
const { isArrayBufferView } = require ( 'internal/util/types' ) ;
19
32
const { FastBuffer } = require ( 'internal/buffer' ) ;
20
33
@@ -203,9 +216,113 @@ function handleError(ex, buf) {
203
216
return buf ;
204
217
}
205
218
219
+ // Implements an RFC 4122 version 4 random UUID.
220
+ // To improve performance, random data is generated in batches
221
+ // large enough to cover kBatchSize UUID's at a time. The uuidData
222
+ // and uuid buffers are reused. Each call to randomUUID() consumes
223
+ // 16 bytes from the buffer.
224
+
225
+ const kHexDigits = [
226
+ 48 , 49 , 50 , 51 , 52 , 53 , 54 , 55 ,
227
+ 56 , 57 , 97 , 98 , 99 , 100 , 101 , 102
228
+ ] ;
229
+
230
+ const kBatchSize = 128 ;
231
+ let uuidData ;
232
+ let uuidNotBuffered ;
233
+ let uuid ;
234
+ let uuidBatch = 0 ;
235
+
236
+ function getBufferedUUID ( ) {
237
+ if ( uuidData === undefined ) {
238
+ uuidData = secureBuffer ( 16 * kBatchSize ) ;
239
+ if ( uuidData === undefined )
240
+ throw new ERR_OPERATION_FAILED ( 'Out of memory' ) ;
241
+ }
242
+
243
+ if ( uuidBatch === 0 ) randomFillSync ( uuidData ) ;
244
+ uuidBatch = ( uuidBatch + 1 ) % kBatchSize ;
245
+ return uuidData . slice ( uuidBatch * 16 , ( uuidBatch * 16 ) + 16 ) ;
246
+ }
247
+
248
+ function randomUUID ( options ) {
249
+ if ( options !== undefined )
250
+ validateObject ( options , 'options' ) ;
251
+ const {
252
+ disableEntropyCache = false ,
253
+ } = { ...options } ;
254
+
255
+ validateBoolean ( disableEntropyCache , 'options.disableEntropyCache' ) ;
256
+
257
+ if ( uuid === undefined ) {
258
+ uuid = Buffer . alloc ( 36 , '-' ) ;
259
+ uuid [ 14 ] = 52 ; // '4', identifies the UUID version
260
+ }
261
+
262
+ let uuidBuf ;
263
+ if ( ! disableEntropyCache ) {
264
+ uuidBuf = getBufferedUUID ( ) ;
265
+ } else {
266
+ uuidBuf = uuidNotBuffered ;
267
+ if ( uuidBuf === undefined )
268
+ uuidBuf = uuidNotBuffered = secureBuffer ( 16 ) ;
269
+ if ( uuidBuf === undefined )
270
+ throw new ERR_OPERATION_FAILED ( 'Out of memory' ) ;
271
+ randomFillSync ( uuidBuf ) ;
272
+ }
273
+
274
+ // Variant byte: 10xxxxxx (variant 1)
275
+ uuidBuf [ 8 ] = ( uuidBuf [ 8 ] & 0x3f ) | 0x80 ;
276
+
277
+ // This function is structured the way it is for performance.
278
+ // The uuid buffer stores the serialization of the random
279
+ // bytes from uuidData.
280
+ // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
281
+ let n = 0 ;
282
+ uuid [ 0 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
283
+ uuid [ 1 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
284
+ uuid [ 2 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
285
+ uuid [ 3 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
286
+ uuid [ 4 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
287
+ uuid [ 5 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
288
+ uuid [ 6 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
289
+ uuid [ 7 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
290
+ // -
291
+ uuid [ 9 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
292
+ uuid [ 10 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
293
+ uuid [ 11 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
294
+ uuid [ 12 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
295
+ // -
296
+ // 4, uuid[14] is set already...
297
+ uuid [ 15 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
298
+ uuid [ 16 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
299
+ uuid [ 17 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
300
+ // -
301
+ uuid [ 19 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
302
+ uuid [ 20 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
303
+ uuid [ 21 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
304
+ uuid [ 22 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
305
+ // -
306
+ uuid [ 24 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
307
+ uuid [ 25 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
308
+ uuid [ 26 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
309
+ uuid [ 27 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
310
+ uuid [ 28 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
311
+ uuid [ 29 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
312
+ uuid [ 30 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
313
+ uuid [ 31 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
314
+ uuid [ 32 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
315
+ uuid [ 33 ] = kHexDigits [ uuidBuf [ n ++ ] & 0xf ] ;
316
+ uuid [ 34 ] = kHexDigits [ uuidBuf [ n ] >> 4 ] ;
317
+ uuid [ 35 ] = kHexDigits [ uuidBuf [ n ] & 0xf ] ;
318
+
319
+ return uuid . latin1Slice ( 0 , 36 ) ;
320
+ }
321
+
206
322
module . exports = {
207
323
randomBytes,
208
324
randomFill,
209
325
randomFillSync,
210
- randomInt
326
+ randomInt,
327
+ randomUUID,
211
328
} ;
0 commit comments