Something went wrong. Try again.
Monorepo for Tangled tangled.org
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455const enc = new TextEncoder();
const b64url = (x: ArrayBuffer | Uint8Array) => { const bytes = x instanceof Uint8Array ? x : new Uint8Array(x); let raw = ""; for (const byte of bytes) raw += String.fromCharCode(byte); return btoa(raw).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");};
const unb64url = (x: string) => { const raw = atob( x.replaceAll("-", "+").replaceAll("_", "/") + "=".repeat((4 - (x.length % 4)) % 4) ); return Uint8Array.from(raw, (c) => c.charCodeAt(0));};
const keyFor = async (secret: string) => crypto.subtle.importKey( "raw", await crypto.subtle.digest("SHA-256", enc.encode(secret)), "AES-GCM", false, ["encrypt", "decrypt"] );
export const sha256Base64Url = async (value: string) => b64url(await crypto.subtle.digest("SHA-256", enc.encode(value)));
export const seal = async (value: unknown, secret: string) => { if (!secret) throw new Error("session secret is not configured"); const iv = crypto.getRandomValues(new Uint8Array(12)); const body = await crypto.subtle.encrypt( { name: "AES-GCM", iv }, await keyFor(secret), enc.encode(JSON.stringify(value)) ); return `${b64url(iv)}.${b64url(body)}`;};
export const open = async <T>(value: string | undefined, secret: string): Promise<T | null> => { if (!value || !secret) return null; try { const [iv, body] = value.split("."); if (!iv || !body) return null; const plain = await crypto.subtle.decrypt( { name: "AES-GCM", iv: unb64url(iv) }, await keyFor(secret), unb64url(body) ); return JSON.parse(new TextDecoder().decode(plain)) as T; } catch { return null; }};