bcrypt-ts 1.0.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/src/helpers.ts ADDED
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Gets the number of rounds used to encrypt the specified hash.
3
+ *
4
+ * @param hash Hash to extract the used number of rounds from
5
+ * @returns Number of rounds used
6
+ * @throws {Error} If `hash` is not a string
7
+ */
8
+ export const getRounds = (hash: string): number => {
9
+ if (typeof hash !== "string")
10
+ throw new Error(`Illegal arguments: ${typeof hash}`);
11
+
12
+ return parseInt(hash.split("$")[2], 10);
13
+ };
14
+
15
+ /**
16
+ * Gets the salt portion from a hash. Does not validate the hash.
17
+ *
18
+ * @param hash Hash to extract the salt from
19
+ * @returns Extracted salt part
20
+ * @throws {Error} If `hash` is not a string or otherwise invalid
21
+ */
22
+ export const getSalt = (hash: string): string => {
23
+ if (typeof hash !== "string")
24
+ throw new Error(`Illegal arguments: ${typeof hash}`);
25
+
26
+ if (hash.length !== 60)
27
+ throw new Error(`Illegal hash length: ${hash.length} != 60`);
28
+
29
+ return hash.substring(0, 29);
30
+ };
package/src/index.ts ADDED
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Copyright (c) 2012 Nevins Bartolomeo <nevins.bartolomeo@gmail.com>
3
+ * Copyright (c) 2012 Shane Girish <shaneGirish@gmail.com>
4
+ * Copyright (c) 2014 Daniel Wirtz <dcode@dcode.io>
5
+ *
6
+ * Redistribution and use in source and binary forms, with or without
7
+ * modification, are permitted provided that the following conditions
8
+ * are met:
9
+ * 1. Redistributions of source code must retain the above copyright
10
+ * notice, this list of conditions and the following disclaimer.
11
+ * 2. Redistributions in binary form must reproduce the above copyright
12
+ * notice, this list of conditions and the following disclaimer in the
13
+ * documentation and/or other materials provided with the distribution.
14
+ * 3. The name of the author may not be used to endorse or promote products
15
+ * derived from this software without specific prior written permission.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ */
28
+
29
+ /**
30
+ * @license bcrypt.js (c) 2013 Daniel Wirtz <dcode@dcode.io>
31
+ * Released under the Apache License, Version 2.0
32
+ * see: https://github.com/dcodeIO/bcrypt.js for details
33
+ */
34
+
35
+ export * from "./base64";
36
+ export * from "./compare";
37
+ export * from "./hash";
38
+ export * from "./helpers";
39
+ export * from "./salt";
package/src/salt.ts ADDED
@@ -0,0 +1,49 @@
1
+ import { BCRYPT_SALT_LEN, GENSALT_DEFAULT_LOG2_ROUNDS } from "./constant";
2
+ import { encodeBase64 } from "./base64";
3
+ import { nextTick, random } from "./utils";
4
+ /**
5
+ * Synchronously generates a salt.
6
+ *
7
+ * @param rounds Number of rounds to use, defaults to 10 if omitted
8
+ * @returns Resulting salt
9
+ * @throws {Error} If a random fallback is required but not set
10
+ */
11
+ export const genSaltSync = (rounds = GENSALT_DEFAULT_LOG2_ROUNDS): string => {
12
+ if (typeof rounds !== "number")
13
+ throw Error("Illegal arguments: " + typeof rounds);
14
+ if (rounds < 4) rounds = 4;
15
+ else if (rounds > 31) rounds = 31;
16
+
17
+ const salt = [];
18
+
19
+ salt.push("$2a$");
20
+ if (rounds < 10) salt.push("0");
21
+ salt.push(rounds.toString());
22
+ salt.push("$");
23
+ salt.push(encodeBase64(random(BCRYPT_SALT_LEN), BCRYPT_SALT_LEN)); // May throw
24
+
25
+ return salt.join("");
26
+ };
27
+
28
+ /**
29
+ * Asynchronously generates a salt.
30
+ *
31
+ * @param rounds Number of rounds to use, defaults to 10 if omitted
32
+ */
33
+ export const genSalt = (
34
+ rounds = GENSALT_DEFAULT_LOG2_ROUNDS
35
+ ): Promise<string> => {
36
+ if (typeof rounds !== "number")
37
+ throw Error("illegal arguments: " + typeof rounds);
38
+
39
+ return new Promise((resolve, reject) =>
40
+ nextTick(() => {
41
+ // Pretty thin, but salting is fast enough
42
+ try {
43
+ resolve(genSaltSync(rounds));
44
+ } catch (err) {
45
+ reject(err);
46
+ }
47
+ })
48
+ );
49
+ };
package/src/utfx.ts ADDED
@@ -0,0 +1,232 @@
1
+ /**
2
+ * utfx-embeddable (c) 2014 Daniel Wirtz <dcode@dcode.io>
3
+ * Released under the Apache License, Version 2.0
4
+ * see: https://github.com/dcodeIO/utfx for details
5
+ */
6
+
7
+ export const MAX_CODEPOINT = 0x10ffff;
8
+
9
+ /**
10
+ * Encodes UTF8 code points to UTF8 bytes.
11
+ * @param {(!function():number|null) | number} src Code points source, either as a function returning the next code point
12
+ * respectively `null` if there are no more code points left or a single numeric code point.
13
+ * @param {!function(number)} dst Bytes destination as a function successively called with the next byte
14
+ */
15
+ export const encodeUTF8 = (
16
+ src: number | (() => number | null),
17
+ dst: (byte: number) => void
18
+ ): void => {
19
+ let cp = null;
20
+
21
+ if (typeof src === "number") (cp = src), (src = (): null => null);
22
+
23
+ while (cp !== null || (cp = src()) !== null) {
24
+ if (cp < 0x80) dst(cp & 0x7f);
25
+ else if (cp < 0x800)
26
+ dst(((cp >> 6) & 0x1f) | 0xc0), dst((cp & 0x3f) | 0x80);
27
+ else if (cp < 0x10000)
28
+ dst(((cp >> 12) & 0x0f) | 0xe0),
29
+ dst(((cp >> 6) & 0x3f) | 0x80),
30
+ dst((cp & 0x3f) | 0x80);
31
+ else
32
+ dst(((cp >> 18) & 0x07) | 0xf0),
33
+ dst(((cp >> 12) & 0x3f) | 0x80),
34
+ dst(((cp >> 6) & 0x3f) | 0x80),
35
+ dst((cp & 0x3f) | 0x80);
36
+ cp = null;
37
+ }
38
+ };
39
+
40
+ /**
41
+ * Decodes UTF8 bytes to UTF8 code points.
42
+ *
43
+ * @param src Bytes source as a function returning the next byte respectively `null` if there
44
+ * are no more bytes left.
45
+ * @param dst Code points destination as a function successively called with each decoded code point.
46
+ * @throws {RangeError} If a starting byte is invalid in UTF8
47
+ * @throws {Error} If the last sequence is truncated. Has an array property `bytes` holding the
48
+ * remaining bytes.
49
+ */
50
+ export const decodeUTF8 = (
51
+ src: () => number | null,
52
+ dst: (byte: number) => void
53
+ ): void => {
54
+ let a: number | null;
55
+ let b: number | null;
56
+ let c: number | null;
57
+ let d: number | null;
58
+
59
+ const fail = (b: (number | null)[]): void => {
60
+ b = b.slice(0, b.indexOf(null));
61
+
62
+ const err = Error(b.toString());
63
+
64
+ err.name = "TruncatedError";
65
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
66
+ // @ts-ignore
67
+ err["bytes"] = b;
68
+
69
+ throw err;
70
+ };
71
+
72
+ while ((a = src()) !== null) {
73
+ if ((a & 0x80) === 0) dst(a);
74
+ else if ((a & 0xe0) === 0xc0)
75
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
76
+ // @ts-ignore
77
+ (b = src()) === null && fail([a, b]), dst(((a & 0x1f) << 6) | (b & 0x3f));
78
+ else if ((a & 0xf0) === 0xe0)
79
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
80
+ // @ts-ignore
81
+ ((b = src()) === null || (c = src()) === null) && fail([a, b, c]),
82
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
83
+ // @ts-ignore
84
+ dst(((a & 0x0f) << 12) | ((b & 0x3f) << 6) | (c & 0x3f));
85
+ else if ((a & 0xf8) === 0xf0)
86
+ ((b = src()) === null || (c = src()) === null || (d = src()) === null) &&
87
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
88
+ // @ts-ignore
89
+ fail([a, b, c, d]),
90
+ dst(
91
+ ((a & 0x07) << 18) |
92
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
93
+ // @ts-ignore
94
+ ((b & 0x3f) << 12) |
95
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
96
+ // @ts-ignore
97
+ ((c & 0x3f) << 6) |
98
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
99
+ // @ts-ignore
100
+ (d & 0x3f)
101
+ );
102
+ else throw RangeError(`Illegal starting byte: ${a}`);
103
+ }
104
+ };
105
+
106
+ /**
107
+ * Converts UTF16 characters to UTF8 code points.
108
+ * @param {!function():number|null} src Characters source as a function returning the next char code respectively
109
+ * `null` if there are no more characters left.
110
+ * @param {!function(number)} dst Code points destination as a function successively called with each converted code
111
+ * point.
112
+ */
113
+ export const UTF16toUTF8 = (
114
+ src: () => number | null,
115
+ dst: (byte: number) => void
116
+ ): void => {
117
+ let c1: number | null;
118
+ let c2 = null;
119
+
120
+ // eslint-disable-next-line no-constant-condition
121
+ while (true) {
122
+ if ((c1 = c2 !== null ? c2 : src()) === null) break;
123
+ if (c1 >= 0xd800 && c1 <= 0xdfff) {
124
+ if ((c2 = src()) !== null) {
125
+ if (c2 >= 0xdc00 && c2 <= 0xdfff) {
126
+ dst((c1 - 0xd800) * 0x400 + c2 - 0xdc00 + 0x10000);
127
+ c2 = null;
128
+ continue;
129
+ }
130
+ }
131
+ }
132
+ dst(c1);
133
+ }
134
+ if (c2 !== null) dst(c2);
135
+ };
136
+
137
+ /**
138
+ * Converts UTF8 code points to UTF16 characters.
139
+ *
140
+ * @param src Code points source, either as a function returning the next code point
141
+ * respectively `null` if there are no more code points left or a single numeric code point.
142
+ * @param dst Characters destination as a function successively called with each converted char code.
143
+ * @throws {RangeError} If a code point is out of range
144
+ */
145
+ export const UTF8toUTF16 = (
146
+ src: (() => number | null) | number,
147
+ dst: (byte: number) => void
148
+ ): void => {
149
+ let cp = null;
150
+
151
+ if (typeof src === "number") (cp = src), (src = (): null => null);
152
+
153
+ while (cp !== null || (cp = src()) !== null) {
154
+ if (cp <= 0xffff) dst(cp);
155
+ else (cp -= 0x10000), dst((cp >> 10) + 0xd800), dst((cp % 0x400) + 0xdc00);
156
+ cp = null;
157
+ }
158
+ };
159
+
160
+ /**
161
+ * Converts and encodes UTF16 characters to UTF8 bytes.
162
+ * @param {!function():number|null} src Characters source as a function returning the next char code respectively `null`
163
+ * if there are no more characters left.
164
+ * @param {!function(number)} dst Bytes destination as a function successively called with the next byte.
165
+ */
166
+ export const encodeUTF16toUTF8 = (
167
+ src: () => number | null,
168
+ dst: (byte: number) => void
169
+ ): void => {
170
+ UTF16toUTF8(src, function (cp) {
171
+ encodeUTF8(cp, dst);
172
+ });
173
+ };
174
+
175
+ /**
176
+ * Decodes and converts UTF8 bytes to UTF16 characters.
177
+ * @param {!function():number|null} src Bytes source as a function returning the next byte respectively `null` if there
178
+ * are no more bytes left.
179
+ * @param {!function(number)} dst Characters destination as a function successively called with each converted char code.
180
+ * @throws {RangeError} If a starting byte is invalid in UTF8
181
+ * @throws {Error} If the last sequence is truncated. Has an array property `bytes` holding the remaining bytes.
182
+ */
183
+ export const decodeUTF8toUTF16 = (
184
+ src: () => number | null,
185
+ dst: (byte: number) => void
186
+ ): void => {
187
+ decodeUTF8(src, (cp) => {
188
+ UTF8toUTF16(cp, dst);
189
+ });
190
+ };
191
+
192
+ /**
193
+ * Calculates the byte length of an UTF8 code point.
194
+ *
195
+ * @param codePoint UTF8 code point
196
+ * @returns Byte length
197
+ */
198
+ export const calculateCodePoint = (codePoint: number): number =>
199
+ codePoint < 0x80 ? 1 : codePoint < 0x800 ? 2 : codePoint < 0x10000 ? 3 : 4;
200
+
201
+ /**
202
+ * Calculates the number of UTF8 bytes required to store UTF8 code points.
203
+ * @param src Code points source as a function returning the next code point respectively
204
+ * `null` if there are no more code points left.
205
+ * @returns The number of UTF8 bytes required
206
+ */
207
+ export const calculateUTF8 = (src: () => number | null): number => {
208
+ let cp: number | null;
209
+ let l = 0;
210
+
211
+ while ((cp = src()) !== null) l += calculateCodePoint(cp);
212
+
213
+ return l;
214
+ };
215
+
216
+ /**
217
+ * Calculates the number of UTF8 code points respectively UTF8 bytes required to store UTF16 char codes.
218
+ * @param src Characters source as a function returning the next char code respectively
219
+ * `null` if there are no more characters left.
220
+ * @returns The number of UTF8 code points at index 0 and the number of UTF8 bytes required at index 1.
221
+ */
222
+ export const calculateUTF16asUTF8 = (src: () => number | null): number[] => {
223
+ let n = 0,
224
+ l = 0;
225
+
226
+ UTF16toUTF8(src, function (cp) {
227
+ ++n;
228
+ l += calculateCodePoint(cp);
229
+ });
230
+
231
+ return [n, l];
232
+ };
package/src/utils.ts ADDED
@@ -0,0 +1,70 @@
1
+ import { encodeUTF16toUTF8 } from "./utfx";
2
+
3
+ /**
4
+ * Continues with the callback on the next tick.
5
+ */
6
+ export const nextTick =
7
+ typeof process !== "undefined" &&
8
+ process &&
9
+ typeof process.nextTick === "function"
10
+ ? typeof setImmediate === "function"
11
+ ? setImmediate
12
+ : // eslint-disable-next-line @typescript-eslint/unbound-method
13
+ process.nextTick
14
+ : setTimeout;
15
+
16
+ /**
17
+ * Generates cryptographically secure random bytes.
18
+ *
19
+ * @param length Bytes length
20
+ * @returns Random bytes
21
+ * @throws {Error} If no random implementation is available
22
+ */
23
+ export const random = (length: number): number[] => {
24
+ /* node */ if (typeof module !== "undefined" && module && module["exports"])
25
+ try {
26
+ // eslint-disable-next-line
27
+ return require("crypto")["randomBytes"](length);
28
+ } catch (err) {
29
+ // do nothing
30
+ }
31
+ /* WCA */ try {
32
+ let array: Uint32Array;
33
+
34
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
35
+ // @ts-ignore
36
+ (self["crypto"] || self["msCrypto"])["getRandomValues"](
37
+ (array = new Uint32Array(length))
38
+ );
39
+
40
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
41
+ return Array.prototype.slice.call(array);
42
+ } catch (err) {
43
+ // do nothing
44
+ }
45
+
46
+ throw Error(
47
+ "Neither WebCryptoAPI nor a crypto module is available. Use bcrypt.setRandomFallback to set an alternative"
48
+ );
49
+ };
50
+
51
+ /**
52
+ * Converts a JavaScript string to UTF8 bytes.
53
+ * @param {string} str String
54
+ * @returns {!Array.<number>} UTF8 bytes
55
+ * @inner
56
+ */
57
+
58
+ export const stringToBytes = (str: string): number[] => {
59
+ const out: number[] = [];
60
+ let i = 0;
61
+
62
+ encodeUTF16toUTF8(
63
+ () => (i >= str.length ? null : str.charCodeAt(i++)),
64
+ (b: number) => {
65
+ out.push(b);
66
+ }
67
+ );
68
+
69
+ return out;
70
+ };