diff --git a/apps/machine/src/services/signer-resolver.ts b/apps/machine/src/services/signer-resolver.ts index 44aa4b5..65f1647 100644 --- a/apps/machine/src/services/signer-resolver.ts +++ b/apps/machine/src/services/signer-resolver.ts @@ -26,6 +26,7 @@ import { parseSpireSeed, seedFingerprint, type Signer, + type SpireSeed, } from '@bitSpire/nostr-client' import type { BunkerBindingRecord } from '@/types/electron' @@ -67,17 +68,38 @@ async function loadPairingState(): Promise { export async function resolveSigner(opts: ResolveSignerOptions): Promise { const { spireSeed, binding } = await loadPairingState() + const resume = (b: BunkerBindingRecord): Promise => + resumeFromBinding({ + clientSecretHex: b.clientSecretHex, + spirePubkey: b.spirePubkey, + bunkerUrl: b.bunkerUrl, + }) + if (spireSeed) { - const seed = parseSpireSeed(spireSeed) - const fingerprint = seedFingerprint(spireSeed) + let seed: SpireSeed + let fingerprint: string + try { + seed = parseSpireSeed(spireSeed) + fingerprint = seedFingerprint(spireSeed) + } catch (err) { + // A stored seed we can't parse — e.g. a legacy-shape seed left in .env + // after the seed format changed (bitspire-#70). If we already hold a + // binding it's authoritative (server-persistent), so resume from it + // rather than bricking a paired machine on the next boot. With no + // binding the seed is our only pairing input, so fail closed. + if (binding) { + console.warn( + '[Signer] Stored spire seed is unparseable; resuming from existing binding:', + (err as Error).message, + ) + return resume(binding) + } + throw err + } if (binding && binding.seedFingerprint === fingerprint) { console.log('[Signer] Resuming bunker session for spire', seed.spirePubkey) - return resumeFromBinding({ - clientSecretHex: binding.clientSecretHex, - spirePubkey: binding.spirePubkey, - bunkerUrl: binding.bunkerUrl, - }) + return resume(binding) } // First pair or re-pair: redeem the one-shot connect secret. @@ -105,11 +127,7 @@ export async function resolveSigner(opts: ResolveSignerOptions): Promise // No seed in this boot but a binding survives → resume. if (binding) { console.log('[Signer] Resuming bunker session from stored binding (no seed this boot)') - return resumeFromBinding({ - clientSecretHex: binding.clientSecretHex, - spirePubkey: binding.spirePubkey, - bunkerUrl: binding.bunkerUrl, - }) + return resume(binding) } if (opts.allowEphemeral) {