diff --git a/kez-chat/web/src/lib/kez.ts b/kez-chat/web/src/lib/kez.ts index 4895d08..ac21362 100644 --- a/kez-chat/web/src/lib/kez.ts +++ b/kez-chat/web/src/lib/kez.ts @@ -116,6 +116,18 @@ function signWith( payload: unknown, signer: Ed25519Identity, ): SignatureBlock { + // Defensive: if a caller (Svelte file with loose checks, etc.) passes + // something missing .identity, the envelope would be silently + // unverifiable because both signature.key and payload.primary would + // be undefined. Fail loudly instead. + if (!signer || typeof signer.identity !== "string") { + throw new Error( + "signWith: signer.identity missing — pass an Ed25519Identity (use identityFromSeed)", + ); + } + if (!(signer.seed instanceof Uint8Array) || signer.seed.length !== 32) { + throw new Error("signWith: signer.seed must be a 32-byte Uint8Array"); + } const jcs = canonicalBytes(payload); const sig = ed25519.sign(jcs, signer.seed); return { diff --git a/kez-chat/web/src/routes/AddClaim.svelte b/kez-chat/web/src/routes/AddClaim.svelte index 18dc69c..0939de1 100644 --- a/kez-chat/web/src/routes/AddClaim.svelte +++ b/kez-chat/web/src/routes/AddClaim.svelte @@ -3,6 +3,7 @@ import { push } from "svelte-spa-router"; import { signClaim, + identityFromSeed, toPrettyJson, toMarkdown, toCompact, @@ -166,7 +167,12 @@ alert("Identifier looks empty — please fill in the field."); return; } - envelope = signClaim(session.unlocked, subject); + // UnlockedIdentity has {handle, server, primary, seed} — not the + // Ed25519Identity {seed, publicKey, identity} shape signClaim wants. + // Reconstruct from the seed so signer.identity is defined and + // ends up in payload.primary + signature.key. + const signer = identityFromSeed(session.unlocked.seed); + envelope = signClaim(signer, subject); step = "publish"; }