js-generate-password 1.0.0 → 1.1.0

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/package.json CHANGED
@@ -1,51 +1,59 @@
1
- {
2
- "name": "js-generate-password",
3
- "version": "1.0.0",
4
- "private": false,
5
- "description": "Password Generator for using in javascript/typescript based projects.",
6
- "Author": "Ahmad Joya <joya.abn@gmail.com>",
7
- "scripts": {
8
- "build": "rollup -c"
9
- },
10
- "repository": {
11
- "type": "git",
12
- "url": "git+https://github.com/ahmadjoya/js-generate-password.git"
13
- },
14
- "keywords": [
15
- "generate password",
16
- "js-generate-password",
17
- "password generator",
18
- "password generator",
19
- "random password generator",
20
- "simple password generator",
21
- "easy password generator",
22
- "password",
23
- "generator",
24
- "unique",
25
- "nodejs",
26
- "nextjs",
27
- "react",
28
- "reactjs",
29
- "random"
30
- ],
31
- "license": "ISC",
32
- "bugs": {
33
- "url": "https://github.com/ahmadjoya/js-generate-password/issues"
34
- },
35
- "homepage": "https://github.com/ahmadjoya/js-generate-password#readme",
36
- "type": "module",
37
- "main": "dist/index.js",
38
- "types": "dist/index.d.ts",
39
- "files": [
40
- "dist"
41
- ],
42
- "bin": "./dist/index.js",
43
- "devDependencies": {
44
- "@rollup/plugin-commonjs": "^25.0.7",
45
- "@rollup/plugin-node-resolve": "^15.2.3",
46
- "@rollup/plugin-terser": "^0.4.4",
47
- "rollup": "^4.6.1",
48
- "rollup-plugin-dts": "^6.1.0",
49
- "rollup-plugin-typescript2": "^0.36.0"
50
- }
51
- }
1
+ {
2
+ "name": "js-generate-password",
3
+ "version": "1.1.0",
4
+ "private": false,
5
+ "description": "Tiny, dependency-free, cryptographically secure password generator for JavaScript and TypeScript projects.",
6
+ "author": "Ahmad Joya <joya.abn@gmail.com>",
7
+ "license": "MIT",
8
+ "type": "module",
9
+ "sideEffects": false,
10
+ "main": "./dist/index.cjs",
11
+ "module": "./dist/index.mjs",
12
+ "types": "./dist/index.d.cts",
13
+ "exports": {
14
+ ".": {
15
+ "import": {
16
+ "types": "./dist/index.d.mts",
17
+ "default": "./dist/index.mjs"
18
+ },
19
+ "require": {
20
+ "types": "./dist/index.d.cts",
21
+ "default": "./dist/index.cjs"
22
+ }
23
+ },
24
+ "./package.json": "./package.json"
25
+ },
26
+ "files": [
27
+ "dist",
28
+ "src"
29
+ ],
30
+ "engines": {
31
+ "node": ">=18"
32
+ },
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "git+https://github.com/ahmadjoya/generate-password-lite.git"
36
+ },
37
+ "keywords": [
38
+ "password",
39
+ "password-generator",
40
+ "generate-password",
41
+ "generate-password-lite",
42
+ "js-generate-password",
43
+ "random-password",
44
+ "secure-password",
45
+ "crypto",
46
+ "csprng",
47
+ "generator",
48
+ "random",
49
+ "typescript",
50
+ "nodejs",
51
+ "react",
52
+ "nextjs",
53
+ "browser"
54
+ ],
55
+ "bugs": {
56
+ "url": "https://github.com/ahmadjoya/generate-password-lite/issues"
57
+ },
58
+ "homepage": "https://github.com/ahmadjoya/generate-password-lite#readme"
59
+ }
package/src/index.ts ADDED
@@ -0,0 +1,22 @@
1
+ import { generatePswd } from './lib/password-generator'
2
+ import { checkError } from './lib/check-options-error'
3
+ import { processOption } from './lib/process-options'
4
+ import { GenerateOptions } from './types'
5
+
6
+ /**
7
+ * Generates a random password using a cryptographically secure random source.
8
+ *
9
+ * @param options - Optional overrides. Every unset option falls back to its
10
+ * documented default.
11
+ * @returns The generated password.
12
+ */
13
+ function GeneratePassword(options: GenerateOptions = {}): string {
14
+ const resolved = processOption(options)
15
+
16
+ checkError(resolved)
17
+
18
+ return generatePswd(resolved)
19
+ }
20
+
21
+ export { GeneratePassword, type GenerateOptions }
22
+ export default GeneratePassword
@@ -0,0 +1,52 @@
1
+ import { ResolvedOptions } from '../types'
2
+
3
+ const assertCount = (value: number, name: string) => {
4
+ if (!Number.isInteger(value) || value < 0) {
5
+ throw new Error(
6
+ `generate-password-lite: \`${name}\` must be a non-negative integer, received ${value}.`
7
+ )
8
+ }
9
+ }
10
+
11
+ export const checkError = (options: ResolvedOptions) => {
12
+ const {
13
+ length,
14
+ lowercase,
15
+ uppercase,
16
+ numbers,
17
+ symbols,
18
+ minLengthLowercase,
19
+ minLengthUppercase,
20
+ minLengthNumbers,
21
+ minLengthSymbols,
22
+ } = options
23
+
24
+ if (!Number.isInteger(length) || length < 1) {
25
+ throw new Error(
26
+ `generate-password-lite: \`length\` must be a positive integer, received ${length}.`
27
+ )
28
+ }
29
+
30
+ assertCount(minLengthLowercase, 'minLengthLowercase')
31
+ assertCount(minLengthUppercase, 'minLengthUppercase')
32
+ assertCount(minLengthNumbers, 'minLengthNumbers')
33
+ assertCount(minLengthSymbols, 'minLengthSymbols')
34
+
35
+ // Lowercase, uppercase, numbers and symbols have all been turned off, so
36
+ // there is no character class left to build a password from.
37
+ if (!lowercase && !uppercase && !numbers && !symbols) {
38
+ throw new Error(
39
+ 'generate-password-lite: `lowercase`, `uppercase`, `numbers` and `symbols` are all false. No valid characters to generate the password from.'
40
+ )
41
+ }
42
+
43
+ // The guaranteed characters alone would already overflow the password.
44
+ const minimumTotal =
45
+ minLengthLowercase + minLengthUppercase + minLengthNumbers + minLengthSymbols
46
+
47
+ if (minimumTotal > length) {
48
+ throw new Error(
49
+ `generate-password-lite: the sum of the minimum character counts (${minimumTotal}) is greater than \`length\` (${length}).`
50
+ )
51
+ }
52
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Number of distinct values a Uint32 can hold.
3
+ */
4
+ const UINT32_RANGE = 0x100000000
5
+
6
+ const getWebCrypto = (): Crypto => {
7
+ const webCrypto = globalThis.crypto
8
+
9
+ if (!webCrypto || typeof webCrypto.getRandomValues !== 'function') {
10
+ throw new Error(
11
+ 'generate-password-lite: no Web Crypto implementation found. ' +
12
+ 'A secure random source is required to generate passwords. ' +
13
+ 'Use Node.js 18+, a modern browser, or polyfill `globalThis.crypto`.'
14
+ )
15
+ }
16
+
17
+ return webCrypto
18
+ }
19
+
20
+ /**
21
+ * Returns a cryptographically secure integer in the range [0, upperLimit).
22
+ *
23
+ * Uses rejection sampling so that every value is equally likely. Taking a
24
+ * plain `random % upperLimit` would bias the low end of the range whenever
25
+ * `upperLimit` is not a power of two.
26
+ */
27
+ export const generateRandomNumbers = (upperLimit: number): number => {
28
+ if (!Number.isInteger(upperLimit) || upperLimit <= 0) {
29
+ throw new RangeError(
30
+ `generate-password-lite: upperLimit must be a positive integer, received ${upperLimit}.`
31
+ )
32
+ }
33
+
34
+ const webCrypto = getWebCrypto()
35
+ const buffer = new Uint32Array(1)
36
+
37
+ // Largest multiple of upperLimit that fits in the Uint32 range. Draws at or
38
+ // above this cutoff are discarded rather than folded back into the range.
39
+ const cutoff = Math.floor(UINT32_RANGE / upperLimit) * upperLimit
40
+
41
+ let value: number
42
+ do {
43
+ webCrypto.getRandomValues(buffer)
44
+ value = buffer[0]!
45
+ } while (value >= cutoff)
46
+
47
+ return value % upperLimit
48
+ }
@@ -0,0 +1,92 @@
1
+ import { generateRandomNumbers } from './generate-random-number'
2
+ import { shuffleString } from './shuffle-string'
3
+ import { ResolvedOptions } from '../types'
4
+
5
+ const LOWERCASE_CHARS = 'abcdefghijklmnopqrstuvwxyz'
6
+ const UPPERCASE_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
7
+ const NUMBER_CHARS = '0123456789'
8
+ const SYMBOL_CHARS = "!#$%&'()*+,-./:;<=>?@[]^_{|}~"
9
+
10
+ /**
11
+ * Drops every excluded character. `String.replace` with a string pattern only
12
+ * removes the first match, so the exclusion is done with a set instead.
13
+ */
14
+ const removeExceptions = (str: string, exclude: string): string => {
15
+ if (!exclude) return str
16
+
17
+ const banned = new Set([...exclude])
18
+ return [...str].filter(char => !banned.has(char)).join('')
19
+ }
20
+
21
+ /**
22
+ * Picks `count` characters from `pool`. Throws when the caller asked for
23
+ * guaranteed characters out of a pool that `exclude` emptied.
24
+ */
25
+ const pickFrom = (pool: string, count: number, name: string): string => {
26
+ if (count === 0) return ''
27
+
28
+ if (pool.length === 0) {
29
+ throw new Error(
30
+ `generate-password-lite: \`exclude\` removed every ${name} character, but \`minLength${name[0]!.toUpperCase()}${name.slice(1)}\` is ${count}.`
31
+ )
32
+ }
33
+
34
+ let picked = ''
35
+ for (let i = 0; i < count; i++) {
36
+ picked += pool.charAt(generateRandomNumbers(pool.length))
37
+ }
38
+ return picked
39
+ }
40
+
41
+ export const generatePswd = (options: ResolvedOptions): string => {
42
+ const {
43
+ length,
44
+ lowercase,
45
+ uppercase,
46
+ numbers,
47
+ symbols,
48
+ minLengthLowercase,
49
+ minLengthUppercase,
50
+ minLengthNumbers,
51
+ minLengthSymbols,
52
+ exclude,
53
+ } = options
54
+
55
+ const lowercaseChar = removeExceptions(LOWERCASE_CHARS, exclude)
56
+ const uppercaseChar = removeExceptions(UPPERCASE_CHARS, exclude)
57
+ const numberChar = removeExceptions(NUMBER_CHARS, exclude)
58
+ const symbolChar = removeExceptions(SYMBOL_CHARS, exclude)
59
+
60
+ // Characters that must appear, so that the password satisfies every
61
+ // `minLength*` the caller asked for.
62
+ const guaranteed =
63
+ pickFrom(lowercaseChar, minLengthLowercase, 'lowercase') +
64
+ pickFrom(uppercaseChar, minLengthUppercase, 'uppercase') +
65
+ pickFrom(numberChar, minLengthNumbers, 'numbers') +
66
+ pickFrom(symbolChar, minLengthSymbols, 'symbols')
67
+
68
+ // Every character the enabled classes still allow after exclusions.
69
+ const characterPool =
70
+ (lowercase ? lowercaseChar : '') +
71
+ (uppercase ? uppercaseChar : '') +
72
+ (numbers ? numberChar : '') +
73
+ (symbols ? symbolChar : '')
74
+
75
+ const remaining = length - guaranteed.length
76
+
77
+ if (remaining > 0 && characterPool.length === 0) {
78
+ throw new Error(
79
+ 'generate-password-lite: `exclude` removed every character of every enabled class. No valid characters to generate the password from.'
80
+ )
81
+ }
82
+
83
+ let filler = ''
84
+ for (let i = 0; i < remaining; i++) {
85
+ filler += characterPool.charAt(generateRandomNumbers(characterPool.length))
86
+ }
87
+
88
+ // Shuffle the whole password, not just the guaranteed part. Shuffling only
89
+ // the guaranteed characters would pin them to the leading positions and make
90
+ // the layout of the password predictable.
91
+ return shuffleString(guaranteed + filler)
92
+ }
@@ -0,0 +1,34 @@
1
+ import { GenerateOptions, ResolvedOptions } from '../types'
2
+
3
+ const withDefault = <T>(value: T | undefined, fallback: T): T =>
4
+ typeof value === 'undefined' ? fallback : value
5
+
6
+ /**
7
+ * Fills in every unset option. Returns a new object so that the caller's
8
+ * options are never mutated.
9
+ */
10
+ export const processOption = (options: GenerateOptions): ResolvedOptions => {
11
+ const lowercase = withDefault(options.lowercase, true)
12
+ const uppercase = withDefault(options.uppercase, true)
13
+ const numbers = withDefault(options.numbers, true)
14
+ const symbols = withDefault(options.symbols, false)
15
+
16
+ // A disabled character class can never contribute a minimum, regardless of
17
+ // what the caller passed in.
18
+ return {
19
+ length: withDefault(options.length, 10),
20
+ lowercase,
21
+ uppercase,
22
+ numbers,
23
+ symbols,
24
+ exclude: withDefault(options.exclude, ''),
25
+ minLengthLowercase: lowercase
26
+ ? withDefault(options.minLengthLowercase, 1)
27
+ : 0,
28
+ minLengthUppercase: uppercase
29
+ ? withDefault(options.minLengthUppercase, 1)
30
+ : 0,
31
+ minLengthNumbers: numbers ? withDefault(options.minLengthNumbers, 1) : 0,
32
+ minLengthSymbols: symbols ? withDefault(options.minLengthSymbols, 1) : 0,
33
+ }
34
+ }
@@ -0,0 +1,21 @@
1
+ import { generateRandomNumbers } from './generate-random-number'
2
+
3
+ /**
4
+ * Fisher-Yates shuffle backed by the same cryptographically secure source
5
+ * used to pick the characters themselves.
6
+ *
7
+ * Spreads across code points rather than UTF-16 units so that a surrogate
8
+ * pair supplied through `exclude` handling is never split in half.
9
+ */
10
+ export const shuffleString = (str: string): string => {
11
+ const chars = [...str]
12
+
13
+ for (let i = chars.length - 1; i > 0; i--) {
14
+ const j = generateRandomNumbers(i + 1)
15
+ const tmp = chars[i]!
16
+ chars[i] = chars[j]!
17
+ chars[j] = tmp
18
+ }
19
+
20
+ return chars.join('')
21
+ }
package/src/types.ts ADDED
@@ -0,0 +1,57 @@
1
+ export interface GenerateOptions {
2
+ /**
3
+ * Length of the generated password.
4
+ * @default 10
5
+ */
6
+ length?: number
7
+ /**
8
+ * Should the password include lowercase characters.
9
+ * @default true
10
+ */
11
+ lowercase?: boolean
12
+ /**
13
+ * Should the password include uppercase characters.
14
+ * @default true
15
+ */
16
+ uppercase?: boolean
17
+ /**
18
+ * Should the password include numbers.
19
+ * @default true
20
+ */
21
+ numbers?: boolean
22
+ /**
23
+ * Should the password include symbol characters.
24
+ * @default false
25
+ */
26
+ symbols?: boolean
27
+ /**
28
+ * Characters to exclude from the password.
29
+ * @default ""
30
+ */
31
+ exclude?: string
32
+ /**
33
+ * Minimum number of lowercase characters. Forced to 0 when `lowercase` is false.
34
+ * @default 1 when `lowercase` is true, otherwise 0
35
+ */
36
+ minLengthLowercase?: number
37
+ /**
38
+ * Minimum number of uppercase characters. Forced to 0 when `uppercase` is false.
39
+ * @default 1 when `uppercase` is true, otherwise 0
40
+ */
41
+ minLengthUppercase?: number
42
+ /**
43
+ * Minimum number of numeric characters. Forced to 0 when `numbers` is false.
44
+ * @default 1 when `numbers` is true, otherwise 0
45
+ */
46
+ minLengthNumbers?: number
47
+ /**
48
+ * Minimum number of symbol characters. Forced to 0 when `symbols` is false.
49
+ * @default 1 when `symbols` is true, otherwise 0
50
+ */
51
+ minLengthSymbols?: number
52
+ }
53
+
54
+ /**
55
+ * Every option resolved to a concrete value by `processOption`.
56
+ */
57
+ export type ResolvedOptions = Required<GenerateOptions>
package/dist/index.js DELETED
@@ -1 +0,0 @@
1
- "use strict";var e=function(e){return Math.floor(Math.random()*e)},n=function(n){var t="",s="",o=n.length,a=n.lowercase,m=n.uppercase,h=n.numbers,i=n.symbols,l=n.minLengthLowercase,c=n.minLengthUppercase,g=n.minLengthNumbers,u=n.minLengthSymbols,L=n.exclude,p="abcdefghijklmnopqrstuvwxyz";p=r(p,L);var b="ABCDEFGHIJKLMNOPQRSTUVWXYZ";b=r(b,L);var d="0123456789";d=r(d,L);var v="!#$%&'()*+,-./:;<=>?@[]^_{|}~";v=r(v,L);for(var w=p.length,f=0;f<l;f++)s+=p.charAt(e(w));w=b.length;for(f=0;f<c;f++)s+=b.charAt(e(w));w=d.length;for(f=0;f<g;f++)s+=d.charAt(e(w));w=v.length;for(f=0;f<u;f++)s+=v.charAt(e(w));t+=function(e){for(var n=e.split(""),r=n.length-1;r>0;r--){var t=Math.floor(Math.random()*(r+1)),s=n[r];n[r]=n[t],n[t]=s}return n.join("")}(s);var y="";y=a?y+p:y,y=m?y+b:y,y=h?y+d:y,y=i?y+v:y;var N=o-t.length;w=y.length;for(f=0;f<N;f++)t+=y.charAt(e(w));return t},r=function(e,n){return null==n||n.split("").forEach((function(n){e=e.replace(n,"")})),e},t=function(e){var n=e.length,r=e.lowercase,t=e.uppercase,s=e.numbers,o=e.symbols;if(e.minLengthLowercase+e.minLengthUppercase+e.minLengthNumbers+e.minLengthSymbols>n)throw new Error("Sum of Minimum Characters in the passwords greater than the length of the Password to be generated.");if(0==r&&0==t&&0==s&&0==o)throw new Error("Alphabets, Numbers and Symbols are all set to False. No valid Characters to generate the Password.")},s=function(e){return e.length=void 0===e.length?10:e.length,e.lowercase=void 0===e.lowercase||e.lowercase,e.uppercase=void 0===e.uppercase||e.uppercase,e.numbers=void 0===e.numbers||e.numbers,e.symbols=void 0!==e.symbols&&e.symbols,e.lowercase?e.minLengthLowercase=void 0===e.minLengthLowercase?1:e.minLengthLowercase:e.minLengthLowercase=0,e.uppercase?e.minLengthUppercase=void 0===e.minLengthUppercase?1:e.minLengthUppercase:e.minLengthUppercase=0,e.numbers?e.minLengthNumbers=void 0===e.minLengthNumbers?1:e.minLengthNumbers:e.minLengthNumbers=0,e.symbols?e.minLengthSymbols=void 0===e.minLengthSymbols?1:e.minLengthSymbols:e.minLengthSymbols=0,e.exclude=void 0===e.exclude?"":e.exclude,e};exports.GeneratePassword=function(e){return e?(e=s(e),t(e),n(e)):(e=s({length:10,lowercase:!0,uppercase:!0,numbers:!0,symbols:!1,exclude:"",minLengthLowercase:1,minLengthUppercase:1,minLengthNumbers:1,minLengthSymbols:0}),t(e),n(e))};
@@ -1,2 +0,0 @@
1
- import { GenerateOptions } from '../types';
2
- export declare const checkError: (options: GenerateOptions) => void;
@@ -1 +0,0 @@
1
- export declare const generateRandomNumbers: (upperLimit: number) => number;
@@ -1,2 +0,0 @@
1
- import { GenerateOptions } from '../types';
2
- export declare const generatePswd: (options: GenerateOptions) => string;
@@ -1,2 +0,0 @@
1
- import { GenerateOptions } from '../types';
2
- export declare const processOption: (options: GenerateOptions) => GenerateOptions;
@@ -1 +0,0 @@
1
- export declare const shuffleString: (str: string) => string;
package/dist/types.d.ts DELETED
@@ -1,58 +0,0 @@
1
- interface GenerateOptions {
2
- /**
3
- * lenght of the password
4
- * @default 10
5
- */
6
- length?: number
7
- /**
8
- * Should the password include lowercase characters
9
- * @default true
10
- */
11
- lowercase?: boolean
12
- /**
13
- * Should the password include uppercase characters
14
- * @default true
15
- */
16
- uppercase?: boolean
17
- /**
18
- * Should the password include numbers
19
- * @default true
20
- */
21
- numbers?: boolean
22
- /**
23
- * Should the password include symbol characters
24
- * @default false
25
- */
26
- symbols?: boolean
27
- /**
28
- * List of characters to be excluded from the password
29
- * @default ""
30
- */
31
- exclude?: string
32
- /**
33
- * min lentgh of lowercase character
34
- * @default 1
35
- */
36
- minLengthLowercase?: number
37
- /**
38
- * min lentgh of uppercase character
39
- * @default 1
40
- */
41
- minLengthUppercase?: number
42
- /**
43
- * min length of numbers
44
- * @default 1
45
- */
46
- minLengthNumbers?: number
47
- /**
48
- * min length of symbols
49
- * @default 0
50
- */
51
- minLengthSymbols?: number
52
- }
53
-
54
- declare namespace GeneratePassword {}
55
-
56
- declare function GeneratePassword(options?: GenerateOptions): string
57
-
58
- export { type GenerateOptions, GeneratePassword };