Skip to content

feat(storage): add a passphrase-encrypted identity vault #360

Description

@kNoAPP

Part of #353. Depends on the storage root.

Problem or Motivation

The seed cannot live where every other preference lives.

AGENTS.md is unambiguous: every setting except locale and theme is per-radio and encrypted under that radio's own derived key. The seed breaks that rule on both counts:

  • It is the thing that survives losing the radio. Storing it under a key derived from the radio's own secrets makes it worthless for its primary purpose.
  • It spans identities whose storage keys differ by construction. There is no single per-radio namespace it could live in.

It also cannot simply be held in memory and forgotten, or the identity list would be unrenderable — the app could not show the user which personas exist without re-deriving them, which requires the seed.

Proposed Solution

A new vault object store in the existing meshcore IndexedDB database, keyed by seed fingerprint rather than by radio public key. Bump DB_VERSION and create it in the existing openDB upgrade path alongside radios and secrets (storage.ts:79-93).

Metadata-only by default

The vault holds what is needed to render and manage personas without holding the secret that creates them:

The seed itself is not persisted by default. Deriving a new persona or switching to one re-prompts for the phrase. This keeps the strongest property available: the phrase exists only on paper, and a compromised browser yields no ability to mint further identities.

Offer "remember this seed on this device" as explicit, clearly-labelled opt-in for users who accept the trade.

Encryption

Reuse the passphrase KDF already proven in archive.ts:47 — PBKDF2-HMAC-SHA256 at 600,000 iterations with NFKC normalization. It exists for exactly this threat model: a human-chosen passphrase protecting something expected to sit on disk. Do not reuse the 100,000-iteration radio-derived path.

AGENTS.md amendment

This ticket must amend the Persisting Preferences section of AGENTS.md to document the vault as a third category alongside the two localStorage pre-connect preferences and the per-radio encrypted blob. Leaving the rule as written while shipping code that contradicts it would mislead every future contributor and every agent reading that file.

The amendment should state what the vault holds, why it cannot be per-radio, and that it is the only sanctioned exception.

Verification

  • A vault survives switching between two personas and remains readable under both.
  • A wrong passphrase is distinguishable from a corrupt record, as the backup envelope already manages.
  • With "remember the seed" off, nothing in IndexedDB permits deriving a new identity.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions