@depup/crypto-random-string 5.0.0-depup.4 → 6.0.0-depup.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/changes.json +3 -3
- package/index.d.ts +14 -29
- package/index.js +104 -13
- package/package.json +13 -15
- package/readme.md +8 -33
- package/browser.js +0 -31
- package/core.js +0 -140
package/README.md
CHANGED
|
@@ -13,8 +13,8 @@ npm install @depup/crypto-random-string
|
|
|
13
13
|
|
|
14
14
|
| Field | Value |
|
|
15
15
|
|-------|-------|
|
|
16
|
-
| Original | [crypto-random-string](https://www.npmjs.com/package/crypto-random-string) @
|
|
17
|
-
| Processed | 2026-
|
|
16
|
+
| Original | [crypto-random-string](https://www.npmjs.com/package/crypto-random-string) @ 6.0.0 |
|
|
17
|
+
| Processed | 2026-08-31 |
|
|
18
18
|
| Smoke test | passed |
|
|
19
19
|
| Deps updated | 1 |
|
|
20
20
|
|
|
@@ -22,7 +22,7 @@ npm install @depup/crypto-random-string
|
|
|
22
22
|
|
|
23
23
|
| Dependency | From | To |
|
|
24
24
|
|------------|------|-----|
|
|
25
|
-
| type-fest | ^
|
|
25
|
+
| type-fest | ^5.8.0 | ^5.9.0 |
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
package/changes.json
CHANGED
package/index.d.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
import {MergeExclusive} from 'type-fest';
|
|
1
|
+
import {type MergeExclusive} from 'type-fest';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
type BaseOptions = {
|
|
4
4
|
/**
|
|
5
5
|
Length of the returned string.
|
|
6
|
+
|
|
7
|
+
Must be a non-negative integer.
|
|
8
|
+
|
|
9
|
+
This is the number of characters, so a string generated from a `characters` set with characters outside the [Basic Multilingual Plane](https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane), like emoji, has a larger `.length` than this.
|
|
6
10
|
*/
|
|
7
11
|
length: number;
|
|
8
|
-
}
|
|
12
|
+
};
|
|
9
13
|
|
|
10
|
-
|
|
14
|
+
type TypeOption = {
|
|
11
15
|
/**
|
|
12
16
|
Use only characters from a predefined set of allowed characters.
|
|
13
17
|
|
|
@@ -17,7 +21,7 @@ interface TypeOption {
|
|
|
17
21
|
|
|
18
22
|
The `distinguishable` set contains only uppercase characters that are not easily confused: `CDEHKMPRTUWXY012458`. It can be useful if you need to print out a short string that you'd like users to read and type back in with minimal errors. For example, reading a code off of a screen that needs to be typed into a phone to connect two devices.
|
|
19
23
|
|
|
20
|
-
The `ascii-printable` set contains all [printable ASCII characters](https://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters): ``!"
|
|
24
|
+
The `ascii-printable` set contains all [printable ASCII characters](https://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters) except the space: ``!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~`` Useful for generating passwords where all possible ASCII characters should be used.
|
|
21
25
|
|
|
22
26
|
The `alphanumeric` set contains uppercase letters, lowercase letters, and digits: `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`. Useful for generating [nonce](https://developer.mozilla.org/en-US/docs/Web/API/HTMLOrForeignElement/nonce) values.
|
|
23
27
|
|
|
@@ -46,14 +50,16 @@ interface TypeOption {
|
|
|
46
50
|
```
|
|
47
51
|
*/
|
|
48
52
|
type?: 'hex' | 'base64' | 'url-safe' | 'numeric' | 'distinguishable' | 'ascii-printable' | 'alphanumeric';
|
|
49
|
-
}
|
|
53
|
+
};
|
|
50
54
|
|
|
51
|
-
|
|
55
|
+
type CharactersOption = {
|
|
52
56
|
/**
|
|
53
57
|
Use only characters from a custom set of allowed characters.
|
|
54
58
|
|
|
55
59
|
Cannot be set at the same time as the `type` option.
|
|
56
60
|
|
|
61
|
+
Each character is picked with equal probability, so repeating a character in the set makes it more likely to be picked. The length limits count Unicode characters, not UTF-16 code units, so characters outside the [Basic Multilingual Plane](https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane), like emoji, are handled correctly.
|
|
62
|
+
|
|
57
63
|
Minimum length: `1`
|
|
58
64
|
Maximum length: `65536`
|
|
59
65
|
|
|
@@ -64,7 +70,7 @@ interface CharactersOption {
|
|
|
64
70
|
```
|
|
65
71
|
*/
|
|
66
72
|
characters?: string;
|
|
67
|
-
}
|
|
73
|
+
};
|
|
68
74
|
|
|
69
75
|
export type Options = BaseOptions & MergeExclusive<TypeOption, CharactersOption>;
|
|
70
76
|
|
|
@@ -82,24 +88,3 @@ cryptoRandomString({length: 10});
|
|
|
82
88
|
```
|
|
83
89
|
*/
|
|
84
90
|
export default function cryptoRandomString(options: Options): string;
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
Asynchronously generate a [cryptographically strong](https://en.wikipedia.org/wiki/Strong_cryptography) random string.
|
|
88
|
-
|
|
89
|
-
For most use-cases, there's really no good reason to use this async version. From the Node.js docs:
|
|
90
|
-
|
|
91
|
-
> The `crypto.randomBytes()` method will not complete until there is sufficient entropy available. This should normally never take longer than a few milliseconds. The only time when generating the random bytes may conceivably block for a longer period of time is right after boot, when the whole system is still low on entropy.
|
|
92
|
-
|
|
93
|
-
In general, anything async comes with some overhead on it's own.
|
|
94
|
-
|
|
95
|
-
@returns A promise which resolves to a randomized string.
|
|
96
|
-
|
|
97
|
-
@example
|
|
98
|
-
```
|
|
99
|
-
import {cryptoRandomStringAsync} from 'crypto-random-string';
|
|
100
|
-
|
|
101
|
-
await cryptoRandomStringAsync({length: 10});
|
|
102
|
-
//=> '2cf05d94db'
|
|
103
|
-
```
|
|
104
|
-
*/
|
|
105
|
-
export function cryptoRandomStringAsync(options: Options): Promise<string>;
|
package/index.js
CHANGED
|
@@ -1,13 +1,104 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
import {uint8ArrayToBase64, uint8ArrayToHex} from 'uint8array-extras';
|
|
2
|
+
|
|
3
|
+
// `crypto.getRandomValues` throws an error if too much entropy is requested at once. (https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues#exceptions)
|
|
4
|
+
const maxBytesPerRequest = 65_536;
|
|
5
|
+
|
|
6
|
+
// Each character is picked with a single `Uint16` selector value, so a character set cannot be larger than the range of one.
|
|
7
|
+
const maxCharacterSetSize = 0x1_00_00;
|
|
8
|
+
|
|
9
|
+
function fillWithRandomValues(typedArray) {
|
|
10
|
+
const maxElementsPerRequest = maxBytesPerRequest / typedArray.BYTES_PER_ELEMENT;
|
|
11
|
+
|
|
12
|
+
for (let offset = 0; offset < typedArray.length; offset += maxElementsPerRequest) {
|
|
13
|
+
// `TypedArray#subarray` clamps the end index and shares the underlying buffer, so this fills the array in place without any copying.
|
|
14
|
+
crypto.getRandomValues(typedArray.subarray(offset, offset + maxElementsPerRequest));
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return typedArray;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const randomBytes = byteLength => fillWithRandomValues(new Uint8Array(byteLength));
|
|
21
|
+
|
|
22
|
+
const generateForCustomCharacters = (length, characters) => {
|
|
23
|
+
// Generating entropy is faster than complex math operations, so we use the simplest way
|
|
24
|
+
const characterCount = characters.length;
|
|
25
|
+
const validSelectorCount = Math.floor(maxCharacterSetSize / characterCount) * characterCount; // Using values at or above this will ruin distribution when using modular division
|
|
26
|
+
// Generating a bit more than required, adjusted for how many values we expect to discard, so we usually only need one pass
|
|
27
|
+
const entropyLength = Math.ceil(1.1 * length * (maxCharacterSetSize / validSelectorCount));
|
|
28
|
+
let string = '';
|
|
29
|
+
let stringLength = 0;
|
|
30
|
+
|
|
31
|
+
while (stringLength < length) {
|
|
32
|
+
const entropy = fillWithRandomValues(new Uint16Array(entropyLength));
|
|
33
|
+
|
|
34
|
+
for (let index = 0; index < entropyLength; index++) {
|
|
35
|
+
const entropyValue = entropy[index];
|
|
36
|
+
|
|
37
|
+
if (entropyValue < validSelectorCount) { // Skip values which will ruin distribution when using modular division
|
|
38
|
+
string += characters[entropyValue % characterCount];
|
|
39
|
+
stringLength++;
|
|
40
|
+
|
|
41
|
+
if (stringLength === length) {
|
|
42
|
+
return string;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return string;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const characterSets = new Map([
|
|
52
|
+
['url-safe', [...'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~']],
|
|
53
|
+
['numeric', [...'0123456789']],
|
|
54
|
+
['distinguishable', [...'CDEHKMPRTUWXY012458']],
|
|
55
|
+
['ascii-printable', [...'!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~']],
|
|
56
|
+
['alphanumeric', [...'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789']],
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
const allowedTypes = new Set(['hex', 'base64', ...characterSets.keys()]);
|
|
60
|
+
|
|
61
|
+
export default function cryptoRandomString({length, type, characters}) {
|
|
62
|
+
if (!Number.isSafeInteger(length) || length < 0) {
|
|
63
|
+
throw new TypeError('Expected `length` to be a non-negative integer');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (type !== undefined && characters !== undefined) {
|
|
67
|
+
throw new TypeError('Expected either `type` or `characters`');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (characters !== undefined) {
|
|
71
|
+
if (typeof characters !== 'string') {
|
|
72
|
+
throw new TypeError('Expected `characters` to be a string');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Spread to keep characters outside the Basic Multilingual Plane, like emoji, intact.
|
|
76
|
+
const customCharacterSet = [...characters];
|
|
77
|
+
|
|
78
|
+
if (customCharacterSet.length === 0) {
|
|
79
|
+
throw new TypeError('Expected `characters` to contain at least 1 character');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (customCharacterSet.length > maxCharacterSetSize) {
|
|
83
|
+
throw new TypeError(`Expected \`characters\` to contain at most ${maxCharacterSetSize} characters, got ${customCharacterSet.length}`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return generateForCustomCharacters(length, customCharacterSet);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (type !== undefined && !allowedTypes.has(type)) {
|
|
90
|
+
throw new TypeError(`Unknown type: ${type}`);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const characterSet = characterSets.get(type);
|
|
94
|
+
|
|
95
|
+
if (characterSet !== undefined) {
|
|
96
|
+
return generateForCustomCharacters(length, characterSet);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (type === 'base64') {
|
|
100
|
+
return uint8ArrayToBase64(randomBytes(Math.ceil(length * 0.75))).slice(0, length); // Needs 0.75 bytes of entropy per character
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return uint8ArrayToHex(randomBytes(Math.ceil(length * 0.5))).slice(0, length); // Needs 0.5 bytes of entropy per character
|
|
104
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@depup/crypto-random-string",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0-depup.1",
|
|
4
4
|
"description": "Generate a cryptographically strong random string (with updated dependencies)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "sindresorhus/crypto-random-string",
|
|
@@ -13,19 +13,17 @@
|
|
|
13
13
|
"type": "module",
|
|
14
14
|
"exports": {
|
|
15
15
|
"types": "./index.d.ts",
|
|
16
|
-
"
|
|
17
|
-
"browser": "./browser.js"
|
|
16
|
+
"default": "./index.js"
|
|
18
17
|
},
|
|
18
|
+
"sideEffects": false,
|
|
19
19
|
"engines": {
|
|
20
|
-
"node": ">=
|
|
20
|
+
"node": ">=22"
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
|
23
23
|
"test": "xo && ava && tsd"
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
26
26
|
"index.js",
|
|
27
|
-
"browser.js",
|
|
28
|
-
"core.js",
|
|
29
27
|
"index.d.ts",
|
|
30
28
|
"changes.json",
|
|
31
29
|
"README.md"
|
|
@@ -53,25 +51,25 @@
|
|
|
53
51
|
"protect"
|
|
54
52
|
],
|
|
55
53
|
"dependencies": {
|
|
56
|
-
"type-fest": "^5.
|
|
54
|
+
"type-fest": "^5.9.0",
|
|
55
|
+
"uint8array-extras": "^1.5.0"
|
|
57
56
|
},
|
|
58
57
|
"devDependencies": {
|
|
59
|
-
"ava": "^
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"xo": "^0.48.0"
|
|
58
|
+
"ava": "^8.0.1",
|
|
59
|
+
"tsd": "^0.33.0",
|
|
60
|
+
"xo": "^4.0.0"
|
|
63
61
|
},
|
|
64
62
|
"depup": {
|
|
65
63
|
"changes": {
|
|
66
64
|
"type-fest": {
|
|
67
|
-
"from": "^
|
|
68
|
-
"to": "^5.
|
|
65
|
+
"from": "^5.8.0",
|
|
66
|
+
"to": "^5.9.0"
|
|
69
67
|
}
|
|
70
68
|
},
|
|
71
69
|
"depsUpdated": 1,
|
|
72
70
|
"originalPackage": "crypto-random-string",
|
|
73
|
-
"originalVersion": "
|
|
74
|
-
"processedAt": "2026-
|
|
71
|
+
"originalVersion": "6.0.0",
|
|
72
|
+
"processedAt": "2026-08-31T00:35:43.225Z",
|
|
75
73
|
"smokeTest": "passed"
|
|
76
74
|
}
|
|
77
75
|
}
|
package/readme.md
CHANGED
|
@@ -48,23 +48,6 @@ cryptoRandomString({length: 10, characters: 'abc'});
|
|
|
48
48
|
|
|
49
49
|
Returns a randomized string. [Hex](https://en.wikipedia.org/wiki/Hexadecimal) by default.
|
|
50
50
|
|
|
51
|
-
### cryptoRandomStringAsync(options)
|
|
52
|
-
|
|
53
|
-
Returns a promise which resolves to a randomized string. [Hex](https://en.wikipedia.org/wiki/Hexadecimal) by default.
|
|
54
|
-
|
|
55
|
-
For most use-cases, there's really no good reason to use this async version. From the Node.js docs:
|
|
56
|
-
|
|
57
|
-
> The `crypto.randomBytes()` method will not complete until there is sufficient entropy available. This should normally never take longer than a few milliseconds. The only time when generating the random bytes may conceivably block for a longer period of time is right after boot, when the whole system is still low on entropy.
|
|
58
|
-
|
|
59
|
-
In general, anything async comes with some overhead on it's own.
|
|
60
|
-
|
|
61
|
-
```js
|
|
62
|
-
import {cryptoRandomStringAsync} from 'crypto-random-string';
|
|
63
|
-
|
|
64
|
-
await cryptoRandomStringAsync({length: 10});
|
|
65
|
-
//=> '2cf05d94db'
|
|
66
|
-
```
|
|
67
|
-
|
|
68
51
|
#### options
|
|
69
52
|
|
|
70
53
|
Type: `object`
|
|
@@ -72,10 +55,12 @@ Type: `object`
|
|
|
72
55
|
##### length
|
|
73
56
|
|
|
74
57
|
*Required*\
|
|
75
|
-
Type: `number`
|
|
58
|
+
Type: `number` *(non-negative integer)*
|
|
76
59
|
|
|
77
60
|
Length of the returned string.
|
|
78
61
|
|
|
62
|
+
This is the number of characters, so a string generated from a `characters` set with characters outside the [Basic Multilingual Plane](https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane), like emoji, has a larger `.length` than this.
|
|
63
|
+
|
|
79
64
|
##### type
|
|
80
65
|
|
|
81
66
|
Type: `string`\
|
|
@@ -88,7 +73,7 @@ Cannot be set at the same time as the `characters` option.
|
|
|
88
73
|
|
|
89
74
|
The `distinguishable` set contains only uppercase characters that are not easily confused: `CDEHKMPRTUWXY012458`. It can be useful if you need to print out a short string that you'd like users to read and type back in with minimal errors. For example, reading a code off of a screen that needs to be typed into a phone to connect two devices.
|
|
90
75
|
|
|
91
|
-
The `ascii-printable` set contains all [printable ASCII characters](https://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters): ``!"
|
|
76
|
+
The `ascii-printable` set contains all [printable ASCII characters](https://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters) except the space: ``!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~`` Useful for generating passwords where all possible ASCII characters should be used.
|
|
92
77
|
|
|
93
78
|
The `alphanumeric` set contains uppercase letters, lowercase letters, and digits: `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`. Useful for generating [nonce](https://developer.mozilla.org/en-US/docs/Web/API/HTMLOrForeignElement/nonce) values.
|
|
94
79
|
|
|
@@ -102,24 +87,14 @@ Use only characters from a custom set of allowed characters.
|
|
|
102
87
|
|
|
103
88
|
Cannot be set at the same time as the `type` option.
|
|
104
89
|
|
|
90
|
+
Each character is picked with equal probability, so repeating a character in the set makes it more likely to be picked. The length limits count Unicode characters, not UTF-16 code units, so characters outside the [Basic Multilingual Plane](https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane), like emoji, are handled correctly.
|
|
91
|
+
|
|
105
92
|
## Related
|
|
106
93
|
|
|
107
94
|
- [random-int](https://github.com/sindresorhus/random-int) - Generate a random integer
|
|
108
95
|
- [random-float](https://github.com/sindresorhus/random-float) - Generate a random float
|
|
109
96
|
- [random-item](https://github.com/sindresorhus/random-item) - Get a random item from an array
|
|
110
97
|
- [random-boolean](https://github.com/arthurvr/random-boolean) - Get a random boolean
|
|
111
|
-
- [random-
|
|
112
|
-
- [random-
|
|
98
|
+
- [random-object-key](https://github.com/sindresorhus/random-object-key) - Get a random key from an object
|
|
99
|
+
- [random-object-value](https://github.com/sindresorhus/random-object-value) - Get a random value from an object
|
|
113
100
|
- [unique-random](https://github.com/sindresorhus/unique-random) - Generate random numbers that are consecutively unique
|
|
114
|
-
|
|
115
|
-
---
|
|
116
|
-
|
|
117
|
-
<div align="center">
|
|
118
|
-
<b>
|
|
119
|
-
<a href="https://tidelift.com/subscription/pkg/npm-crypto-random-string?utm_source=npm-crypto-random-string&utm_medium=referral&utm_campaign=readme">Get professional support for this package with a Tidelift subscription</a>
|
|
120
|
-
</b>
|
|
121
|
-
<br>
|
|
122
|
-
<sub>
|
|
123
|
-
Tidelift helps make open source sustainable for maintainers while giving companies<br>assurances about security, maintenance, and licensing for their dependencies.
|
|
124
|
-
</sub>
|
|
125
|
-
</div>
|
package/browser.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
/* eslint-env browser */
|
|
2
|
-
import {createStringGenerator, createAsyncStringGenerator} from './core.js';
|
|
3
|
-
|
|
4
|
-
const toHex = uInt8Array => [...uInt8Array].map(byte => byte.toString(16).padStart(2, '0')).join('');
|
|
5
|
-
const toBase64 = uInt8Array => btoa(String.fromCodePoint(...uInt8Array));
|
|
6
|
-
|
|
7
|
-
// `crypto.getRandomValues` throws an error if too much entropy is requested at once. (https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues#exceptions)
|
|
8
|
-
const maxEntropy = 65_536;
|
|
9
|
-
|
|
10
|
-
function getRandomValues(byteLength) {
|
|
11
|
-
const generatedBytes = new Uint8Array(byteLength);
|
|
12
|
-
|
|
13
|
-
for (let totalGeneratedBytes = 0; totalGeneratedBytes < byteLength; totalGeneratedBytes += maxEntropy) {
|
|
14
|
-
generatedBytes.set(
|
|
15
|
-
crypto.getRandomValues(new Uint8Array(Math.min(maxEntropy, byteLength - totalGeneratedBytes))),
|
|
16
|
-
totalGeneratedBytes,
|
|
17
|
-
);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return generatedBytes;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function specialRandomBytes(byteLength, type, length) {
|
|
24
|
-
const generatedBytes = getRandomValues(byteLength);
|
|
25
|
-
const convert = type === 'hex' ? toHex : toBase64;
|
|
26
|
-
|
|
27
|
-
return convert(generatedBytes).slice(0, length);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export default createStringGenerator(specialRandomBytes, getRandomValues);
|
|
31
|
-
export const cryptoRandomStringAsync = createAsyncStringGenerator(specialRandomBytes, getRandomValues);
|
package/core.js
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
const urlSafeCharacters = [...'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~'];
|
|
2
|
-
const numericCharacters = [...'0123456789'];
|
|
3
|
-
const distinguishableCharacters = [...'CDEHKMPRTUWXY012458'];
|
|
4
|
-
const asciiPrintableCharacters = [...'!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'];
|
|
5
|
-
const alphanumericCharacters = [...'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'];
|
|
6
|
-
|
|
7
|
-
const readUInt16LE = (uInt8Array, offset) => uInt8Array[offset] + (uInt8Array[offset + 1] << 8); // eslint-disable-line no-bitwise
|
|
8
|
-
|
|
9
|
-
const generateForCustomCharacters = (length, characters, randomBytes) => {
|
|
10
|
-
// Generating entropy is faster than complex math operations, so we use the simplest way
|
|
11
|
-
const characterCount = characters.length;
|
|
12
|
-
const maxValidSelector = (Math.floor(0x1_00_00 / characterCount) * characterCount) - 1; // Using values above this will ruin distribution when using modular division
|
|
13
|
-
const entropyLength = 2 * Math.ceil(1.1 * length); // Generating a bit more than required so chances we need more than one pass will be really low
|
|
14
|
-
let string = '';
|
|
15
|
-
let stringLength = 0;
|
|
16
|
-
|
|
17
|
-
while (stringLength < length) { // In case we had many bad values, which may happen for character sets of size above 0x8000 but close to it
|
|
18
|
-
const entropy = randomBytes(entropyLength);
|
|
19
|
-
let entropyPosition = 0;
|
|
20
|
-
|
|
21
|
-
while (entropyPosition < entropyLength && stringLength < length) {
|
|
22
|
-
const entropyValue = readUInt16LE(entropy, entropyPosition);
|
|
23
|
-
entropyPosition += 2;
|
|
24
|
-
if (entropyValue > maxValidSelector) { // Skip values which will ruin distribution when using modular division
|
|
25
|
-
continue;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
string += characters[entropyValue % characterCount];
|
|
29
|
-
stringLength++;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return string;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const generateForCustomCharactersAsync = async (length, characters, randomBytesAsync) => {
|
|
37
|
-
// Generating entropy is faster than complex math operations, so we use the simplest way
|
|
38
|
-
const characterCount = characters.length;
|
|
39
|
-
const maxValidSelector = (Math.floor(0x1_00_00 / characterCount) * characterCount) - 1; // Using values above this will ruin distribution when using modular division
|
|
40
|
-
const entropyLength = 2 * Math.ceil(1.1 * length); // Generating a bit more than required so chances we need more than one pass will be really low
|
|
41
|
-
let string = '';
|
|
42
|
-
let stringLength = 0;
|
|
43
|
-
|
|
44
|
-
while (stringLength < length) { // In case we had many bad values, which may happen for character sets of size above 0x8000 but close to it
|
|
45
|
-
const entropy = await randomBytesAsync(entropyLength); // eslint-disable-line no-await-in-loop
|
|
46
|
-
let entropyPosition = 0;
|
|
47
|
-
|
|
48
|
-
while (entropyPosition < entropyLength && stringLength < length) {
|
|
49
|
-
const entropyValue = readUInt16LE(entropy, entropyPosition);
|
|
50
|
-
entropyPosition += 2;
|
|
51
|
-
if (entropyValue > maxValidSelector) { // Skip values which will ruin distribution when using modular division
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
string += characters[entropyValue % characterCount];
|
|
56
|
-
stringLength++;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return string;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
const allowedTypes = new Set([
|
|
64
|
-
undefined,
|
|
65
|
-
'hex',
|
|
66
|
-
'base64',
|
|
67
|
-
'url-safe',
|
|
68
|
-
'numeric',
|
|
69
|
-
'distinguishable',
|
|
70
|
-
'ascii-printable',
|
|
71
|
-
'alphanumeric',
|
|
72
|
-
]);
|
|
73
|
-
|
|
74
|
-
const createGenerator = (generateForCustomCharacters, specialRandomBytes, randomBytes) => ({length, type, characters}) => {
|
|
75
|
-
if (!(length >= 0 && Number.isFinite(length))) {
|
|
76
|
-
throw new TypeError('Expected a `length` to be a non-negative finite number');
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
if (type !== undefined && characters !== undefined) {
|
|
80
|
-
throw new TypeError('Expected either `type` or `characters`');
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (characters !== undefined && typeof characters !== 'string') {
|
|
84
|
-
throw new TypeError('Expected `characters` to be string');
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (!allowedTypes.has(type)) {
|
|
88
|
-
throw new TypeError(`Unknown type: ${type}`);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (type === undefined && characters === undefined) {
|
|
92
|
-
type = 'hex';
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (type === 'hex' || (type === undefined && characters === undefined)) {
|
|
96
|
-
return specialRandomBytes(Math.ceil(length * 0.5), 'hex', length); // Needs 0.5 bytes of entropy per character
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
if (type === 'base64') {
|
|
100
|
-
return specialRandomBytes(Math.ceil(length * 0.75), 'base64', length); // Needs 0.75 bytes of entropy per character
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
if (type === 'url-safe') {
|
|
104
|
-
return generateForCustomCharacters(length, urlSafeCharacters, randomBytes);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (type === 'numeric') {
|
|
108
|
-
return generateForCustomCharacters(length, numericCharacters, randomBytes);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (type === 'distinguishable') {
|
|
112
|
-
return generateForCustomCharacters(length, distinguishableCharacters, randomBytes);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if (type === 'ascii-printable') {
|
|
116
|
-
return generateForCustomCharacters(length, asciiPrintableCharacters, randomBytes);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (type === 'alphanumeric') {
|
|
120
|
-
return generateForCustomCharacters(length, alphanumericCharacters, randomBytes);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
if (characters.length === 0) {
|
|
124
|
-
throw new TypeError('Expected `characters` string length to be greater than or equal to 1');
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (characters.length > 0x1_00_00) {
|
|
128
|
-
throw new TypeError('Expected `characters` string length to be less or equal to 65536');
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return generateForCustomCharacters(length, characters, randomBytes);
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
export function createStringGenerator(specialRandomBytes, randomBytes) {
|
|
135
|
-
return createGenerator(generateForCustomCharacters, specialRandomBytes, randomBytes);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export function createAsyncStringGenerator(specialRandomBytesAsync, randomBytesAsync) {
|
|
139
|
-
return createGenerator(generateForCustomCharactersAsync, specialRandomBytesAsync, randomBytesAsync);
|
|
140
|
-
}
|