@wener/common 1.0.2 → 1.0.4
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/lib/cn/DivisionCode.js +311 -0
- package/lib/cn/DivisionCode.js.map +1 -0
- package/lib/cn/Mod11Checksum.js +42 -0
- package/lib/cn/Mod11Checksum.js.map +1 -0
- package/lib/cn/Mod31Checksum.js +48 -0
- package/lib/cn/Mod31Checksum.js.map +1 -0
- package/lib/cn/ResidentIdentityCardNumber.js +50 -0
- package/lib/cn/ResidentIdentityCardNumber.js.map +1 -0
- package/lib/cn/UnifiedSocialCreditCode.js +118 -0
- package/lib/cn/UnifiedSocialCreditCode.js.map +1 -0
- package/lib/cn/formatDate.js +15 -0
- package/lib/cn/formatDate.js.map +1 -0
- package/lib/cn/index.js +4 -0
- package/lib/cn/index.js.map +1 -0
- package/lib/cn/parseSex.js +22 -0
- package/lib/cn/parseSex.js.map +1 -0
- package/lib/cn/types.d.js +8 -0
- package/lib/cn/types.d.js.map +1 -0
- package/lib/data/formatSort.js +15 -0
- package/lib/data/formatSort.js.map +1 -0
- package/lib/data/index.js +4 -0
- package/lib/data/index.js.map +1 -0
- package/lib/data/maybeNumber.js +22 -0
- package/lib/data/maybeNumber.js.map +1 -0
- package/lib/data/parseSort.js +95 -0
- package/lib/data/parseSort.js.map +1 -0
- package/lib/data/resolvePagination.js +36 -0
- package/lib/data/resolvePagination.js.map +1 -0
- package/lib/data/types.d.js +3 -0
- package/lib/data/types.d.js.map +1 -0
- package/lib/index.js +6 -2
- package/lib/index.js.map +1 -1
- package/lib/jsonschema/JsonSchema.js +4 -4
- package/lib/jsonschema/JsonSchema.js.map +1 -1
- package/lib/jsonschema/types.d.js.map +1 -1
- package/lib/meta/defineFileType.js +44 -0
- package/lib/meta/defineFileType.js.map +1 -0
- package/lib/meta/defineInit.js.map +1 -1
- package/lib/meta/defineMetadata.js +14 -3
- package/lib/meta/defineMetadata.js.map +1 -1
- package/lib/meta/index.js +1 -0
- package/lib/meta/index.js.map +1 -1
- package/lib/password/PHC.js +8 -8
- package/lib/password/PHC.js.map +1 -1
- package/lib/password/Password.js.map +1 -1
- package/lib/password/createArgon2PasswordAlgorithm.js.map +1 -1
- package/lib/password/createBase64PasswordAlgorithm.js.map +1 -1
- package/lib/password/createBcryptPasswordAlgorithm.js.map +1 -1
- package/lib/password/createPBKDF2PasswordAlgorithm.js.map +1 -1
- package/lib/password/createScryptPasswordAlgorithm.js.map +1 -1
- package/lib/search/AdvanceSearch.js.map +1 -1
- package/lib/search/formatAdvanceSearch.js +1 -1
- package/lib/search/formatAdvanceSearch.js.map +1 -1
- package/lib/search/optimizeAdvanceSearch.js.map +1 -1
- package/lib/search/parseAdvanceSearch.js.map +1 -1
- package/lib/search/parser.d.js.map +1 -1
- package/lib/search/parser.js +380 -76
- package/lib/search/parser.js.map +1 -1
- package/lib/search/types.d.js.map +1 -1
- package/lib/tools/renderJsonSchemaToMarkdownDoc.js.map +1 -1
- package/package.json +14 -5
- package/src/cn/DivisionCode.test.ts +43 -0
- package/src/cn/DivisionCode.ts +209 -0
- package/src/cn/Mod11Checksum.ts +24 -0
- package/src/cn/Mod31Checksum.ts +36 -0
- package/src/cn/ResidentIdentityCardNumber.test.ts +17 -0
- package/src/cn/ResidentIdentityCardNumber.ts +96 -0
- package/src/cn/UnifiedSocialCreditCode.test.ts +16 -0
- package/src/cn/UnifiedSocialCreditCode.ts +143 -0
- package/src/cn/__snapshots__/ResidentIdentityCardNumber.test.ts.snap +15 -0
- package/src/cn/__snapshots__/UnifiedSocialCreditCode.test.ts.snap +41 -0
- package/src/cn/formatDate.ts +12 -0
- package/src/cn/index.ts +3 -0
- package/src/cn/parseSex.ts +13 -0
- package/src/cn/types.d.ts +51 -0
- package/src/data/formatSort.test.ts +13 -0
- package/src/data/formatSort.ts +18 -0
- package/src/data/index.ts +5 -0
- package/src/data/maybeNumber.ts +23 -0
- package/src/data/parseSort.test.ts +67 -0
- package/src/data/parseSort.ts +108 -0
- package/src/data/resolvePagination.test.ts +58 -0
- package/src/data/resolvePagination.ts +60 -0
- package/src/data/types.d.ts +33 -0
- package/src/index.ts +8 -2
- package/src/jsonschema/JsonSchema.test.ts +13 -22
- package/src/jsonschema/JsonSchema.ts +145 -177
- package/src/jsonschema/types.d.ts +151 -161
- package/src/meta/defineFileType.tsx +68 -0
- package/src/meta/defineInit.ts +32 -53
- package/src/meta/defineMetadata.test.ts +5 -7
- package/src/meta/defineMetadata.ts +35 -40
- package/src/meta/index.ts +2 -0
- package/src/password/PHC.test.ts +186 -277
- package/src/password/PHC.ts +243 -243
- package/src/password/Password.test.ts +38 -50
- package/src/password/Password.ts +73 -95
- package/src/password/createArgon2PasswordAlgorithm.ts +65 -69
- package/src/password/createBase64PasswordAlgorithm.ts +9 -9
- package/src/password/createBcryptPasswordAlgorithm.ts +20 -22
- package/src/password/createPBKDF2PasswordAlgorithm.ts +49 -61
- package/src/password/createScryptPasswordAlgorithm.ts +48 -59
- package/src/search/AdvanceSearch.test.ts +136 -143
- package/src/search/AdvanceSearch.ts +6 -6
- package/src/search/__snapshots__/AdvanceSearch.test.ts.snap +3 -3
- package/src/search/formatAdvanceSearch.ts +44 -53
- package/src/search/optimizeAdvanceSearch.ts +70 -83
- package/src/search/parseAdvanceSearch.ts +16 -19
- package/src/search/parser.d.ts +3 -3
- package/src/search/parser.js +325 -73
- package/src/search/parser.peggy +42 -9
- package/src/search/types.d.ts +28 -54
- package/src/tools/renderJsonSchemaToMarkdownDoc.ts +69 -69
- package/lib/normalizePagination.js +0 -14
- package/lib/normalizePagination.js.map +0 -1
- package/lib/parseSort.js +0 -91
- package/lib/parseSort.js.map +0 -1
- package/src/normalizePagination.ts +0 -25
- package/src/parseSort.test.ts +0 -42
- package/src/parseSort.ts +0 -115
package/src/password/Password.ts
CHANGED
|
@@ -3,111 +3,89 @@ import { createPBKDF2PasswordAlgorithm } from './createPBKDF2PasswordAlgorithm';
|
|
|
3
3
|
import { PHC } from './PHC';
|
|
4
4
|
|
|
5
5
|
export namespace Password {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
6
|
+
export interface ParsedPassword {
|
|
7
|
+
id: string;
|
|
8
|
+
version?: number;
|
|
9
|
+
params?: Record<string, string | number>;
|
|
10
|
+
salt?: Uint8Array;
|
|
11
|
+
hash?: Uint8Array;
|
|
12
|
+
}
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
readonly ids?: string[];
|
|
23
|
-
hash(password: string, opts?: PasswordAlgorithmHashOptions): Promise<string>;
|
|
24
|
-
verify(password: string, hash: string, opts: PasswordAlgorithmVerifyOptions): Promise<boolean>;
|
|
25
|
-
};
|
|
14
|
+
type PasswordAlgorithmHashOptions = { rounds?: number; salt?: Uint8Array; id?: string };
|
|
15
|
+
type PasswordAlgorithmVerifyOptions = ParsedPassword;
|
|
16
|
+
export type PasswordAlgorithm = {
|
|
17
|
+
readonly name: string;
|
|
18
|
+
readonly ids?: string[];
|
|
19
|
+
hash(password: string, opts?: PasswordAlgorithmHashOptions): Promise<string>;
|
|
20
|
+
verify(password: string, hash: string, opts: PasswordAlgorithmVerifyOptions): Promise<boolean>;
|
|
21
|
+
};
|
|
26
22
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
23
|
+
const Algorithms: Record<string, string | PasswordAlgorithm> = {
|
|
24
|
+
1: 'md5',
|
|
25
|
+
'2a': 'bcrypt', // original
|
|
26
|
+
'2b': 'bcrypt', // February 2014
|
|
27
|
+
'2x': 'bcrypt', // June 2011
|
|
28
|
+
'2y': 'bcrypt', // June 2011
|
|
29
|
+
5: 'sha256',
|
|
30
|
+
6: 'sha512',
|
|
31
|
+
7: 'scrypt',
|
|
32
|
+
};
|
|
33
|
+
let DefaultAlgorithm: string = '6';
|
|
38
34
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
35
|
+
export function setDefaultAlgorithm(algorithm: string) {
|
|
36
|
+
Errors.BadRequest.check(Algorithms[algorithm], `Unknown algorithm ${algorithm}`);
|
|
37
|
+
DefaultAlgorithm = algorithm;
|
|
38
|
+
}
|
|
43
39
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
export function getDefaultAlgorithm() {
|
|
41
|
+
return DefaultAlgorithm;
|
|
42
|
+
}
|
|
47
43
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
44
|
+
export function addAlgorithm(algorithm: PasswordAlgorithm) {
|
|
45
|
+
Algorithms[algorithm.name] = algorithm;
|
|
46
|
+
if (algorithm.ids) {
|
|
47
|
+
for (const id of algorithm.ids) {
|
|
48
|
+
Algorithms[id] = algorithm;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
56
52
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
id: 'sha256',
|
|
60
|
-
digest: 'SHA-256',
|
|
61
|
-
}),
|
|
62
|
-
);
|
|
63
|
-
addAlgorithm(
|
|
64
|
-
createPBKDF2PasswordAlgorithm({
|
|
65
|
-
id: 'sha512',
|
|
66
|
-
digest: 'SHA-512',
|
|
67
|
-
}),
|
|
68
|
-
);
|
|
53
|
+
addAlgorithm(createPBKDF2PasswordAlgorithm({ id: 'sha256', digest: 'SHA-256' }));
|
|
54
|
+
addAlgorithm(createPBKDF2PasswordAlgorithm({ id: 'sha512', digest: 'SHA-512' }));
|
|
69
55
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
56
|
+
export async function parse(hash: string) {
|
|
57
|
+
return PHC.deserialize(hash);
|
|
58
|
+
}
|
|
73
59
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
60
|
+
function resolveAlgorithm(id: string | PasswordAlgorithm): PasswordAlgorithm {
|
|
61
|
+
let f = id;
|
|
62
|
+
while (typeof f === 'string') {
|
|
63
|
+
f = Algorithms[f];
|
|
64
|
+
}
|
|
65
|
+
if (!f) {
|
|
66
|
+
throw new Error(`Unknown algorithm ${id}`);
|
|
67
|
+
}
|
|
68
|
+
return f;
|
|
69
|
+
}
|
|
84
70
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
parsed: res,
|
|
91
|
-
};
|
|
92
|
-
}
|
|
71
|
+
export async function check(password: string, hash: string) {
|
|
72
|
+
let res = await parse(hash);
|
|
73
|
+
let f = resolveAlgorithm(res.id);
|
|
74
|
+
return { result: f.verify(password, hash, res), parsed: res };
|
|
75
|
+
}
|
|
93
76
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
77
|
+
export async function verify(password: string, hash: string) {
|
|
78
|
+
let res = await parse(hash);
|
|
79
|
+
let f = resolveAlgorithm(res.id);
|
|
80
|
+
return f.verify(password, hash, res);
|
|
81
|
+
}
|
|
99
82
|
|
|
100
|
-
|
|
101
|
-
algorithm?: string | PasswordAlgorithm;
|
|
102
|
-
};
|
|
83
|
+
export type PasswordHashOptions = PasswordAlgorithmHashOptions & { algorithm?: string | PasswordAlgorithm };
|
|
103
84
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
...opts,
|
|
111
|
-
});
|
|
112
|
-
}
|
|
85
|
+
export async function hash(password: string, { algorithm, ...opts }: PasswordHashOptions = {}) {
|
|
86
|
+
let f = resolveAlgorithm(algorithm ?? DefaultAlgorithm);
|
|
87
|
+
let id = algorithm ?? DefaultAlgorithm;
|
|
88
|
+
typeof id !== 'string' && (id = f.name);
|
|
89
|
+
return f.hash(password, { id, ...opts });
|
|
90
|
+
}
|
|
113
91
|
}
|
|
@@ -2,79 +2,75 @@ import { maybeFunction, type MaybeFunction, type MaybePromise } from '@wener/uti
|
|
|
2
2
|
import { Password } from './Password';
|
|
3
3
|
|
|
4
4
|
type Provide = {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
hash: (password: string, options: { salt?: Buffer; raw?: boolean; type?: 0 | 1 | 2 }) => Promise<string>;
|
|
6
|
+
verify: (hash: string, password: string) => Promise<boolean>;
|
|
7
7
|
};
|
|
8
8
|
|
|
9
9
|
export function createArgon2PasswordAlgorithm({
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
10
|
+
type,
|
|
11
|
+
provide = async () => {
|
|
12
|
+
throw new Error('Please provide argon2');
|
|
13
|
+
// const { default: wasm } = await import('argon2-browser/dist/argon2.wasm');
|
|
14
|
+
// const argon2 = await WebAssembly.instantiateStreaming(fetch(wasm), {
|
|
15
|
+
// env: {
|
|
16
|
+
// memoryBase: 0,
|
|
17
|
+
// tableBase: 0,
|
|
18
|
+
// memory: new WebAssembly.Memory({ initial: 256 }),
|
|
19
|
+
// table: new WebAssembly.Table({ initial: 0, element: 'anyfunc' }),
|
|
20
|
+
// __memory_base: 0,
|
|
21
|
+
// __table_base: 0,
|
|
22
|
+
// },
|
|
23
|
+
// });
|
|
24
|
+
// console.log(argon2.instance.exports);
|
|
25
|
+
// const { hash } = argon2.instance.exports as any as typeof import('argon2-browser');
|
|
26
|
+
},
|
|
27
|
+
// argon2-browser/dist/argon2-bundled.min.js
|
|
28
|
+
// import('argon2-browser').then(({ default: { hash, verify } }) => {
|
|
29
|
+
// return {
|
|
30
|
+
// hash(password, options) {
|
|
31
|
+
// return hash({
|
|
32
|
+
// pass: password,
|
|
33
|
+
// });
|
|
34
|
+
// },
|
|
35
|
+
// verify(hash, password) {
|
|
36
|
+
// return verify({
|
|
37
|
+
// pass: password,
|
|
38
|
+
// hash: hash,
|
|
39
|
+
// })
|
|
40
|
+
// .then(() => true)
|
|
41
|
+
// .catch(() => false);
|
|
42
|
+
// },
|
|
43
|
+
// };
|
|
44
|
+
// }),
|
|
45
|
+
// provide = () => import('argon2'),
|
|
46
46
|
}: {
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
type?: 'argon2d' | 'argon2i' | 'argon2id';
|
|
48
|
+
provide?: MaybeFunction<MaybePromise<Provide>>;
|
|
49
49
|
} = {}): Password.PasswordAlgorithm {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
argon2d: 0,
|
|
53
|
-
argon2i: 1,
|
|
54
|
-
argon2id: 2,
|
|
55
|
-
} as const;
|
|
50
|
+
// 0=Argon2d, 1=Argon2i, 2=Argon2id
|
|
51
|
+
const toType: Record<string, 0 | 1 | 2 | undefined> = { argon2d: 0, argon2i: 1, argon2id: 2 } as const;
|
|
56
52
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
53
|
+
let mod: Provide;
|
|
54
|
+
const resolve = () => {
|
|
55
|
+
if (mod) return mod;
|
|
56
|
+
return Promise.resolve(maybeFunction(provide)).then((v) => (mod = v));
|
|
57
|
+
};
|
|
58
|
+
return {
|
|
59
|
+
name: 'argon2',
|
|
60
|
+
ids: ['argon2i', 'argon2d', 'argon2id'],
|
|
61
|
+
async hash(password: string, opts) {
|
|
62
|
+
// const { hash } = await import('argon2');
|
|
63
|
+
const { hash } = await resolve();
|
|
64
|
+
const id = opts?.id;
|
|
65
|
+
return hash(password, {
|
|
66
|
+
salt: opts?.salt ? Buffer.from(opts.salt) : undefined,
|
|
67
|
+
raw: false,
|
|
68
|
+
type: toType[id || ''] ?? toType[type || ''],
|
|
69
|
+
});
|
|
70
|
+
},
|
|
71
|
+
async verify(password: string, hash: string) {
|
|
72
|
+
const { verify } = await resolve();
|
|
73
|
+
return verify(hash, password);
|
|
74
|
+
},
|
|
75
|
+
};
|
|
80
76
|
}
|
|
@@ -2,13 +2,13 @@ import { ArrayBuffers } from '@wener/utils';
|
|
|
2
2
|
import { Password } from './Password';
|
|
3
3
|
|
|
4
4
|
export function createBase64PasswordAlgorithm({ id = 'base64' }: { id?: string } = {}): Password.PasswordAlgorithm {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
return {
|
|
6
|
+
name: id,
|
|
7
|
+
async hash(password: string) {
|
|
8
|
+
return `$${id}$$${ArrayBuffers.toBase64(password).replace(/=/g, '')}`;
|
|
9
|
+
},
|
|
10
|
+
async verify(password: string, hash: string, opts) {
|
|
11
|
+
return Boolean(opts.hash) && ArrayBuffers.toString(opts.hash!) === password;
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
14
|
}
|
|
@@ -2,29 +2,27 @@ import type { MaybePromise } from '@wener/utils';
|
|
|
2
2
|
import { Password } from './Password';
|
|
3
3
|
|
|
4
4
|
type ProviderType = () => MaybePromise<{
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
hash: (password: string, rounds: number | string) => Promise<string>;
|
|
6
|
+
compare: (password: string, hash: string) => Promise<boolean>;
|
|
7
7
|
}>;
|
|
8
8
|
|
|
9
9
|
export function createBcryptPasswordAlgorithm({
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}: {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
},
|
|
29
|
-
};
|
|
10
|
+
// provider = () => import('bcrypt').then((v) => v.default),
|
|
11
|
+
provider = () => import('bcryptjs').then((v) => v.default),
|
|
12
|
+
}: { provider?: ProviderType } = {}): Password.PasswordAlgorithm {
|
|
13
|
+
// bcrypt or bcryptjs
|
|
14
|
+
return {
|
|
15
|
+
name: 'bcrypt',
|
|
16
|
+
async hash(password: string, opts) {
|
|
17
|
+
const { hash } = await provider();
|
|
18
|
+
return hash(password, opts?.rounds ?? 10);
|
|
19
|
+
},
|
|
20
|
+
async verify(password: string, hash: string) {
|
|
21
|
+
const { compare } = await provider();
|
|
22
|
+
if (hash.startsWith('$2y$')) {
|
|
23
|
+
hash = hash.replace(/^\$2y\$/, '$2a$');
|
|
24
|
+
}
|
|
25
|
+
return compare(password, hash);
|
|
26
|
+
},
|
|
27
|
+
};
|
|
30
28
|
}
|
|
@@ -3,71 +3,59 @@ import { Password } from './Password';
|
|
|
3
3
|
import { PHC } from './PHC';
|
|
4
4
|
|
|
5
5
|
export function createPBKDF2PasswordAlgorithm({
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
id,
|
|
7
|
+
digest,
|
|
8
|
+
iterations = 100000,
|
|
9
|
+
saltlen = 16,
|
|
10
|
+
keylen = digest === 'SHA-256' ? 32 : 64,
|
|
11
11
|
}: {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
id: string;
|
|
13
|
+
digest: 'SHA-256' | 'SHA-512';
|
|
14
|
+
iterations?: number;
|
|
15
|
+
keylen?: number;
|
|
16
|
+
saltlen?: number;
|
|
17
17
|
}): Password.PasswordAlgorithm {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
return {
|
|
19
|
+
name: id,
|
|
20
|
+
async hash(password: string, opts) {
|
|
21
|
+
let salt: Uint8Array;
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
23
|
+
if (opts?.salt) {
|
|
24
|
+
salt = opts.salt;
|
|
25
|
+
} else {
|
|
26
|
+
salt = new Uint8Array(saltlen);
|
|
27
|
+
crypto.getRandomValues(salt);
|
|
28
|
+
}
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
const rounds = opts?.rounds ?? iterations;
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
async verify(password: string, _: string, opts) {
|
|
50
|
-
const rounds = opts?.params?.rounds ?? iterations;
|
|
51
|
-
const salt = opts.salt;
|
|
52
|
-
const storedHash = opts.hash;
|
|
53
|
-
Errors.BadRequest.check(typeof rounds === 'number', 'Invalid rounds');
|
|
54
|
-
Errors.BadRequest.check(salt instanceof Uint8Array, 'Invalid salt');
|
|
55
|
-
Errors.BadRequest.check(storedHash instanceof Uint8Array, 'Invalid hash');
|
|
32
|
+
let key = await crypto.subtle.importKey('raw', new TextEncoder().encode(password), 'PBKDF2', false, [
|
|
33
|
+
'deriveBits',
|
|
34
|
+
]);
|
|
35
|
+
let hash = await crypto.subtle.deriveBits(
|
|
36
|
+
{ name: 'PBKDF2', iterations: rounds, salt, hash: digest },
|
|
37
|
+
key,
|
|
38
|
+
keylen * 8,
|
|
39
|
+
);
|
|
40
|
+
return PHC.serialize({ id: opts?.id ?? id, params: { rounds }, salt, hash: new Uint8Array(hash) });
|
|
41
|
+
},
|
|
42
|
+
async verify(password: string, _: string, opts) {
|
|
43
|
+
const rounds = opts?.params?.rounds ?? iterations;
|
|
44
|
+
const salt = opts.salt;
|
|
45
|
+
const storedHash = opts.hash;
|
|
46
|
+
Errors.BadRequest.check(typeof rounds === 'number', 'Invalid rounds');
|
|
47
|
+
Errors.BadRequest.check(salt instanceof Uint8Array, 'Invalid salt');
|
|
48
|
+
Errors.BadRequest.check(storedHash instanceof Uint8Array, 'Invalid hash');
|
|
56
49
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
storedHash.length * 8,
|
|
69
|
-
);
|
|
70
|
-
return new Uint8Array(hash).every((v, i) => v === storedHash![i]);
|
|
71
|
-
},
|
|
72
|
-
};
|
|
50
|
+
let key = await crypto.subtle.importKey('raw', new TextEncoder().encode(password), 'PBKDF2', false, [
|
|
51
|
+
'deriveBits',
|
|
52
|
+
]);
|
|
53
|
+
let hash = await crypto.subtle.deriveBits(
|
|
54
|
+
{ name: 'PBKDF2', iterations: rounds, salt, hash: digest },
|
|
55
|
+
key,
|
|
56
|
+
storedHash.length * 8,
|
|
57
|
+
);
|
|
58
|
+
return new Uint8Array(hash).every((v, i) => v === storedHash![i]);
|
|
59
|
+
},
|
|
60
|
+
};
|
|
73
61
|
}
|
|
@@ -4,69 +4,58 @@ import { Password } from './Password';
|
|
|
4
4
|
import { PHC } from './PHC';
|
|
5
5
|
|
|
6
6
|
export function createScryptPasswordAlgorithm(
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
7
|
+
options: {
|
|
8
|
+
id?: string;
|
|
9
|
+
cost?: number;
|
|
10
|
+
blocksize?: number;
|
|
11
|
+
parallelism?: number;
|
|
12
|
+
saltlen?: number;
|
|
13
|
+
keylen?: number;
|
|
14
|
+
} = {},
|
|
15
15
|
): Password.PasswordAlgorithm {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
16
|
+
let id = options.id || 'scrypt';
|
|
17
|
+
options.cost ||= Math.pow(2, 14);
|
|
18
|
+
options.blocksize ||= 8;
|
|
19
|
+
options.parallelism ||= 1;
|
|
20
|
+
options.saltlen ||= 16;
|
|
21
|
+
options.keylen ||= 32;
|
|
22
|
+
return {
|
|
23
|
+
name: id,
|
|
24
|
+
async hash(password: string, opts): Promise<string> {
|
|
25
|
+
const salt = opts?.salt || randomBytes(options.saltlen!);
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
let N = options.cost!;
|
|
28
|
+
let r = options.blocksize!;
|
|
29
|
+
let p = options.parallelism!;
|
|
30
|
+
scrypt(password, salt, options.keylen!, { N, r, p }, (err, derivedKey) => {
|
|
31
|
+
if (err) return reject(err);
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
ln: N!,
|
|
38
|
-
r: r!,
|
|
39
|
-
p: p!,
|
|
40
|
-
},
|
|
41
|
-
salt,
|
|
42
|
-
hash: derivedKey,
|
|
43
|
-
}),
|
|
44
|
-
);
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
},
|
|
33
|
+
resolve(PHC.serialize({ id: opts?.id ?? id, params: { ln: N!, r: r!, p: p! }, salt, hash: derivedKey }));
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
},
|
|
48
37
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
38
|
+
async verify(password: string, hash: string, opts): Promise<boolean> {
|
|
39
|
+
try {
|
|
40
|
+
const salt = Errors.BadRequest.require(opts.salt);
|
|
41
|
+
const storedHash = Errors.BadRequest.require(opts.hash);
|
|
53
42
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
43
|
+
const N = parseInt(opts.params?.ln as string, 10);
|
|
44
|
+
const r = parseInt(opts.params?.r as string, 10);
|
|
45
|
+
const p = parseInt(opts.params?.p as string, 10);
|
|
46
|
+
const keylen = storedHash.length;
|
|
58
47
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
48
|
+
return new Promise((resolve, reject) => {
|
|
49
|
+
scrypt(password, salt, keylen, { N, r, p }, (err, derivedKey) => {
|
|
50
|
+
if (err) return reject(err);
|
|
62
51
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
52
|
+
const isMatch = timingSafeEqual(derivedKey, storedHash);
|
|
53
|
+
resolve(isMatch);
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
} catch (error) {
|
|
57
|
+
return Promise.resolve(false);
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
};
|
|
72
61
|
}
|