Socket
Socket
Sign inDemoInstall

crypto-random-string

Package Overview
Dependencies
1
Maintainers
1
Versions
10
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 4.0.0 to 5.0.0

browser.js

54

index.d.ts

@@ -71,40 +71,36 @@ import {MergeExclusive} from 'type-fest';

declare const cryptoRandomString: {
/**
Generate a [cryptographically strong](https://en.wikipedia.org/wiki/Strong_cryptography) random string.
/**
Generate a [cryptographically strong](https://en.wikipedia.org/wiki/Strong_cryptography) random string.
@returns A randomized string.
@returns A randomized string.
@example
```
import cryptoRandomString from 'crypto-random-string';
@example
```
import cryptoRandomString from 'crypto-random-string';
cryptoRandomString({length: 10});
//=> '2cf05d94db'
```
*/
(options: Options): string;
cryptoRandomString({length: 10});
//=> '2cf05d94db'
```
*/
export default function cryptoRandomString(options: Options): string;
/**
Asynchronously generate a [cryptographically strong](https://en.wikipedia.org/wiki/Strong_cryptography) random string.
/**
Asynchronously generate a [cryptographically strong](https://en.wikipedia.org/wiki/Strong_cryptography) random string.
For most use-cases, there's really no good reason to use this async version. From the Node.js docs:
For most use-cases, there's really no good reason to use this async version. From the Node.js docs:
> 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.
> 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.
In general, anything async comes with some overhead on it's own.
In general, anything async comes with some overhead on it's own.
@returns A promise which resolves to a randomized string.
@returns A promise which resolves to a randomized string.
@example
```
import cryptoRandomString from 'crypto-random-string';
@example
```
import {cryptoRandomStringAsync} from 'crypto-random-string';
await cryptoRandomString.async({length: 10});
//=> '2cf05d94db'
```
*/
async(options: Options): Promise<string>;
};
export default cryptoRandomString;
await cryptoRandomStringAsync({length: 10});
//=> '2cf05d94db'
```
*/
export function cryptoRandomStringAsync(options: Options): Promise<string>;

@@ -1,148 +0,13 @@

import {promisify} from 'util';
import crypto from 'crypto';
// TODO: When targeting Node.js 16, remove `cryptoRandomStringAsync` and use `crypto.webcrypto.getRandomValues` to interop with the browser code.
// TODO: Later, when targeting Node.js 18, only use the browser code
import {promisify} from 'node:util';
import {randomBytes} from 'node:crypto';
import {createStringGenerator, createAsyncStringGenerator} from './core.js';
const randomBytesAsync = promisify(crypto.randomBytes);
const randomBytesAsync = promisify(randomBytes);
const urlSafeCharacters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~'.split('');
const numericCharacters = '0123456789'.split('');
const distinguishableCharacters = 'CDEHKMPRTUWXY012458'.split('');
const asciiPrintableCharacters = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~'.split('');
const alphanumericCharacters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'.split('');
const generateForCustomCharacters = (length, characters) => {
// Generating entropy is faster than complex math operations, so we use the simplest way
const characterCount = characters.length;
const maxValidSelector = (Math.floor(0x10000 / characterCount) * characterCount) - 1; // Using values above this will ruin distribution when using modular division
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
let string = '';
let stringLength = 0;
while (stringLength < length) { // In case we had many bad values, which may happen for character sets of size above 0x8000 but close to it
const entropy = crypto.randomBytes(entropyLength);
let entropyPosition = 0;
while (entropyPosition < entropyLength && stringLength < length) {
const entropyValue = entropy.readUInt16LE(entropyPosition);
entropyPosition += 2;
if (entropyValue > maxValidSelector) { // Skip values which will ruin distribution when using modular division
continue;
}
string += characters[entropyValue % characterCount];
stringLength++;
}
}
return string;
};
const generateForCustomCharactersAsync = async (length, characters) => {
// Generating entropy is faster than complex math operations, so we use the simplest way
const characterCount = characters.length;
const maxValidSelector = (Math.floor(0x10000 / characterCount) * characterCount) - 1; // Using values above this will ruin distribution when using modular division
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
let string = '';
let stringLength = 0;
while (stringLength < length) { // In case we had many bad values, which may happen for character sets of size above 0x8000 but close to it
const entropy = await randomBytesAsync(entropyLength); // eslint-disable-line no-await-in-loop
let entropyPosition = 0;
while (entropyPosition < entropyLength && stringLength < length) {
const entropyValue = entropy.readUInt16LE(entropyPosition);
entropyPosition += 2;
if (entropyValue > maxValidSelector) { // Skip values which will ruin distribution when using modular division
continue;
}
string += characters[entropyValue % characterCount];
stringLength++;
}
}
return string;
};
const generateRandomBytes = (byteLength, type, length) => crypto.randomBytes(byteLength).toString(type).slice(0, length);
const generateRandomBytesAsync = async (byteLength, type, length) => {
export default createStringGenerator((byteLength, type, length) => randomBytes(byteLength).toString(type).slice(0, length), size => new Uint8Array(randomBytes(size)));
export const cryptoRandomStringAsync = createAsyncStringGenerator(async (byteLength, type, length) => {
const buffer = await randomBytesAsync(byteLength);
return buffer.toString(type).slice(0, length);
};
const allowedTypes = new Set([
undefined,
'hex',
'base64',
'url-safe',
'numeric',
'distinguishable',
'ascii-printable',
'alphanumeric'
]);
const createGenerator = (generateForCustomCharacters, generateRandomBytes) => ({length, type, characters}) => {
if (!(length >= 0 && Number.isFinite(length))) {
throw new TypeError('Expected a `length` to be a non-negative finite number');
}
if (type !== undefined && characters !== undefined) {
throw new TypeError('Expected either `type` or `characters`');
}
if (characters !== undefined && typeof characters !== 'string') {
throw new TypeError('Expected `characters` to be string');
}
if (!allowedTypes.has(type)) {
throw new TypeError(`Unknown type: ${type}`);
}
if (type === undefined && characters === undefined) {
type = 'hex';
}
if (type === 'hex' || (type === undefined && characters === undefined)) {
return generateRandomBytes(Math.ceil(length * 0.5), 'hex', length); // Need 0.5 byte entropy per character
}
if (type === 'base64') {
return generateRandomBytes(Math.ceil(length * 0.75), 'base64', length); // Need 0.75 byte of entropy per character
}
if (type === 'url-safe') {
return generateForCustomCharacters(length, urlSafeCharacters);
}
if (type === 'numeric') {
return generateForCustomCharacters(length, numericCharacters);
}
if (type === 'distinguishable') {
return generateForCustomCharacters(length, distinguishableCharacters);
}
if (type === 'ascii-printable') {
return generateForCustomCharacters(length, asciiPrintableCharacters);
}
if (type === 'alphanumeric') {
return generateForCustomCharacters(length, alphanumericCharacters);
}
if (characters.length === 0) {
throw new TypeError('Expected `characters` string length to be greater than or equal to 1');
}
if (characters.length > 0x10000) {
throw new TypeError('Expected `characters` string length to be less or equal to 65536');
}
return generateForCustomCharacters(length, characters.split(''));
};
const cryptoRandomString = createGenerator(generateForCustomCharacters, generateRandomBytes);
cryptoRandomString.async = createGenerator(generateForCustomCharactersAsync, generateRandomBytesAsync);
export default cryptoRandomString;
}, async size => new Uint8Array(await randomBytesAsync(size)));
{
"name": "crypto-random-string",
"version": "4.0.0",
"version": "5.0.0",
"description": "Generate a cryptographically strong random string",

@@ -14,5 +14,9 @@ "license": "MIT",

"type": "module",
"exports": "./index.js",
"exports": {
"types": "./index.d.ts",
"node": "./index.js",
"browser": "./browser.js"
},
"engines": {
"node": ">=12"
"node": ">=14.16"
},

@@ -24,2 +28,4 @@ "scripts": {

"index.js",
"browser.js",
"core.js",
"index.d.ts"

@@ -44,9 +50,10 @@ ],

"dependencies": {
"type-fest": "^1.0.1"
"type-fest": "^2.12.2"
},
"devDependencies": {
"ava": "^3.15.0",
"tsd": "^0.14.0",
"xo": "^0.38.2"
"ava": "^4.2.0",
"dot-prop": "^7.2.0",
"tsd": "^0.20.0",
"xo": "^0.48.0"
}
}

@@ -7,7 +7,9 @@ # crypto-random-string

Works in Node.js and browsers.
## Install
```sh
npm install crypto-random-string
```
$ npm install crypto-random-string
```

@@ -50,3 +52,3 @@ ## Usage

### cryptoRandomString.async(options)
### cryptoRandomStringAsync(options)

@@ -61,2 +63,9 @@ Returns a promise which resolves to a randomized string. [Hex](https://en.wikipedia.org/wiki/Hexadecimal) by default.

```js
import {cryptoRandomStringAsync} from 'crypto-random-string';
await cryptoRandomStringAsync({length: 10});
//=> '2cf05d94db'
```
#### options

@@ -63,0 +72,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc