@dungarees/crypto 0.11.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/bcrypt.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import type { CryptoBackend } from './type.ts';
2
+ export declare const DEFAULT_BCRYPT_ROUNDS = 10;
3
+ export declare const createBCryptBackend: ({ rounds, }?: {
4
+ rounds?: number;
5
+ }) => CryptoBackend;
package/bcrypt.js ADDED
@@ -0,0 +1,8 @@
1
+ import { compareSync, genSaltSync, hashSync } from 'bcryptjs';
2
+ export const DEFAULT_BCRYPT_ROUNDS = 10;
3
+ // The cost is a parameter so a test can drop it: the rounds are what make bcrypt deliberately
4
+ // slow.
5
+ export const createBCryptBackend = ({ rounds = DEFAULT_BCRYPT_ROUNDS, } = {}) => ({
6
+ encryptPassword: (plainPassword) => hashSync(plainPassword, genSaltSync(rounds)),
7
+ comparePassword: (plainPassword, encryptedPassword) => compareSync(plainPassword, encryptedPassword),
8
+ });
package/fake.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ import type { CryptoBackend } from './type.ts';
2
+ export type FakeCryptoBackend = {
3
+ backend: CryptoBackend;
4
+ encryptRequests: string[];
5
+ compareRequests: Array<[string, string]>;
6
+ };
7
+ export declare const createFakeCryptoBackend: () => FakeCryptoBackend;
package/fake.js ADDED
@@ -0,0 +1,21 @@
1
+ const ENCRYPTED_PREFIX = 'encrypted_';
2
+ // Prefixes rather than hashes, so it is cheap enough for a test that only needs a password to round
3
+ // trip — and so a plaintext password leaking into a store is visible rather than merely unequal.
4
+ export const createFakeCryptoBackend = () => {
5
+ const encryptRequests = [];
6
+ const compareRequests = [];
7
+ return {
8
+ backend: {
9
+ encryptPassword: (plainPassword) => {
10
+ encryptRequests.push(plainPassword);
11
+ return `${ENCRYPTED_PREFIX}${plainPassword}`;
12
+ },
13
+ comparePassword: (plainPassword, encryptedPassword) => {
14
+ compareRequests.push([plainPassword, encryptedPassword]);
15
+ return encryptedPassword === `${ENCRYPTED_PREFIX}${plainPassword}`;
16
+ },
17
+ },
18
+ encryptRequests,
19
+ compareRequests,
20
+ };
21
+ };
package/package.json ADDED
@@ -0,0 +1,451 @@
1
+ {
2
+ "name": "@dungarees/crypto",
3
+ "engines": {
4
+ "node": ">=25.0.0"
5
+ },
6
+ "scripts": {
7
+ "type-check": "tsc --noEmit"
8
+ },
9
+ "type": "module",
10
+ "dependencies": {
11
+ "@dungarees/core": "*",
12
+ "bcryptjs": "^3.0.3"
13
+ },
14
+ "devDependencies": {
15
+ "typescript": "^5.9.3",
16
+ "vitest": "^3.0.2"
17
+ },
18
+ "author": "info@productkind.com",
19
+ "license": "MIT",
20
+ "version": "0.11.4",
21
+ "exports": {
22
+ "./bcrypt.ts": {
23
+ "import": "./bcrypt.js",
24
+ "types": "./bcrypt.d.ts"
25
+ },
26
+ "./fake.ts": {
27
+ "import": "./fake.js",
28
+ "types": "./fake.d.ts"
29
+ },
30
+ "./node_modules/typescript/lib/lib.d.ts": {
31
+ "import": "./node_modules/typescript/lib/lib.d.js",
32
+ "types": "./node_modules/typescript/lib/lib.d.d.ts"
33
+ },
34
+ "./node_modules/typescript/lib/lib.decorators.d.ts": {
35
+ "import": "./node_modules/typescript/lib/lib.decorators.d.js",
36
+ "types": "./node_modules/typescript/lib/lib.decorators.d.d.ts"
37
+ },
38
+ "./node_modules/typescript/lib/lib.decorators.legacy.d.ts": {
39
+ "import": "./node_modules/typescript/lib/lib.decorators.legacy.d.js",
40
+ "types": "./node_modules/typescript/lib/lib.decorators.legacy.d.d.ts"
41
+ },
42
+ "./node_modules/typescript/lib/lib.dom.asynciterable.d.ts": {
43
+ "import": "./node_modules/typescript/lib/lib.dom.asynciterable.d.js",
44
+ "types": "./node_modules/typescript/lib/lib.dom.asynciterable.d.d.ts"
45
+ },
46
+ "./node_modules/typescript/lib/lib.dom.d.ts": {
47
+ "import": "./node_modules/typescript/lib/lib.dom.d.js",
48
+ "types": "./node_modules/typescript/lib/lib.dom.d.d.ts"
49
+ },
50
+ "./node_modules/typescript/lib/lib.dom.iterable.d.ts": {
51
+ "import": "./node_modules/typescript/lib/lib.dom.iterable.d.js",
52
+ "types": "./node_modules/typescript/lib/lib.dom.iterable.d.d.ts"
53
+ },
54
+ "./node_modules/typescript/lib/lib.es2015.collection.d.ts": {
55
+ "import": "./node_modules/typescript/lib/lib.es2015.collection.d.js",
56
+ "types": "./node_modules/typescript/lib/lib.es2015.collection.d.d.ts"
57
+ },
58
+ "./node_modules/typescript/lib/lib.es2015.core.d.ts": {
59
+ "import": "./node_modules/typescript/lib/lib.es2015.core.d.js",
60
+ "types": "./node_modules/typescript/lib/lib.es2015.core.d.d.ts"
61
+ },
62
+ "./node_modules/typescript/lib/lib.es2015.d.ts": {
63
+ "import": "./node_modules/typescript/lib/lib.es2015.d.js",
64
+ "types": "./node_modules/typescript/lib/lib.es2015.d.d.ts"
65
+ },
66
+ "./node_modules/typescript/lib/lib.es2015.generator.d.ts": {
67
+ "import": "./node_modules/typescript/lib/lib.es2015.generator.d.js",
68
+ "types": "./node_modules/typescript/lib/lib.es2015.generator.d.d.ts"
69
+ },
70
+ "./node_modules/typescript/lib/lib.es2015.iterable.d.ts": {
71
+ "import": "./node_modules/typescript/lib/lib.es2015.iterable.d.js",
72
+ "types": "./node_modules/typescript/lib/lib.es2015.iterable.d.d.ts"
73
+ },
74
+ "./node_modules/typescript/lib/lib.es2015.promise.d.ts": {
75
+ "import": "./node_modules/typescript/lib/lib.es2015.promise.d.js",
76
+ "types": "./node_modules/typescript/lib/lib.es2015.promise.d.d.ts"
77
+ },
78
+ "./node_modules/typescript/lib/lib.es2015.proxy.d.ts": {
79
+ "import": "./node_modules/typescript/lib/lib.es2015.proxy.d.js",
80
+ "types": "./node_modules/typescript/lib/lib.es2015.proxy.d.d.ts"
81
+ },
82
+ "./node_modules/typescript/lib/lib.es2015.reflect.d.ts": {
83
+ "import": "./node_modules/typescript/lib/lib.es2015.reflect.d.js",
84
+ "types": "./node_modules/typescript/lib/lib.es2015.reflect.d.d.ts"
85
+ },
86
+ "./node_modules/typescript/lib/lib.es2015.symbol.d.ts": {
87
+ "import": "./node_modules/typescript/lib/lib.es2015.symbol.d.js",
88
+ "types": "./node_modules/typescript/lib/lib.es2015.symbol.d.d.ts"
89
+ },
90
+ "./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts": {
91
+ "import": "./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.js",
92
+ "types": "./node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.d.ts"
93
+ },
94
+ "./node_modules/typescript/lib/lib.es2016.array.include.d.ts": {
95
+ "import": "./node_modules/typescript/lib/lib.es2016.array.include.d.js",
96
+ "types": "./node_modules/typescript/lib/lib.es2016.array.include.d.d.ts"
97
+ },
98
+ "./node_modules/typescript/lib/lib.es2016.d.ts": {
99
+ "import": "./node_modules/typescript/lib/lib.es2016.d.js",
100
+ "types": "./node_modules/typescript/lib/lib.es2016.d.d.ts"
101
+ },
102
+ "./node_modules/typescript/lib/lib.es2016.full.d.ts": {
103
+ "import": "./node_modules/typescript/lib/lib.es2016.full.d.js",
104
+ "types": "./node_modules/typescript/lib/lib.es2016.full.d.d.ts"
105
+ },
106
+ "./node_modules/typescript/lib/lib.es2016.intl.d.ts": {
107
+ "import": "./node_modules/typescript/lib/lib.es2016.intl.d.js",
108
+ "types": "./node_modules/typescript/lib/lib.es2016.intl.d.d.ts"
109
+ },
110
+ "./node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts": {
111
+ "import": "./node_modules/typescript/lib/lib.es2017.arraybuffer.d.js",
112
+ "types": "./node_modules/typescript/lib/lib.es2017.arraybuffer.d.d.ts"
113
+ },
114
+ "./node_modules/typescript/lib/lib.es2017.d.ts": {
115
+ "import": "./node_modules/typescript/lib/lib.es2017.d.js",
116
+ "types": "./node_modules/typescript/lib/lib.es2017.d.d.ts"
117
+ },
118
+ "./node_modules/typescript/lib/lib.es2017.date.d.ts": {
119
+ "import": "./node_modules/typescript/lib/lib.es2017.date.d.js",
120
+ "types": "./node_modules/typescript/lib/lib.es2017.date.d.d.ts"
121
+ },
122
+ "./node_modules/typescript/lib/lib.es2017.full.d.ts": {
123
+ "import": "./node_modules/typescript/lib/lib.es2017.full.d.js",
124
+ "types": "./node_modules/typescript/lib/lib.es2017.full.d.d.ts"
125
+ },
126
+ "./node_modules/typescript/lib/lib.es2017.intl.d.ts": {
127
+ "import": "./node_modules/typescript/lib/lib.es2017.intl.d.js",
128
+ "types": "./node_modules/typescript/lib/lib.es2017.intl.d.d.ts"
129
+ },
130
+ "./node_modules/typescript/lib/lib.es2017.object.d.ts": {
131
+ "import": "./node_modules/typescript/lib/lib.es2017.object.d.js",
132
+ "types": "./node_modules/typescript/lib/lib.es2017.object.d.d.ts"
133
+ },
134
+ "./node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts": {
135
+ "import": "./node_modules/typescript/lib/lib.es2017.sharedmemory.d.js",
136
+ "types": "./node_modules/typescript/lib/lib.es2017.sharedmemory.d.d.ts"
137
+ },
138
+ "./node_modules/typescript/lib/lib.es2017.string.d.ts": {
139
+ "import": "./node_modules/typescript/lib/lib.es2017.string.d.js",
140
+ "types": "./node_modules/typescript/lib/lib.es2017.string.d.d.ts"
141
+ },
142
+ "./node_modules/typescript/lib/lib.es2017.typedarrays.d.ts": {
143
+ "import": "./node_modules/typescript/lib/lib.es2017.typedarrays.d.js",
144
+ "types": "./node_modules/typescript/lib/lib.es2017.typedarrays.d.d.ts"
145
+ },
146
+ "./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts": {
147
+ "import": "./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.js",
148
+ "types": "./node_modules/typescript/lib/lib.es2018.asyncgenerator.d.d.ts"
149
+ },
150
+ "./node_modules/typescript/lib/lib.es2018.asynciterable.d.ts": {
151
+ "import": "./node_modules/typescript/lib/lib.es2018.asynciterable.d.js",
152
+ "types": "./node_modules/typescript/lib/lib.es2018.asynciterable.d.d.ts"
153
+ },
154
+ "./node_modules/typescript/lib/lib.es2018.d.ts": {
155
+ "import": "./node_modules/typescript/lib/lib.es2018.d.js",
156
+ "types": "./node_modules/typescript/lib/lib.es2018.d.d.ts"
157
+ },
158
+ "./node_modules/typescript/lib/lib.es2018.full.d.ts": {
159
+ "import": "./node_modules/typescript/lib/lib.es2018.full.d.js",
160
+ "types": "./node_modules/typescript/lib/lib.es2018.full.d.d.ts"
161
+ },
162
+ "./node_modules/typescript/lib/lib.es2018.intl.d.ts": {
163
+ "import": "./node_modules/typescript/lib/lib.es2018.intl.d.js",
164
+ "types": "./node_modules/typescript/lib/lib.es2018.intl.d.d.ts"
165
+ },
166
+ "./node_modules/typescript/lib/lib.es2018.promise.d.ts": {
167
+ "import": "./node_modules/typescript/lib/lib.es2018.promise.d.js",
168
+ "types": "./node_modules/typescript/lib/lib.es2018.promise.d.d.ts"
169
+ },
170
+ "./node_modules/typescript/lib/lib.es2018.regexp.d.ts": {
171
+ "import": "./node_modules/typescript/lib/lib.es2018.regexp.d.js",
172
+ "types": "./node_modules/typescript/lib/lib.es2018.regexp.d.d.ts"
173
+ },
174
+ "./node_modules/typescript/lib/lib.es2019.array.d.ts": {
175
+ "import": "./node_modules/typescript/lib/lib.es2019.array.d.js",
176
+ "types": "./node_modules/typescript/lib/lib.es2019.array.d.d.ts"
177
+ },
178
+ "./node_modules/typescript/lib/lib.es2019.d.ts": {
179
+ "import": "./node_modules/typescript/lib/lib.es2019.d.js",
180
+ "types": "./node_modules/typescript/lib/lib.es2019.d.d.ts"
181
+ },
182
+ "./node_modules/typescript/lib/lib.es2019.full.d.ts": {
183
+ "import": "./node_modules/typescript/lib/lib.es2019.full.d.js",
184
+ "types": "./node_modules/typescript/lib/lib.es2019.full.d.d.ts"
185
+ },
186
+ "./node_modules/typescript/lib/lib.es2019.intl.d.ts": {
187
+ "import": "./node_modules/typescript/lib/lib.es2019.intl.d.js",
188
+ "types": "./node_modules/typescript/lib/lib.es2019.intl.d.d.ts"
189
+ },
190
+ "./node_modules/typescript/lib/lib.es2019.object.d.ts": {
191
+ "import": "./node_modules/typescript/lib/lib.es2019.object.d.js",
192
+ "types": "./node_modules/typescript/lib/lib.es2019.object.d.d.ts"
193
+ },
194
+ "./node_modules/typescript/lib/lib.es2019.string.d.ts": {
195
+ "import": "./node_modules/typescript/lib/lib.es2019.string.d.js",
196
+ "types": "./node_modules/typescript/lib/lib.es2019.string.d.d.ts"
197
+ },
198
+ "./node_modules/typescript/lib/lib.es2019.symbol.d.ts": {
199
+ "import": "./node_modules/typescript/lib/lib.es2019.symbol.d.js",
200
+ "types": "./node_modules/typescript/lib/lib.es2019.symbol.d.d.ts"
201
+ },
202
+ "./node_modules/typescript/lib/lib.es2020.bigint.d.ts": {
203
+ "import": "./node_modules/typescript/lib/lib.es2020.bigint.d.js",
204
+ "types": "./node_modules/typescript/lib/lib.es2020.bigint.d.d.ts"
205
+ },
206
+ "./node_modules/typescript/lib/lib.es2020.d.ts": {
207
+ "import": "./node_modules/typescript/lib/lib.es2020.d.js",
208
+ "types": "./node_modules/typescript/lib/lib.es2020.d.d.ts"
209
+ },
210
+ "./node_modules/typescript/lib/lib.es2020.date.d.ts": {
211
+ "import": "./node_modules/typescript/lib/lib.es2020.date.d.js",
212
+ "types": "./node_modules/typescript/lib/lib.es2020.date.d.d.ts"
213
+ },
214
+ "./node_modules/typescript/lib/lib.es2020.full.d.ts": {
215
+ "import": "./node_modules/typescript/lib/lib.es2020.full.d.js",
216
+ "types": "./node_modules/typescript/lib/lib.es2020.full.d.d.ts"
217
+ },
218
+ "./node_modules/typescript/lib/lib.es2020.intl.d.ts": {
219
+ "import": "./node_modules/typescript/lib/lib.es2020.intl.d.js",
220
+ "types": "./node_modules/typescript/lib/lib.es2020.intl.d.d.ts"
221
+ },
222
+ "./node_modules/typescript/lib/lib.es2020.number.d.ts": {
223
+ "import": "./node_modules/typescript/lib/lib.es2020.number.d.js",
224
+ "types": "./node_modules/typescript/lib/lib.es2020.number.d.d.ts"
225
+ },
226
+ "./node_modules/typescript/lib/lib.es2020.promise.d.ts": {
227
+ "import": "./node_modules/typescript/lib/lib.es2020.promise.d.js",
228
+ "types": "./node_modules/typescript/lib/lib.es2020.promise.d.d.ts"
229
+ },
230
+ "./node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts": {
231
+ "import": "./node_modules/typescript/lib/lib.es2020.sharedmemory.d.js",
232
+ "types": "./node_modules/typescript/lib/lib.es2020.sharedmemory.d.d.ts"
233
+ },
234
+ "./node_modules/typescript/lib/lib.es2020.string.d.ts": {
235
+ "import": "./node_modules/typescript/lib/lib.es2020.string.d.js",
236
+ "types": "./node_modules/typescript/lib/lib.es2020.string.d.d.ts"
237
+ },
238
+ "./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts": {
239
+ "import": "./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.js",
240
+ "types": "./node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.d.ts"
241
+ },
242
+ "./node_modules/typescript/lib/lib.es2021.d.ts": {
243
+ "import": "./node_modules/typescript/lib/lib.es2021.d.js",
244
+ "types": "./node_modules/typescript/lib/lib.es2021.d.d.ts"
245
+ },
246
+ "./node_modules/typescript/lib/lib.es2021.full.d.ts": {
247
+ "import": "./node_modules/typescript/lib/lib.es2021.full.d.js",
248
+ "types": "./node_modules/typescript/lib/lib.es2021.full.d.d.ts"
249
+ },
250
+ "./node_modules/typescript/lib/lib.es2021.intl.d.ts": {
251
+ "import": "./node_modules/typescript/lib/lib.es2021.intl.d.js",
252
+ "types": "./node_modules/typescript/lib/lib.es2021.intl.d.d.ts"
253
+ },
254
+ "./node_modules/typescript/lib/lib.es2021.promise.d.ts": {
255
+ "import": "./node_modules/typescript/lib/lib.es2021.promise.d.js",
256
+ "types": "./node_modules/typescript/lib/lib.es2021.promise.d.d.ts"
257
+ },
258
+ "./node_modules/typescript/lib/lib.es2021.string.d.ts": {
259
+ "import": "./node_modules/typescript/lib/lib.es2021.string.d.js",
260
+ "types": "./node_modules/typescript/lib/lib.es2021.string.d.d.ts"
261
+ },
262
+ "./node_modules/typescript/lib/lib.es2021.weakref.d.ts": {
263
+ "import": "./node_modules/typescript/lib/lib.es2021.weakref.d.js",
264
+ "types": "./node_modules/typescript/lib/lib.es2021.weakref.d.d.ts"
265
+ },
266
+ "./node_modules/typescript/lib/lib.es2022.array.d.ts": {
267
+ "import": "./node_modules/typescript/lib/lib.es2022.array.d.js",
268
+ "types": "./node_modules/typescript/lib/lib.es2022.array.d.d.ts"
269
+ },
270
+ "./node_modules/typescript/lib/lib.es2022.d.ts": {
271
+ "import": "./node_modules/typescript/lib/lib.es2022.d.js",
272
+ "types": "./node_modules/typescript/lib/lib.es2022.d.d.ts"
273
+ },
274
+ "./node_modules/typescript/lib/lib.es2022.error.d.ts": {
275
+ "import": "./node_modules/typescript/lib/lib.es2022.error.d.js",
276
+ "types": "./node_modules/typescript/lib/lib.es2022.error.d.d.ts"
277
+ },
278
+ "./node_modules/typescript/lib/lib.es2022.full.d.ts": {
279
+ "import": "./node_modules/typescript/lib/lib.es2022.full.d.js",
280
+ "types": "./node_modules/typescript/lib/lib.es2022.full.d.d.ts"
281
+ },
282
+ "./node_modules/typescript/lib/lib.es2022.intl.d.ts": {
283
+ "import": "./node_modules/typescript/lib/lib.es2022.intl.d.js",
284
+ "types": "./node_modules/typescript/lib/lib.es2022.intl.d.d.ts"
285
+ },
286
+ "./node_modules/typescript/lib/lib.es2022.object.d.ts": {
287
+ "import": "./node_modules/typescript/lib/lib.es2022.object.d.js",
288
+ "types": "./node_modules/typescript/lib/lib.es2022.object.d.d.ts"
289
+ },
290
+ "./node_modules/typescript/lib/lib.es2022.regexp.d.ts": {
291
+ "import": "./node_modules/typescript/lib/lib.es2022.regexp.d.js",
292
+ "types": "./node_modules/typescript/lib/lib.es2022.regexp.d.d.ts"
293
+ },
294
+ "./node_modules/typescript/lib/lib.es2022.string.d.ts": {
295
+ "import": "./node_modules/typescript/lib/lib.es2022.string.d.js",
296
+ "types": "./node_modules/typescript/lib/lib.es2022.string.d.d.ts"
297
+ },
298
+ "./node_modules/typescript/lib/lib.es2023.array.d.ts": {
299
+ "import": "./node_modules/typescript/lib/lib.es2023.array.d.js",
300
+ "types": "./node_modules/typescript/lib/lib.es2023.array.d.d.ts"
301
+ },
302
+ "./node_modules/typescript/lib/lib.es2023.collection.d.ts": {
303
+ "import": "./node_modules/typescript/lib/lib.es2023.collection.d.js",
304
+ "types": "./node_modules/typescript/lib/lib.es2023.collection.d.d.ts"
305
+ },
306
+ "./node_modules/typescript/lib/lib.es2023.d.ts": {
307
+ "import": "./node_modules/typescript/lib/lib.es2023.d.js",
308
+ "types": "./node_modules/typescript/lib/lib.es2023.d.d.ts"
309
+ },
310
+ "./node_modules/typescript/lib/lib.es2023.full.d.ts": {
311
+ "import": "./node_modules/typescript/lib/lib.es2023.full.d.js",
312
+ "types": "./node_modules/typescript/lib/lib.es2023.full.d.d.ts"
313
+ },
314
+ "./node_modules/typescript/lib/lib.es2023.intl.d.ts": {
315
+ "import": "./node_modules/typescript/lib/lib.es2023.intl.d.js",
316
+ "types": "./node_modules/typescript/lib/lib.es2023.intl.d.d.ts"
317
+ },
318
+ "./node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts": {
319
+ "import": "./node_modules/typescript/lib/lib.es2024.arraybuffer.d.js",
320
+ "types": "./node_modules/typescript/lib/lib.es2024.arraybuffer.d.d.ts"
321
+ },
322
+ "./node_modules/typescript/lib/lib.es2024.collection.d.ts": {
323
+ "import": "./node_modules/typescript/lib/lib.es2024.collection.d.js",
324
+ "types": "./node_modules/typescript/lib/lib.es2024.collection.d.d.ts"
325
+ },
326
+ "./node_modules/typescript/lib/lib.es2024.d.ts": {
327
+ "import": "./node_modules/typescript/lib/lib.es2024.d.js",
328
+ "types": "./node_modules/typescript/lib/lib.es2024.d.d.ts"
329
+ },
330
+ "./node_modules/typescript/lib/lib.es2024.full.d.ts": {
331
+ "import": "./node_modules/typescript/lib/lib.es2024.full.d.js",
332
+ "types": "./node_modules/typescript/lib/lib.es2024.full.d.d.ts"
333
+ },
334
+ "./node_modules/typescript/lib/lib.es2024.object.d.ts": {
335
+ "import": "./node_modules/typescript/lib/lib.es2024.object.d.js",
336
+ "types": "./node_modules/typescript/lib/lib.es2024.object.d.d.ts"
337
+ },
338
+ "./node_modules/typescript/lib/lib.es2024.promise.d.ts": {
339
+ "import": "./node_modules/typescript/lib/lib.es2024.promise.d.js",
340
+ "types": "./node_modules/typescript/lib/lib.es2024.promise.d.d.ts"
341
+ },
342
+ "./node_modules/typescript/lib/lib.es2024.regexp.d.ts": {
343
+ "import": "./node_modules/typescript/lib/lib.es2024.regexp.d.js",
344
+ "types": "./node_modules/typescript/lib/lib.es2024.regexp.d.d.ts"
345
+ },
346
+ "./node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts": {
347
+ "import": "./node_modules/typescript/lib/lib.es2024.sharedmemory.d.js",
348
+ "types": "./node_modules/typescript/lib/lib.es2024.sharedmemory.d.d.ts"
349
+ },
350
+ "./node_modules/typescript/lib/lib.es2024.string.d.ts": {
351
+ "import": "./node_modules/typescript/lib/lib.es2024.string.d.js",
352
+ "types": "./node_modules/typescript/lib/lib.es2024.string.d.d.ts"
353
+ },
354
+ "./node_modules/typescript/lib/lib.es5.d.ts": {
355
+ "import": "./node_modules/typescript/lib/lib.es5.d.js",
356
+ "types": "./node_modules/typescript/lib/lib.es5.d.d.ts"
357
+ },
358
+ "./node_modules/typescript/lib/lib.es6.d.ts": {
359
+ "import": "./node_modules/typescript/lib/lib.es6.d.js",
360
+ "types": "./node_modules/typescript/lib/lib.es6.d.d.ts"
361
+ },
362
+ "./node_modules/typescript/lib/lib.esnext.array.d.ts": {
363
+ "import": "./node_modules/typescript/lib/lib.esnext.array.d.js",
364
+ "types": "./node_modules/typescript/lib/lib.esnext.array.d.d.ts"
365
+ },
366
+ "./node_modules/typescript/lib/lib.esnext.collection.d.ts": {
367
+ "import": "./node_modules/typescript/lib/lib.esnext.collection.d.js",
368
+ "types": "./node_modules/typescript/lib/lib.esnext.collection.d.d.ts"
369
+ },
370
+ "./node_modules/typescript/lib/lib.esnext.d.ts": {
371
+ "import": "./node_modules/typescript/lib/lib.esnext.d.js",
372
+ "types": "./node_modules/typescript/lib/lib.esnext.d.d.ts"
373
+ },
374
+ "./node_modules/typescript/lib/lib.esnext.decorators.d.ts": {
375
+ "import": "./node_modules/typescript/lib/lib.esnext.decorators.d.js",
376
+ "types": "./node_modules/typescript/lib/lib.esnext.decorators.d.d.ts"
377
+ },
378
+ "./node_modules/typescript/lib/lib.esnext.disposable.d.ts": {
379
+ "import": "./node_modules/typescript/lib/lib.esnext.disposable.d.js",
380
+ "types": "./node_modules/typescript/lib/lib.esnext.disposable.d.d.ts"
381
+ },
382
+ "./node_modules/typescript/lib/lib.esnext.error.d.ts": {
383
+ "import": "./node_modules/typescript/lib/lib.esnext.error.d.js",
384
+ "types": "./node_modules/typescript/lib/lib.esnext.error.d.d.ts"
385
+ },
386
+ "./node_modules/typescript/lib/lib.esnext.float16.d.ts": {
387
+ "import": "./node_modules/typescript/lib/lib.esnext.float16.d.js",
388
+ "types": "./node_modules/typescript/lib/lib.esnext.float16.d.d.ts"
389
+ },
390
+ "./node_modules/typescript/lib/lib.esnext.full.d.ts": {
391
+ "import": "./node_modules/typescript/lib/lib.esnext.full.d.js",
392
+ "types": "./node_modules/typescript/lib/lib.esnext.full.d.d.ts"
393
+ },
394
+ "./node_modules/typescript/lib/lib.esnext.intl.d.ts": {
395
+ "import": "./node_modules/typescript/lib/lib.esnext.intl.d.js",
396
+ "types": "./node_modules/typescript/lib/lib.esnext.intl.d.d.ts"
397
+ },
398
+ "./node_modules/typescript/lib/lib.esnext.iterator.d.ts": {
399
+ "import": "./node_modules/typescript/lib/lib.esnext.iterator.d.js",
400
+ "types": "./node_modules/typescript/lib/lib.esnext.iterator.d.d.ts"
401
+ },
402
+ "./node_modules/typescript/lib/lib.esnext.promise.d.ts": {
403
+ "import": "./node_modules/typescript/lib/lib.esnext.promise.d.js",
404
+ "types": "./node_modules/typescript/lib/lib.esnext.promise.d.d.ts"
405
+ },
406
+ "./node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts": {
407
+ "import": "./node_modules/typescript/lib/lib.esnext.sharedmemory.d.js",
408
+ "types": "./node_modules/typescript/lib/lib.esnext.sharedmemory.d.d.ts"
409
+ },
410
+ "./node_modules/typescript/lib/lib.scripthost.d.ts": {
411
+ "import": "./node_modules/typescript/lib/lib.scripthost.d.js",
412
+ "types": "./node_modules/typescript/lib/lib.scripthost.d.d.ts"
413
+ },
414
+ "./node_modules/typescript/lib/lib.webworker.asynciterable.d.ts": {
415
+ "import": "./node_modules/typescript/lib/lib.webworker.asynciterable.d.js",
416
+ "types": "./node_modules/typescript/lib/lib.webworker.asynciterable.d.d.ts"
417
+ },
418
+ "./node_modules/typescript/lib/lib.webworker.d.ts": {
419
+ "import": "./node_modules/typescript/lib/lib.webworker.d.js",
420
+ "types": "./node_modules/typescript/lib/lib.webworker.d.d.ts"
421
+ },
422
+ "./node_modules/typescript/lib/lib.webworker.importscripts.d.ts": {
423
+ "import": "./node_modules/typescript/lib/lib.webworker.importscripts.d.js",
424
+ "types": "./node_modules/typescript/lib/lib.webworker.importscripts.d.d.ts"
425
+ },
426
+ "./node_modules/typescript/lib/lib.webworker.iterable.d.ts": {
427
+ "import": "./node_modules/typescript/lib/lib.webworker.iterable.d.js",
428
+ "types": "./node_modules/typescript/lib/lib.webworker.iterable.d.d.ts"
429
+ },
430
+ "./node_modules/typescript/lib/tsserverlibrary.d.ts": {
431
+ "import": "./node_modules/typescript/lib/tsserverlibrary.d.js",
432
+ "types": "./node_modules/typescript/lib/tsserverlibrary.d.d.ts"
433
+ },
434
+ "./node_modules/typescript/lib/typescript.d.ts": {
435
+ "import": "./node_modules/typescript/lib/typescript.d.js",
436
+ "types": "./node_modules/typescript/lib/typescript.d.d.ts"
437
+ },
438
+ "./service.test.ts": {
439
+ "import": "./service.test.js",
440
+ "types": "./service.test.d.ts"
441
+ },
442
+ "./service.ts": {
443
+ "import": "./service.js",
444
+ "types": "./service.d.ts"
445
+ },
446
+ "./type.ts": {
447
+ "import": "./type.js",
448
+ "types": "./type.d.ts"
449
+ }
450
+ }
451
+ }
package/service.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ import type { CryptoServiceCreator } from './type.ts';
2
+ export declare const createCryptoService: CryptoServiceCreator;
package/service.js ADDED
@@ -0,0 +1,19 @@
1
+ import { createCausedError } from '@dungarees/core/error.ts';
2
+ export const createCryptoService = (backend) => ({
3
+ encryptPassword: (plainPassword) => {
4
+ try {
5
+ return backend.encryptPassword(plainPassword);
6
+ }
7
+ catch (cause) {
8
+ throw createCausedError({ message: "Couldn't encrypt password", cause });
9
+ }
10
+ },
11
+ comparePassword: ({ plainPassword, encryptedPassword }) => {
12
+ try {
13
+ return backend.comparePassword(plainPassword, encryptedPassword);
14
+ }
15
+ catch (cause) {
16
+ throw createCausedError({ message: "Couldn't compare passwords", cause });
17
+ }
18
+ },
19
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,90 @@
1
+ import { createBCryptBackend } from './bcrypt.js';
2
+ import { createFakeCryptoBackend } from './fake.js';
3
+ import { createCryptoService } from './service.js';
4
+ import { expect, test } from 'vitest';
5
+ // The lowest cost bcrypt accepts: the rounds are what make it slow, and these tests only need the
6
+ // hash-then-compare contract.
7
+ const TEST_ROUNDS = 4;
8
+ const createRealCryptoService = () => createCryptoService(createBCryptBackend({ rounds: TEST_ROUNDS }));
9
+ test('encryptPassword does not hand back the password it was given', () => {
10
+ const crypto = createRealCryptoService();
11
+ expect(crypto.encryptPassword('password')).not.toBe('password');
12
+ });
13
+ test('encryptPassword produces a bcrypt hash', () => {
14
+ const crypto = createRealCryptoService();
15
+ expect(crypto.encryptPassword('password')).toMatch(/^\$2[aby]\$\d{2}\$/);
16
+ });
17
+ test('comparePassword accepts the password that produced the hash', () => {
18
+ const crypto = createRealCryptoService();
19
+ const encryptedPassword = crypto.encryptPassword('password');
20
+ expect(crypto.comparePassword({ plainPassword: 'password', encryptedPassword })).toBe(true);
21
+ });
22
+ test('comparePassword rejects any other password', () => {
23
+ const crypto = createRealCryptoService();
24
+ const encryptedPassword = crypto.encryptPassword('password');
25
+ expect(crypto.comparePassword({ plainPassword: 'password_wrong', encryptedPassword })).toBe(false);
26
+ });
27
+ test('encryptPassword salts, so the same password hashes differently each time', () => {
28
+ const crypto = createRealCryptoService();
29
+ expect(crypto.encryptPassword('password')).not.toBe(crypto.encryptPassword('password'));
30
+ });
31
+ test('comparePassword accepts the password against either of its two hashes', () => {
32
+ const crypto = createRealCryptoService();
33
+ const first = crypto.encryptPassword('password');
34
+ const second = crypto.encryptPassword('password');
35
+ expect([
36
+ crypto.comparePassword({ plainPassword: 'password', encryptedPassword: first }),
37
+ crypto.comparePassword({ plainPassword: 'password', encryptedPassword: second }),
38
+ ]).toEqual([true, true]);
39
+ });
40
+ test('comparePassword rejects a hash that is not a hash at all', () => {
41
+ const crypto = createRealCryptoService();
42
+ expect(crypto.comparePassword({ plainPassword: 'password', encryptedPassword: 'not-a-hash' })).toBe(false);
43
+ });
44
+ test('encryptPassword reports a failing backend as an encryption failure', () => {
45
+ const crypto = createCryptoService({
46
+ encryptPassword: () => {
47
+ throw new Error('backend down');
48
+ },
49
+ comparePassword: () => false,
50
+ });
51
+ expect(() => crypto.encryptPassword('password')).toThrow("Couldn't encrypt password: backend down");
52
+ });
53
+ test('comparePassword reports a failing backend as a comparison failure', () => {
54
+ const crypto = createCryptoService({
55
+ encryptPassword: (plainPassword) => plainPassword,
56
+ comparePassword: () => {
57
+ throw new Error('backend down');
58
+ },
59
+ });
60
+ expect(() => crypto.comparePassword({ plainPassword: 'password', encryptedPassword: 'hash' })).toThrow("Couldn't compare passwords: backend down");
61
+ });
62
+ test('the fake backend round-trips a password without the cost of real hashing', () => {
63
+ const { backend } = createFakeCryptoBackend();
64
+ const crypto = createCryptoService(backend);
65
+ const encryptedPassword = crypto.encryptPassword('password');
66
+ expect(crypto.comparePassword({ plainPassword: 'password', encryptedPassword })).toBe(true);
67
+ });
68
+ test('the fake backend rejects a password that does not match', () => {
69
+ const { backend } = createFakeCryptoBackend();
70
+ const crypto = createCryptoService(backend);
71
+ const encryptedPassword = crypto.encryptPassword('password');
72
+ expect(crypto.comparePassword({ plainPassword: 'other', encryptedPassword })).toBe(false);
73
+ });
74
+ test('the fake backend marks its hashes, so a plaintext leak is visible in a test', () => {
75
+ const { backend } = createFakeCryptoBackend();
76
+ const crypto = createCryptoService(backend);
77
+ expect(crypto.encryptPassword('password')).toBe('encrypted_password');
78
+ });
79
+ test('the fake backend records what it was asked to encrypt', () => {
80
+ const { backend, encryptRequests } = createFakeCryptoBackend();
81
+ const crypto = createCryptoService(backend);
82
+ crypto.encryptPassword('password');
83
+ expect(encryptRequests).toEqual(['password']);
84
+ });
85
+ test('the fake backend records what it was asked to compare', () => {
86
+ const { backend, compareRequests } = createFakeCryptoBackend();
87
+ const crypto = createCryptoService(backend);
88
+ crypto.comparePassword({ plainPassword: 'password', encryptedPassword: 'encrypted_password' });
89
+ expect(compareRequests).toEqual([['password', 'encrypted_password']]);
90
+ });
package/type.d.ts ADDED
@@ -0,0 +1,13 @@
1
+ export type ComparePasswordArgs = {
2
+ plainPassword: string;
3
+ encryptedPassword: string;
4
+ };
5
+ export type CryptoService = {
6
+ encryptPassword: (plainPassword: string) => string;
7
+ comparePassword: (args: ComparePasswordArgs) => boolean;
8
+ };
9
+ export type CryptoBackend = {
10
+ encryptPassword: (plainPassword: string) => string;
11
+ comparePassword: (plainPassword: string, encryptedPassword: string) => boolean;
12
+ };
13
+ export type CryptoServiceCreator = (backend: CryptoBackend) => CryptoService;
package/type.js ADDED
@@ -0,0 +1 @@
1
+ export {};