Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
1.7 kB · 49 lines
TypeScript
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950export const encode = (bytes: Uint8Array) => btoa(String.fromCharCode(...bytes)) .replaceAll("+", "-") .replaceAll("/", "_") .replaceAll("=", "");export const decode = (value: string) => Uint8Array.from(atob(value.replaceAll("-", "+").replaceAll("_", "/")), (c) => c.charCodeAt(0), );export const random = () => encode(crypto.getRandomValues(new Uint8Array(32)));export const hash = async (value: string) => encode( new Uint8Array( await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value)), ), );export const opaque = (value: unknown): value is string => typeof value === "string" && /^[A-Za-z0-9_-]{43}$/.test(value);async function key(secret: string) { return crypto.subtle.importKey("raw", decode(secret), "AES-GCM", false, [ "encrypt", "decrypt", ]);}export async function encrypt(secret: string, value: unknown, binding: string) { const iv = crypto.getRandomValues(new Uint8Array(12)); const ciphertext = await crypto.subtle.encrypt( { name: "AES-GCM", iv, additionalData: new TextEncoder().encode(binding) }, await key(secret), new TextEncoder().encode(JSON.stringify(value)), ); return { iv: encode(iv), ciphertext: encode(new Uint8Array(ciphertext)) };}export async function decrypt<T>( secret: string, sealed: { iv: string; ciphertext: string }, binding: string,): Promise<T> { const bytes = await crypto.subtle.decrypt( { name: "AES-GCM", iv: decode(sealed.iv), additionalData: new TextEncoder().encode(binding), }, await key(secret), decode(sealed.ciphertext), ); return JSON.parse(new TextDecoder().decode(bytes)) as T;}