feat(web): add account workspaces and signed content flows

This commit is contained in:
justme committed 2026-10-14 04:06:03 +08:00
1 parent 7b8d61d1ba
commit b5cf3d5958
117 files changed
+2789 -1674

No files matched your search

@@ -0,0 +1,22 @@
import { bytes, b64, unb64, sealJson, openJson } from './accountCrypto';
export interface ObjectContext { spaceId: string; channelId: string; domain: 'chat' | 'files'; epoch: number; itemId: string }
const label = (c: ObjectContext) => JSON.stringify(['webdrop/object-key/v1', c.spaceId, c.channelId, c.domain, c.epoch, c.itemId]);
export const randomDomainKey = () => b64(crypto.getRandomValues(new Uint8Array(32)));
async function aes(value: string): Promise<CryptoKey> {
const material = unb64(value);
try { if (material.length !== 32) throw new Error('数据域密钥格式无效'); return await crypto.subtle.importKey('raw', bytes(material), 'AES-GCM', false, ['encrypt', 'decrypt']); }
finally { material.fill(0); }
}
export async function newObjectKey(domainKey: string, context: ObjectContext): Promise<{ key: CryptoKey; envelope: string }> {
const raw = crypto.getRandomValues(new Uint8Array(32));
try {
const key = await crypto.subtle.importKey('raw', bytes(raw), 'AES-GCM', false, ['encrypt', 'decrypt']);
return { key, envelope: await sealJson({ key: b64(raw) }, await aes(domainKey), label(context)) };
} finally { raw.fill(0); }
}
export async function unwrapObjectKey(domainKey: string, envelope: string, context: ObjectContext): Promise<CryptoKey> {
const value = await openJson(envelope, await aes(domainKey), label(context)) as { key?: unknown };
if (typeof value.key !== 'string') throw new Error('对象密钥封装格式无效');
return aes(value.key);
}