@@ -12,24 +12,28 @@ const {
1212 RandomBytesJob,
1313 kCryptoJobAsync,
1414 kCryptoJobSync,
15+ secureBuffer,
1516} = internalBinding('crypto');
1617
1718const {
1819 lazyDOMException,
1920} = require('internal/crypto/util');
2021
21- const { kMaxLength } = require('buffer');
22+ const { Buffer, kMaxLength } = require('buffer');
2223
2324const {
2425 codes: {
2526 ERR_INVALID_ARG_TYPE,
2627 ERR_OUT_OF_RANGE,
28+ ERR_OPERATION_FAILED,
2729 }
2830} = require('internal/errors');
2931
3032const {
3133 validateNumber,
34+ validateBoolean,
3235 validateCallback,
36+ validateObject,
3337} = require('internal/validators');
3438
3539const {
@@ -281,10 +285,114 @@ function getRandomValues(data) {
281285 return data;
282286}
283287
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+
284391module.exports = {
285392 randomBytes,
286393 randomFill,
287394 randomFillSync,
288395 randomInt,
289396 getRandomValues,
397+ randomUUID,
290398};
0 commit comments