import{ok,err}from"./_deps/shared/index.js";import{toBase64,fromBase64}from"./crypto-utils.js";import{exportPKCS8,exportX25519PKCS8,importIdentity,exportMlKemSecretKey,exportMlKemPublicKey,exportMlDsaSecretKey,exportMlDsaPublicKey}from"./identity.js";const PBKDF2_ITERATIONS=31e4,SALT_LENGTH=16,IV_LENGTH=12;function toArrayBuffer(e){const t=new ArrayBuffer(e.byteLength);return new Uint8Array(t).set(e),t}async function deriveKey(e,t){try{if(16!==t.length)return err("INVALID_BACKUP");const r=await crypto.subtle.importKey("raw",(new TextEncoder).encode(e),"PBKDF2",!1,["deriveBits"]),a=new Uint8Array(await crypto.subtle.deriveBits({name:"PBKDF2",hash:"SHA-256",salt:toArrayBuffer(t),iterations:31e4},r,256)),o=await crypto.subtle.importKey("raw",toArrayBuffer(a),{name:"AES-GCM"},!1,["encrypt","decrypt"]);return ok(o)}catch{return err("PBKDF2_FAILED")}}async function serializeIdentity(e){try{const t=await exportPKCS8(e.privateKey);if(!t.ok)return err("EXPORT_FAILED");const r=await exportX25519PKCS8(e.x25519PrivateKey);if(!r.ok)return err("EXPORT_FAILED");const a=exportMlKemSecretKey(e),o=exportMlKemPublicKey(e),n=exportMlDsaSecretKey(e),s=exportMlDsaPublicKey(e),i=e.rotatedKeys?await Promise.all(e.rotatedKeys.map(async e=>{const t=await exportX25519PKCS8(e.x25519PrivateKey);if(!t.ok)throw new Error("Failed to export rotated X25519 key");return{rotatedAt:e.rotatedAt,x25519Pkcs8:toBase64(t.value),...e.mlKemSecretKey?{mlKemSecretKey:toBase64(e.mlKemSecretKey)}:{}}})):void 0;return ok({did:e.did,rawPublicKey:toBase64(e.rawPublicKey),ed25519Pkcs8:toBase64(t.value),x25519Pkcs8:toBase64(r.value),...a?{mlKemSecretKey:toBase64(a)}:{},...o?{mlKemPublicKey:toBase64(o)}:{},...n?{mlDsaSecretKey:toBase64(n)}:{},...s?{mlDsaPublicKey:toBase64(s)}:{},...i?{rotatedKeys:i}:{},exportedAt:Date.now()})}catch{return err("EXPORT_FAILED")}}export async function exportBackup(e,t){try{const r=await serializeIdentity(e);if(!r.ok)return r;const a=crypto.getRandomValues(new Uint8Array(16)),o=crypto.getRandomValues(new Uint8Array(12)),n=await deriveKey(t,a);if(!n.ok)return n;const s=JSON.stringify(r.value),i=(new TextEncoder).encode(s),c=await crypto.subtle.encrypt({name:"AES-GCM",iv:toArrayBuffer(o)},n.value,i),y=new Uint8Array(c);if(y.length<16)return err("ENCRYPTION_FAILED");const l=y.length-16,K=y.slice(0,l),m=y.slice(l);return ok({version:1,salt:toBase64(a),iv:toBase64(o),ciphertext:toBase64(K),tag:toBase64(m)})}catch{return err("ENCRYPTION_FAILED")}}export async function importBackup(e,t){try{if(1!==e.version)return err("INVALID_BACKUP");let r,a,o,n;try{r=fromBase64(e.salt),a=fromBase64(e.iv),o=fromBase64(e.ciphertext),n=fromBase64(e.tag)}catch{return err("INVALID_BACKUP")}if(16!==r.length||12!==a.length||16!==n.length)return err("INVALID_BACKUP");const s=await deriveKey(t,r);if(!s.ok)return s;const i=new Uint8Array(o.length+n.length);let c,y,l,K,m,u,f,B;i.set(o),i.set(n,o.length);try{c=await crypto.subtle.decrypt({name:"AES-GCM",iv:toArrayBuffer(a)},s.value,toArrayBuffer(i))}catch{return err("INVALID_PASSWORD")}try{const e=(new TextDecoder).decode(c);y=JSON.parse(e)}catch{return err("INVALID_BACKUP")}if(!y.did||!y.ed25519Pkcs8||!y.x25519Pkcs8)return err("INVALID_BACKUP");try{l=fromBase64(y.ed25519Pkcs8),K=fromBase64(y.x25519Pkcs8),y.mlKemSecretKey&&(m=fromBase64(y.mlKemSecretKey)),y.mlKemPublicKey&&(u=fromBase64(y.mlKemPublicKey)),y.mlDsaSecretKey&&(f=fromBase64(y.mlDsaSecretKey)),y.mlDsaPublicKey&&(B=fromBase64(y.mlDsaPublicKey))}catch{return err("INVALID_BACKUP")}const d=await importIdentity(l,K,m,u,f,B);if(!d.ok)return err("IMPORT_FAILED");if(y.rotatedKeys&&y.rotatedKeys.length>0){const e=d.value,t=await Promise.all(y.rotatedKeys.map(async e=>{const t=fromBase64(e.x25519Pkcs8),r=await crypto.subtle.importKey("pkcs8",toArrayBuffer(t),{name:"X25519"},!0,["deriveBits"]),a=e.mlKemSecretKey?fromBase64(e.mlKemSecretKey):void 0;return{rotatedAt:e.rotatedAt,x25519PrivateKey:r,...a?{mlKemSecretKey:a}:{}}}));return ok({...e,rotatedKeys:t})}return d}catch{return err("DECRYPTION_FAILED")}}