async function applyStream(bytes, stream) { var readableStream = new ReadableStream({ start(controller) { controller.enqueue(bytes); controller.close(); } }); var resultStream = await readableStream.pipeThrough(stream); var result = await new Response(resultStream).arrayBuffer(); return new Uint8Array(result); } export async function compress(bytes) { return await applyStream(bytes, new CompressionStream('gzip')); } export async function decompress(bytes) { return await applyStream(bytes, new DecompressionStream('gzip')); } export async function getKey(password) { var encoder = new TextEncoder(); var encoded = encoder.encode(password); var hashed = await crypto.subtle.digest('SHA-256', encoded); return await crypto.subtle.importKey( 'raw', hashed, 'AES-GCM', false, ['encrypt', 'decrypt'], ); } export async function encrypt(bytes, key) { var iv = crypto.getRandomValues(new Uint8Array(12)); var encrypted = new Uint8Array(await crypto.subtle.encrypt( {name: 'AES-GCM', iv: iv}, key, bytes )); var result = new Uint8Array(iv.length + encrypted.length); result.set(iv, 0); result.set(encrypted, iv.length); return result; } export async function decrypt(bytes, key) { var iv = bytes.slice(0, 12); var encrypted = bytes.slice(12); return new Uint8Array(await crypto.subtle.decrypt( {name: 'AES-GCM', iv: iv}, key, encrypted )); } export async function encodeText(text, key) { var encoder = new TextEncoder(); var bytes = encoder.encode(text); bytes = await compress(bytes); if (key) { bytes = await encrypt(bytes, key); } return bytes.toBase64().replace(/\+/g, '-').replace(/\//g, '_'); } export async function decodeText(string, key) { var decoder = new TextDecoder(); var bytes = Uint8Array.fromBase64(string.replace(/-/g, '+').replace(/_/g, '/')); if (key) { bytes = await decrypt(bytes, key); } bytes = await decompress(bytes); return decoder.decode(bytes); }