UNPKG

@taxum/cookie

Version:

Cookie jar for Taxum

89 lines 3.1 kB
import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto"; const IV_LEN = 12; const TAG_LEN = 16; /** * A child cookie jar that provides authenticated encryption for its cookies. * * A _private_ child jar signs and encrypts all the cookies added to it and * verifies and decrypts cookies retrieved from it. Any cookies stored in the * `PrivateJar` are simultaneously assured confidentiality, integrity and * authenticity. In other words, clients cannot discover nor tamper with the * contents of a cookie, nor can they fabricate cookie data. */ export class PrivateJar { parent; key; /** * @internal */ constructor(parent, key) { this.parent = parent; this.key = key; } /** * Returns a {@link Cookie} with the name `name` from the parent jar. * * It authenticates and decrypts the cookie's value, returning a `Cookie` * with the decrypted value. If the cookie cannot be found, or the cookie * fails to authenticate or decrypt, `null` is returned. * * @see {@link CookieJar.get} */ get(name) { const cookie = this.parent.get(name); return cookie ? this.decrypt(cookie) : null; } /** * Adds a {@link Cookie} to the parent jar. * * The cookie's value is encrypted with authenticated encryption assuring * confidentially, integrity and authenticity. * * @see {@link CookieJar.add} */ add(cookie) { this.parent.add(this.encrypt(cookie)); } /** * Removes a {@link Cookie} from the parent jar. * * For correct removal, the passed in `cookie` must contain the same `path` * and `domain` as the cookie that was initially set. * * @see {@link CookieJar.remove} */ remove(cookie) { this.parent.remove(cookie); } encrypt(cookie) { const iv = randomBytes(IV_LEN); const cipher = createCipheriv("aes-256-gcm", this.key, iv); cipher.setAAD(Buffer.from(cookie.name, "utf8")); const encrypted = Buffer.concat([cipher.update(cookie.value, "utf8"), cipher.final()]); const data = [iv, encrypted, cipher.getAuthTag()]; return cookie.withValue(Buffer.concat(data).toString("base64")); } decrypt(cookie) { const data = Buffer.from(cookie.value, "base64"); if (data.length < IV_LEN + TAG_LEN) { return null; } const iv = data.subarray(0, IV_LEN); const cipherText = data.subarray(IV_LEN, data.length - TAG_LEN); const tag = data.subarray(data.length - TAG_LEN); const decipher = createDecipheriv("aes-256-gcm", this.key, iv); decipher.setAAD(Buffer.from(cookie.name, "utf8")); decipher.setAuthTag(tag); try { const decrypted = Buffer.concat([ decipher.update(cipherText), decipher.final(), ]).toString("utf8"); return cookie.withValue(decrypted); } catch { return null; } } } //# sourceMappingURL=private.js.map