@taxum/cookie
Version:
Cookie jar for Taxum
89 lines • 3.1 kB
JavaScript
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