Skip to content

Commit d92da42

Browse files
authored
Merge pull request #1 from erfanium/main
Remove std/node dependency
2 parents 94b0477 + 576df69 commit d92da42

File tree

4 files changed

+55
-82
lines changed

4 files changed

+55
-82
lines changed

README.md

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ Deno module based on [crypto-random-string](https://github.com/sindresorhus/cryp
77
## Import Module
88

99
```typescript
10-
import { cryptoRandomString, cryptoRandomStringAsync } from "https://deno.land/x/[email protected]/mod.ts"
10+
import { cryptoRandomString } from "https://deno.land/x/[email protected]/mod.ts"
1111
// or
12-
import { cryptoRandomString, cryptoRandomStringAsync } from "https://github.com/piyush-bhatt/crypto-random-string/raw/main/mod.ts"
12+
import { cryptoRandomString } from "https://github.com/piyush-bhatt/crypto-random-string/raw/main/mod.ts"
1313
```
1414

1515
## Usage
@@ -21,36 +21,20 @@ import { cryptoRandomString, cryptoRandomStringAsync } from "https://github.com/
2121

2222
cryptoRandomString({length: 10}); // '0696cb9e70'
2323

24-
await cryptoRandomStringAsync({length: 10}); // 'c8d4b0140d'
25-
2624
cryptoRandomString({length: 10, type: 'base64'}); // 'dw3mgWC5uO'
2725

28-
await cryptoRandomStringAsync({length: 10, type: 'base64'}); // 'k6ALljZx+E'
29-
3026
cryptoRandomString({length: 10, type: 'url-safe'}); // '0pN1Y2Jz.X'
3127

32-
await cryptoRandomStringAsync({length: 10, type: 'url-safe'}); // '7.F5oBY9Qy'
33-
3428
cryptoRandomString({length: 10, type: 'numeric'}); // '1639380067'
3529

36-
await cryptoRandomStringAsync({length: 10, type: 'numeric'}); // '0923903115'
37-
3830
cryptoRandomString({length: 6, type: 'distinguishable'}); // 'H4HH5D'
3931

40-
await cryptoRandomStringAsync({length: 6, type: 'distinguishable'}); // 'D2Y254'
41-
4232
cryptoRandomString({length: 10, type: 'ascii-printable'}); // '#I&J.GP./9'
4333

44-
await cryptoRandomStringAsync({length: 10, type: 'ascii-printable'}); // '7t%FxZkyL('
45-
4634
cryptoRandomString({length: 10, type: 'alphanumeric'}); // 'ZtgC2J6aU5'
4735

48-
await cryptoRandomStringAsync({length: 10, type: 'alphanumeric'}); // 'FELQVN9S8H'
49-
5036
cryptoRandomString({length: 10, characters: 'abc'}); // 'abcabccbcc'
5137

52-
await cryptoRandomStringAsync({length: 10, characters: 'abc'}); // 'abcbbbacbb'
53-
5438
```
5539

5640
## API
@@ -59,9 +43,6 @@ await cryptoRandomStringAsync({length: 10, characters: 'abc'}); // 'abcbbbacbb'
5943

6044
Returns a randomized string. [Hex](https://en.wikipedia.org/wiki/Hexadecimal) by default.
6145

62-
### cryptoRandomStringAsync(options)
63-
64-
Returns a promise which resolves to a randomized string. [Hex](https://en.wikipedia.org/wiki/Hexadecimal) by default.
6546

6647
#### options
6748

cryptoRandomString.ts

Lines changed: 50 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
import { randomBytes } from "./deps.ts";
2-
import { promisify } from "./deps.ts";
31
import {
42
ALLOWED_TYPES,
53
ALPHANUMERIC_CHARACTERS,
@@ -8,40 +6,49 @@ import {
86
NUMERIC_CHARACTERS,
97
URL_SAFE_CHARACTERS,
108
} from "./constants.ts";
9+
import { encodeToBase64, encodeToHex } from "./deps.ts";
1110

12-
const randomBytesAsync = promisify(randomBytes);
13-
14-
const generateForCustomCharacters = (length: number, characters: string[]) => {
15-
// Generating entropy is faster than complex math operations, so we use the simplest way
16-
const characterCount = characters.length;
17-
const maxValidSelector =
18-
(Math.floor(0x10000 / characterCount) * characterCount) - 1; // Using values above this will ruin distribution when using modular division
19-
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
20-
let string = "";
21-
let stringLength = 0;
22-
23-
while (stringLength < length) { // In case we had many bad values, which may happen for character sets of size above 0x8000 but close to it
24-
const entropy = randomBytes(entropyLength);
25-
let entropyPosition = 0;
11+
export interface GenerateRandomBytes {
12+
(
13+
byteLength: number,
14+
type: "hex" | "base64",
15+
length: number,
16+
): string;
17+
}
18+
19+
export interface GenerateForCustomCharacters {
20+
(length: number, characters: string[]): string;
21+
}
22+
23+
export const MAX_RANDOM_VALUES = 65536;
24+
export const MAX_SIZE = 4294967295;
25+
26+
function randomBytes(size: number) {
27+
if (size > MAX_SIZE) {
28+
throw new RangeError(
29+
`The value of "size" is out of range. It must be >= 0 && <= ${MAX_SIZE}. Received ${size}`,
30+
);
31+
}
2632

27-
while (entropyPosition < entropyLength && stringLength < length) {
28-
const entropyValue = entropy.readUInt16LE(entropyPosition);
29-
entropyPosition += 2;
30-
if (entropyValue > maxValidSelector) { // Skip values which will ruin distribution when using modular division
31-
continue;
32-
}
33+
const bytes = new Uint8Array(size);
3334

34-
string += characters[entropyValue % characterCount];
35-
stringLength++;
35+
//Work around for getRandomValues max generation
36+
if (size > MAX_RANDOM_VALUES) {
37+
for (let generated = 0; generated < size; generated += MAX_RANDOM_VALUES) {
38+
crypto.getRandomValues(
39+
bytes.subarray(generated, generated + MAX_RANDOM_VALUES),
40+
);
3641
}
42+
} else {
43+
crypto.getRandomValues(bytes);
3744
}
3845

39-
return string;
40-
};
46+
return bytes;
47+
}
4148

42-
const generateForCustomCharactersAsync = async (
43-
length: number,
44-
characters: string[],
49+
const generateForCustomCharacters: GenerateForCustomCharacters = (
50+
length,
51+
characters,
4552
) => {
4653
// Generating entropy is faster than complex math operations, so we use the simplest way
4754
const characterCount = characters.length;
@@ -52,11 +59,16 @@ const generateForCustomCharactersAsync = async (
5259
let stringLength = 0;
5360

5461
while (stringLength < length) { // In case we had many bad values, which may happen for character sets of size above 0x8000 but close to it
55-
const entropy = await randomBytesAsync(entropyLength); // eslint-disable-line no-await-in-loop
62+
const entropy = randomBytes(entropyLength);
5663
let entropyPosition = 0;
5764

5865
while (entropyPosition < entropyLength && stringLength < length) {
59-
const entropyValue = entropy.readUInt16LE(entropyPosition);
66+
const entropyValue = new DataView(
67+
entropy.buffer,
68+
entropy.byteOffset,
69+
entropy.byteLength,
70+
)
71+
.getUint16(entropyPosition, true);
6072
entropyPosition += 2;
6173
if (entropyValue > maxValidSelector) { // Skip values which will ruin distribution when using modular division
6274
continue;
@@ -70,24 +82,15 @@ const generateForCustomCharactersAsync = async (
7082
return string;
7183
};
7284

73-
const generateRandomBytes = (
74-
byteLength: number,
75-
type: string,
76-
length: number,
77-
) => randomBytes(byteLength).toString(type).slice(0, length);
78-
79-
const generateRandomBytesAsync = async (
80-
byteLength: number,
81-
type: string,
82-
length: number,
83-
) => {
84-
const buffer = await randomBytesAsync(byteLength);
85-
return buffer.toString(type).slice(0, length);
85+
const generateRandomBytes: GenerateRandomBytes = (byteLength, type, length) => {
86+
const bytes = randomBytes(byteLength);
87+
const str = type === "base64" ? encodeToBase64(bytes) : encodeToHex(bytes);
88+
return str.slice(0, length);
8689
};
8790

8891
const createGenerator = (
89-
generateForCustomCharacters: Function,
90-
generateRandomBytes: Function,
92+
generateForCustomCharacters: GenerateForCustomCharacters,
93+
generateRandomBytes: GenerateRandomBytes,
9194
) =>
9295
(
9396
{ length, type, characters }: {
@@ -165,9 +168,5 @@ const cryptoRandomString = createGenerator(
165168
generateForCustomCharacters,
166169
generateRandomBytes,
167170
);
168-
const cryptoRandomStringAsync = createGenerator(
169-
generateForCustomCharactersAsync,
170-
generateRandomBytesAsync,
171-
);
172171

173-
export { cryptoRandomString, cryptoRandomStringAsync };
172+
export { cryptoRandomString };

deps.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
export { randomBytes } from "https://deno.land/std@0.83.0/node/crypto.ts";
2-
export { promisify } from "https://deno.land/std@0.83.0/node/util.ts";
1+
export { encodeToString as encodeToHex } from "https://deno.land/std@0.99.0/encoding/hex.ts";
2+
export { encode as encodeToBase64 } from "https://deno.land/std@0.99.0/encoding/base64.ts";

mod_test.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { assertEquals, assertMatch, assertThrows } from "./test_deps.ts";
2-
import { cryptoRandomString, cryptoRandomStringAsync } from "./mod.ts";
2+
import { cryptoRandomString } from "./mod.ts";
33

44
// Probabilistic, result is always less than or equal to actual set size, chance it is less is below 1e-256 for sizes up to 32656
55
const generatedCharacterSetSize = (
@@ -25,13 +25,6 @@ Deno.test("main", () => {
2525
assertEquals(generatedCharacterSetSize({}, 16), 16);
2626
});
2727

28-
Deno.test("async", async () => {
29-
assertEquals((await cryptoRandomStringAsync({ length: 0 })).length, 0);
30-
assertEquals((await cryptoRandomStringAsync({ length: 10 })).length, 10);
31-
assertEquals((await cryptoRandomStringAsync({ length: 100 })).length, 100);
32-
assertMatch(await cryptoRandomStringAsync({ length: 100 }), /^[a-f\d]*$/);
33-
});
34-
3528
Deno.test("hex", () => {
3629
assertEquals(cryptoRandomString({ length: 0, type: "hex" }).length, 0);
3730
assertEquals(cryptoRandomString({ length: 10, type: "hex" }).length, 10);

0 commit comments

Comments
 (0)