UNPKG

@worker-tools/encrypted-cookie-store

Version:

A partial implementation of the Cookie Store API that transparently encrypts and decrypts cookies via AES-GCM.

131 lines 7.27 kB
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _EncryptedCookieStore_store, _EncryptedCookieStore_keyring, _EncryptedCookieStore_key, _EncryptedCookieStore_decrypt; export * from 'cookie-store-interface'; import { bufferSourceToUint8Array, concatBufferSources, splitBufferSource } from "typed-array-utils"; import { Base64Decoder, Base64Encoder } from "base64-encoding"; import { AggregateError } from "./aggregate-error.js"; const EXT = '.enc'; const IV_LENGTH = 16; // bytes const secretToUint8Array = (secret) => typeof secret === 'string' ? new TextEncoder().encode(secret) : bufferSourceToUint8Array(secret); /** * # Encrypted Cookie Store * A partial implementation of the [Cookie Store API](https://wicg.github.io/cookie-store) * that transparently encrypts and decrypts cookies via AES-GCM. * * This is likely only useful in server-side implementations, * but written in a platform-agnostic way. */ export class EncryptedCookieStore { constructor(store, key, opts = {}) { var _a; _EncryptedCookieStore_store.set(this, void 0); _EncryptedCookieStore_keyring.set(this, void 0); _EncryptedCookieStore_key.set(this, void 0); _EncryptedCookieStore_decrypt.set(this, async (cookie) => { const errors = []; for (const key of __classPrivateFieldGet(this, _EncryptedCookieStore_keyring, "f")) { try { const buffer = new Base64Decoder().decode(cookie.value); const [iv, cipher] = splitBufferSource(buffer, IV_LENGTH); const clearBuffer = await crypto.subtle.decrypt({ name: 'AES-GCM', iv }, key, cipher); const clearText = new TextDecoder().decode(clearBuffer); cookie.name = cookie.name.substring(0, cookie.name.length - EXT.length); cookie.value = clearText; return cookie; } catch (err) { errors.push(err); } } throw new AggregateError(errors, 'None of the provided keys was able to decrypt the cookie.'); }); __classPrivateFieldSet(this, _EncryptedCookieStore_store, store, "f"); __classPrivateFieldSet(this, _EncryptedCookieStore_key, key, "f"); __classPrivateFieldSet(this, _EncryptedCookieStore_keyring, [key, ...(_a = opts.keyring) !== null && _a !== void 0 ? _a : []], "f"); } /** A helper function to derive a crypto key from a passphrase */ static async deriveCryptoKey(opts) { var _a, _b, _c, _d; if (!opts.secret) throw Error('Secret missing'); const passphraseKey = await (opts.format === 'jwk' ? crypto.subtle.importKey('jwk', opts.secret, 'PBKDF2', false, ['deriveKey']) : crypto.subtle.importKey((_a = opts.format) !== null && _a !== void 0 ? _a : 'raw', secretToUint8Array(opts.secret), 'PBKDF2', false, ['deriveKey', 'deriveBits'])); const key = await crypto.subtle.deriveKey({ name: 'PBKDF2', iterations: (_b = opts.iterations) !== null && _b !== void 0 ? _b : 999, hash: (_c = opts.hash) !== null && _c !== void 0 ? _c : 'SHA-256', salt: opts.salt ? bufferSourceToUint8Array(opts.salt) : new Base64Decoder().decode('Gfw5ic5qS062JvoubvO+DA==') }, passphraseKey, { name: 'AES-GCM', length: (_d = opts.length) !== null && _d !== void 0 ? _d : 256, }, false, ['encrypt', 'decrypt']); return key; } async get(name) { if (typeof name !== 'string') throw Error('Overload not implemented.'); const cookie = await __classPrivateFieldGet(this, _EncryptedCookieStore_store, "f").get(`${name}${EXT}`); if (!cookie) return cookie; // FIXME: empty values! return __classPrivateFieldGet(this, _EncryptedCookieStore_decrypt, "f").call(this, cookie); } async getAll(options) { if (options != null) throw Error('Overload not implemented.'); const list = []; for (const cookie of await __classPrivateFieldGet(this, _EncryptedCookieStore_store, "f").getAll(options)) { if (cookie.name.endsWith(EXT)) { list.push(await __classPrivateFieldGet(this, _EncryptedCookieStore_decrypt, "f").call(this, cookie)); } } return list; } async set(options, value) { var _a; const [name, val] = typeof options === 'string' ? [options, value !== null && value !== void 0 ? value : ''] : [options.name, (_a = options.value) !== null && _a !== void 0 ? _a : '']; // FIXME: empty string! const iv = crypto.getRandomValues(new Uint8Array(IV_LENGTH)); const message = new TextEncoder().encode(val); const cipher = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, __classPrivateFieldGet(this, _EncryptedCookieStore_key, "f"), message); const cipherB64 = new Base64Encoder({ url: true }).encode(concatBufferSources(iv, cipher)); return __classPrivateFieldGet(this, _EncryptedCookieStore_store, "f").set({ ...typeof options === 'string' ? {} : options, name: `${name}${EXT}`, value: cipherB64, }); } delete(options) { if (typeof options !== 'string') throw Error('Overload not implemented.'); return __classPrivateFieldGet(this, _EncryptedCookieStore_store, "f").delete(`${options}${EXT}`); } addEventListener(...args) { return __classPrivateFieldGet(this, _EncryptedCookieStore_store, "f").addEventListener(...args); } dispatchEvent(event) { return __classPrivateFieldGet(this, _EncryptedCookieStore_store, "f").dispatchEvent(event); } removeEventListener(...args) { return __classPrivateFieldGet(this, _EncryptedCookieStore_store, "f").removeEventListener(...args); } } _EncryptedCookieStore_store = new WeakMap(), _EncryptedCookieStore_keyring = new WeakMap(), _EncryptedCookieStore_key = new WeakMap(), _EncryptedCookieStore_decrypt = new WeakMap(); //# sourceMappingURL=index.js.map