Skip to content

Commit 67b0069

Browse files
committed
return the options in use; improve documentation about options in use; improve some types; improve compatibility with older versions of Error
1 parent 10c5cbe commit 67b0069

File tree

2 files changed

+38
-8
lines changed

2 files changed

+38
-8
lines changed

index.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,20 @@ exports.defaultIvLength = 96;
3131
* The written format is IV + Salt + Ciphertext concatenated, and then Base64
3232
* encoded as a string. The data read is first processed with TextEncoder.
3333
*
34+
* The returned store also has the an extra property called `options`, which is
35+
* an object containing the options used to create the store. This can be used
36+
* to check how it was created and save them since they are necessary to decrypt
37+
* the data. Also note that the supplied options are treated very strictly, and
38+
* in case they are present but invalid values they are replaced by the
39+
* defaults. For example, `iterations`, `saltLength` and `ivLength` are all
40+
* expected to be of type number and be positive, finite integers. If you supply
41+
* somthing like '16' or 16.1 for `saltLength`, then the default will be used.
42+
* In the case you rely on loose inputs for these parameters, use the returned
43+
* `options` member of the store to assert that they were interpreted as you
44+
* expected them to. Your backing store will not be written to if it already has
45+
* a string in it so you still have the chance to check your options. Otherwise
46+
* use properly defined data in constants or sanitize your inputs.
47+
*
3448
* @param crypto - The Crypto implementation, which is typically found as
3549
* window.crypto in browser contexts.
3650
* @param backend - A writable Svelte store that implements set and subscribe.
@@ -79,6 +93,7 @@ exports.subtleCryptoStore = Object.freeze(function (crypto, backend, password, o
7993
backend.set(newVal);
8094
});
8195
}),
96+
options: o,
8297
});
8398
});
8499
/** Returns a fucntion that decrypts a ciphertext using AES-GCM */
@@ -195,7 +210,7 @@ const toCodePoint = Object.freeze(function (s) {
195210
if (typeof res !== 'number')
196211
// shouldn't happen in practice since this function is receiving the
197212
// output of atob
198-
throw res;
213+
throw new Error('invalid codepoint');
199214
return res;
200215
});
201216
/**

index.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ export type Options = {
1313
ivLength?: number;
1414
};
1515

16+
type ProcessedOptions = Readonly<Required<Options>>;
17+
1618
/**
1719
* Implements an encrypted Svelte writable store using the Crypto and
1820
* SubtleCrypto APIs with AES-GCM. The data is written to and read from a
@@ -27,6 +29,20 @@ export type Options = {
2729
* The written format is IV + Salt + Ciphertext concatenated, and then Base64
2830
* encoded as a string. The data read is first processed with TextEncoder.
2931
*
32+
* The returned store also has the an extra property called `options`, which is
33+
* an object containing the options used to create the store. This can be used
34+
* to check how it was created and save them since they are necessary to decrypt
35+
* the data. Also note that the supplied options are treated very strictly, and
36+
* in case they are present but invalid values they are replaced by the
37+
* defaults. For example, `iterations`, `saltLength` and `ivLength` are all
38+
* expected to be of type number and be positive, finite integers. If you supply
39+
* somthing like '16' or 16.1 for `saltLength`, then the default will be used.
40+
* In the case you rely on loose inputs for these parameters, use the returned
41+
* `options` member of the store to assert that they were interpreted as you
42+
* expected them to. Your backing store will not be written to if it already has
43+
* a string in it so you still have the chance to check your options. Otherwise
44+
* use properly defined data in constants or sanitize your inputs.
45+
*
3046
* @param crypto - The Crypto implementation, which is typically found as
3147
* window.crypto in browser contexts.
3248
* @param backend - A writable Svelte store that implements set and subscribe.
@@ -53,10 +69,10 @@ export const subtleCryptoStore = Object.freeze(function(
5369
backend: Writable<string>,
5470
password: string,
5571
opts?: Options,
56-
): Writable<Promise<string>> {
72+
): Readonly<Writable<Promise<string>>> {
5773
if (typeof opts === 'undefined')
5874
opts = {};
59-
const o: InternalOptions = Object.freeze({
75+
const o: ProcessedOptions = Object.freeze({
6076
iterations: positiveIntOrDefault(opts, 'iterations', defaultIterations),
6177
saltLength: positiveIntOrDefault(opts, 'saltLength', defaultSaltLength),
6278
ivLength: positiveIntOrDefault(opts, 'ivLength', defaultIvLength),
@@ -92,14 +108,15 @@ export const subtleCryptoStore = Object.freeze(function(
92108
backend.set(newVal);
93109
}),
94110

111+
options: o,
95112
});
96113
});
97114

98115
/** Returns a fucntion that decrypts a ciphertext using AES-GCM */
99116
const newDecryptFunc = Object.freeze(function(
100117
crypto: Crypto,
101118
getMemoized: () => Promise<Memoized>,
102-
o: InternalOptions,
119+
o: ProcessedOptions,
103120
): (s: string) => Promise<string> {
104121
return Object.freeze(async function(s: string): Promise<string> {
105122
if (typeof s !== 'string' || s === '')
@@ -133,7 +150,7 @@ const newDecryptFunc = Object.freeze(function(
133150
const encrypt = Object.freeze(async function(
134151
crypto: Crypto,
135152
getMemoized: () => Promise<Memoized>,
136-
o: InternalOptions,
153+
o: ProcessedOptions,
137154
plainText: Promise<string>,
138155
): Promise<string> {
139156
if (typeof plainText === 'undefined')
@@ -241,8 +258,6 @@ const memoize = Object.freeze(function<T>(makeT: () => T): () => T {
241258
});
242259
});
243260

244-
type InternalOptions = Readonly<Required<Options>>;
245-
246261
/**
247262
* Attempts to get the given property of the object and returns it if it is a
248263
* positive, finite integer. Otherwise it returns the default value.
@@ -277,7 +292,7 @@ const toCodePoint = Object.freeze(function(s: string): number {
277292
if (typeof res !== 'number')
278293
// shouldn't happen in practice since this function is receiving the
279294
// output of atob
280-
throw new Error('invalid codepoint', {cause: s});
295+
throw new Error('invalid codepoint');
281296
return res;
282297
});
283298

0 commit comments

Comments
 (0)