style: capitalize "Relicario" in prose / UI / CLI help

Brand name uses capital R in user-facing text — extension UI strings,
CLI clap help / descriptions / error prose, markdown docs. Lowercase
preserved for the binary command, crate names, npm package, file
paths, env vars, and code identifiers.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
adlee-was-taken
2026-05-01 17:29:10 -04:00
parent 79b10d6a18
commit 39ae2ecbf3
44 changed files with 91 additions and 91 deletions

View File

@@ -1,10 +1,10 @@
# relicario — Design Specification
# Relicario — Design Specification
A git-backed, self-hostable password manager with a Rust core, CLI, and Chrome browser extension. The reference image as a DCT-embedded secret carrier is the core differentiator.
## Overview
relicario is a password manager where vault decryption requires two independent factors: a passphrase the user memorizes and a reference JPEG that carries a 256-bit secret embedded via DCT steganography. The vault lives in a git repository (self-hosted on the user's own Gitea instance), and the server only ever sees opaque ciphertext. Compromise of either factor alone is insufficient to decrypt the vault.
Relicario is a password manager where vault decryption requires two independent factors: a passphrase the user memorizes and a reference JPEG that carries a 256-bit secret embedded via DCT steganography. The vault lives in a git repository (self-hosted on the user's own Gitea instance), and the server only ever sees opaque ciphertext. Compromise of either factor alone is insufficient to decrypt the vault.
Primary goals: portfolio project for adlee.work, architectural elegance, legibility-as-security (the README should read as the security proof), learning Rust, and fun to tinker with.
@@ -23,7 +23,7 @@ A collection of credentials (usernames, passwords, URLs, TOTP seeds, notes) belo
| Stolen device | Filesystem: reference image, device key, cached vault | Decrypt vault | Attacker has image_secret but not passphrase. Argon2id makes brute-force expensive. |
| Stolen device + weak passphrase | Same + feasible brute-force | Decrypt vault | Enforce minimum passphrase strength at vault creation. Universal worst case. |
| Shoulder surfer | Observed passphrase | Decrypt vault (if they also get image) | Passphrase alone insufficient — still need image_secret. |
| Credential stuffing | Leaked email/password from other breaches | Access user's accounts | relicario generates unique passwords per site. Breach of site A doesn't compromise site B. |
| Credential stuffing | Leaked email/password from other breaches | Access user's accounts | Relicario generates unique passwords per site. Breach of site A doesn't compromise site B. |
### Out of scope
@@ -79,7 +79,7 @@ With a 4-word diceware passphrase (~51 bits) and Argon2id at 64 MiB, brute-force
Compared to competitors:
- LastPass/Bitwarden: server breach exposes ~40-60 bits (master password only)
- 1Password: server breach exposes password + 128-bit Secret Key
- relicario: server breach exposes password + 256-bit image_secret
- Relicario: server breach exposes password + 256-bit image_secret
### Authenticated encryption

View File

@@ -1,4 +1,4 @@
# relicario — Credential Capture Design
# Relicario — Credential Capture Design
Experimental feature that detects login form submissions and prompts the user to save or update credentials in the vault. Configurable prompt style (notification bar or toast). Off by default.
@@ -60,7 +60,7 @@ A fixed-position bar at the top of the page, injected into the DOM:
```
┌──────────────────────────────────────────────────────────────────┐
relicario: Save login for github.com? (alee) [Save] [Never] [✕] │
Relicario: Save login for github.com? (alee) [Save] [Never] [✕] │
└──────────────────────────────────────────────────────────────────┘
```
@@ -77,7 +77,7 @@ A floating element in the bottom-right corner:
```
┌─────────────────────────────────┐
relicario │
Relicario │
│ Save login for github.com? │
│ alee │
│ [Save] [Never] [✕] │

View File

@@ -1,4 +1,4 @@
# relicario — Firefox Extension Port Design
# Relicario — Firefox Extension Port Design
Port the existing Chrome MV3 extension to Firefox. Shared TypeScript source, separate manifests, separate build outputs. No code changes to components, popup, or content script.

View File

@@ -1,6 +1,6 @@
# relicario — Standalone Vault Initialization Wizard Design
# Relicario — Standalone Vault Initialization Wizard Design
A browser-based wizard that guides new users through creating an relicario vault from scratch. Lives at `extension/setup.html`, uses the same WASM module as the extension, same terminal dark aesthetic. No server, no Rust toolchain required.
A browser-based wizard that guides new users through creating a Relicario vault from scratch. Lives at `extension/setup.html`, uses the same WASM module as the extension, same terminal dark aesthetic. No server, no Rust toolchain required.
## Scope
@@ -81,9 +81,9 @@ Two things happen:
- Show warning: "Keep this image safe. You need it alongside your passphrase to unlock the vault. Store it somewhere you won't lose it."
**Push config to extension (if available):**
- Try to detect the relicario extension via `chrome.runtime.sendMessage` with a `get_setup_state` message
- Try to detect the Relicario extension via `chrome.runtime.sendMessage` with a `get_setup_state` message
- If extension responds: push `save_setup` message with `{ config: { hostType, hostUrl, repoPath, apiToken }, imageBase64 }`. Show "Extension configured! You can now open the extension and unlock your vault."
- If extension not detected: show the config as a copyable JSON blob with instructions: "Install the relicario extension, then paste this into the setup wizard." (Or just tell them to run through the extension setup manually with the same host/token/repo.)
- If extension not detected: show the config as a copyable JSON blob with instructions: "Install the Relicario extension, then paste this into the setup wizard." (Or just tell them to run through the extension setup manually with the same host/token/repo.)
## WASM Crate Change

View File

@@ -1,6 +1,6 @@
# relicario — WASM + Chrome MV3 Extension Design
# Relicario — WASM + Chrome MV3 Extension Design
The browser extension for relicario. Compiles `relicario-core` to WASM, wraps it in a Chrome MV3 extension with a terminal-aesthetic popup, conservative autofill, and direct Gitea/GitHub API access. No CLI dependency, no native messaging bridge.
The browser extension for Relicario. Compiles `relicario-core` to WASM, wraps it in a Chrome MV3 extension with a terminal-aesthetic popup, conservative autofill, and direct Gitea/GitHub API access. No CLI dependency, no native messaging bridge.
## Scope
@@ -330,7 +330,7 @@ No shadow DOM traversal. No heuristic scoring. No iframe inspection. If the form
### 2. Field Icon Injection
When a password field is detected:
- Small relicario icon (16x16, inline SVG) appears at the right edge of the password field
- Small Relicario icon (16x16, inline SVG) appears at the right edge of the password field
- Click triggers: send page URL to service worker → get matching entries
- Single match: fill immediately
- Multiple matches: show inline picker (small dropdown below the icon)

View File

@@ -1,6 +1,6 @@
# relicario — Typed Item Data Model Design
# Relicario — Typed Item Data Model Design
Foundational data-model rewrite for relicario. Replaces the single `Entry` type with a polymorphic typed-item system supporting Login, SecureNote, Identity, Card, Key, Document, and TOTP — with sections, custom fields, attachments, password history, soft-delete, and the security architecture needed to support 1Password-style daily-driver UX.
Foundational data-model rewrite for Relicario. Replaces the single `Entry` type with a polymorphic typed-item system supporting Login, SecureNote, Identity, Card, Key, Document, and TOTP — with sections, custom fields, attachments, password history, soft-delete, and the security architecture needed to support 1Password-style daily-driver UX.
This is **Phase 1** of the broader 1Password-parity roadmap. Phase 0 (audit remediation) is the precursor implementation pass; Phase 2+ (admin portal, importers, Watchtower checks, etc.) build on top of this model.

View File

@@ -1,4 +1,4 @@
# relicario — Extension Plan 1C-α (Foundation) Design
# Relicario — Extension Plan 1C-α (Foundation) Design
First of three sub-plans that port the browser extension from the v1 single-`Entry` data model to the typed-item model landed in Plans 1A + 1B. 1C-α is the **foundation slice**: rebuild the WASM artifact, migrate shared types, rewrite the service worker against the opaque `SessionHandle` surface, split the message router with sender checks, wire the full security architecture from the typed-items spec, and achieve Login-parity on the new stack. Other six item types show "Coming in 1C-β" placeholders.

View File

@@ -1,4 +1,4 @@
# relicario — Extension Plan 1C-β₁ (Typed-Item Forms) Design
# Relicario — Extension Plan 1C-β₁ (Typed-Item Forms) Design
Second of three sub-plans porting the extension to the typed-item core. 1C-α (foundation) shipped Login-parity; 1C-β₁ adds the **other 5 typed-item forms** so the extension can daily-drive every typed item the Rust core knows about (except Document, deferred to γ for attachment dependencies). Custom-fields editor, vault-settings view, and advanced generator UI move to **β₂**.

View File

@@ -1,4 +1,4 @@
# relicario — Extension Plan 1C-β₂ (Custom Fields + Settings + Generator UI) Design
# Relicario — Extension Plan 1C-β₂ (Custom Fields + Settings + Generator UI) Design
Third of three β sub-plans porting the extension to the typed-item core. 1C-α shipped the security architecture + Login parity; 1C-β₁ added the 5 remaining typed-item forms; **1C-β₂** (this spec) adds the cross-cutting UI surfaces: custom fields editor, full vault-settings view, and an inline generator popover.

View File

@@ -5,7 +5,7 @@
## Goal
The current logo reads as "modern shrine with a blue diamond" — visually correct in concept (a vessel that holds something precious) but blue-techy enough that the project's name (*relicario* — Spanish/Italian for *reliquary*) no longer comes through. The user wants more catholic-reliquary authenticity (gold, deep red, decorative finial) without the cross — closer to the user-supplied references of round-chapel theca reliquaries.
The current logo reads as "modern shrine with a blue diamond" — visually correct in concept (a vessel that holds something precious) but blue-techy enough that the project's name (*Relicario* — Spanish/Italian for *reliquary*) no longer comes through. The user wants more catholic-reliquary authenticity (gold, deep red, decorative finial) without the cross — closer to the user-supplied references of round-chapel theca reliquaries.
The popup currently uses GitHub's dark-blue accent palette throughout. Once the logo shifts to gold, leaving the popup's blue accents in place would create visual whiplash between the toolbar icon and the popup body. The palette shift converts blue → gold and tunes the danger red toward the logo's theca tone, while keeping the dark backgrounds, monospace-ish text, and CLI restraint that define the project's voice.

View File

@@ -7,7 +7,7 @@
## Background
Today the setup wizard (`extension/src/setup/setup.ts`) has one flow: create a brand-new vault. Step 2 only checks that the configured remote is reachable; it does not detect whether that remote already contains a relicario vault. Step 3's "create vault" then writes `.relicario/salt`, `.relicario/params.json`, `.relicario/devices.json`, and `manifest.enc` unconditionally — silently overwriting any existing vault on the remote.
Today the setup wizard (`extension/src/setup/setup.ts`) has one flow: create a brand-new vault. Step 2 only checks that the configured remote is reachable; it does not detect whether that remote already contains a Relicario vault. Step 3's "create vault" then writes `.relicario/salt`, `.relicario/params.json`, `.relicario/devices.json`, and `manifest.enc` unconditionally — silently overwriting any existing vault on the remote.
**Observed failure:** uninstalling and reinstalling the extension while pointed at a populated test repo wipes the manifest with no warning. The user's test entries are gone.
@@ -64,7 +64,7 @@ The progress bar grows from 5 to 6 segments; Step 0 is the new leading segment.
Two large buttons. No host configuration, no other inputs. Sets `state.mode` to `'new'` or `'attach'`. Helper copy under each:
- *create new vault* — "I'm setting up relicario for the first time. This will create a fresh encrypted vault on a new or empty git repository."
- *create new vault* — "I'm setting up Relicario for the first time. This will create a fresh encrypted vault on a new or empty git repository."
- *attach this device* — "I already have a vault on another device. Connect this browser to it using my passphrase and reference image."
### Step 1: host type
@@ -93,7 +93,7 @@ The "switch mode" buttons preserve all entered host config so the user does not
**Warning card copy (mode=new, vault present):**
> ⚠ This repository already contains a relicario vault.
> ⚠ This repository already contains a Relicario vault.
> Last commit: `<sha7>` by `<author>` on `<date>`.
>
> Creating a new vault here would overwrite the existing one and **destroy all data inside**. To use this vault on this device, switch to *attach* mode instead.

View File

@@ -1,12 +1,12 @@
# relicario import / export — design
# Relicario import / export — design
Date: 2026-04-27
Status: design (not yet implemented)
Scope: backup / restore (round-trippable to relicario itself) + LastPass CSV import. Migration **out** to other tools is explicitly out of scope.
Scope: backup / restore (round-trippable to Relicario itself) + LastPass CSV import. Migration **out** to other tools is explicitly out of scope.
## Motivation
Self-hosting a password vault without a backup story is unacceptable for production use. Today, a relicario user has no way to:
Self-hosting a password vault without a backup story is unacceptable for production use. Today, a Relicario user has no way to:
1. **Snapshot** their vault for disaster recovery (git remote going away, repo corruption, account loss).
2. **Onboard** from an existing manager — there's no migration path for a user with credentials in another tool.
@@ -18,13 +18,13 @@ The following choices were brainstormed and approved before this spec was writte
| # | Decision |
|---|---|
| D1 | Two features, one spec: backup/restore round-trippable to relicario, plus a LastPass CSV importer. Migration out is out of scope. |
| D1 | Two features, one spec: backup/restore round-trippable to Relicario, plus a LastPass CSV importer. Migration out is out of scope. |
| D2 | Backup file format: single-file `.relbak` container. Magic header + version + salt + nonce + AEAD-encrypted, zstd-compressed JSON envelope with base64'd binary blobs. |
| D3 | AEAD: XChaCha20-Poly1305 (same primitive used for vault items, but the backup format uses its own envelope with magic header + version byte; it does **not** reuse the `crypto.rs` `encrypt`/`decrypt` helpers, which assume the vault-master-key format). KDF: Argon2id with the same parameters as v1 of the live vault (m=64MiB, t=3, p=4) — but the params are tied to **backup format version**, not read from the vault's `params.json`. |
| D4 | Backup passphrase is independent of the vault passphrase. User picks one at export; user types it at restore. Reusing the vault passphrase is allowed but not auto-filled. |
| D5 | Reference image inclusion is optional. `--include-image` flag (CLI) / checkbox (UI). When included, the image is base64'd into the encrypted envelope — never in the clear inside the file. |
| D6 | Git history (`.git/`) is included **by default**. `--no-history` opt-out for users who want a smaller file at the cost of audit trail and remote URL. |
| D7 | Restore semantics: refuse if the target directory already contains a relicario vault. Restore is a fresh round-trip operation, not a merge. |
| D7 | Restore semantics: refuse if the target directory already contains a Relicario vault. Restore is a fresh round-trip operation, not a merge. |
| D8 | Backup passphrase strength: zxcvbn score ≥ 3, same gate as `init`. Backup is single-factor (one passphrase decrypts the container), so it must be at least as strong as a vault factor. |
| D9 | The user is responsible for deleting the backup file after restore is verified. The encryption protects it in transit / at rest while it exists; it is not a defense against forensic recovery of deleted copies. Documented in CLI help text and the extension UI. |
| D10 | LastPass import: parse the standard LastPass CSV (`url,username,password,totp,extra,name,grouping,fav`). Logins → `Login` items (with embedded TOTP if present); rows with `url == http://sn``SecureNote`; structured LastPass notes (cards, SSH keys, addresses) are **not** auto-parsed — they fall through as `SecureNote` with `extra` as the body. |
@@ -215,7 +215,7 @@ Future format v2 may change these; v1 readers will see `version != 0x01` and pro
## LastPass field mapping
| LastPass column | relicario destination | Notes |
| LastPass column | Relicario destination | Notes |
|---|---|---|
| `name` | `Item.title` | Required; row skipped with warning if missing |
| `grouping` | `Item.group` | `None` if empty |
@@ -246,11 +246,11 @@ Atomicity: output uses the existing `atomic_write` helper (write `.tmp` → rena
| Error | Detection | User-facing message | Recovery |
|---|---|---|---|
| Bad magic | First 4 bytes ≠ `"RBAK"` | `"not a relicario backup file"` | Verify file |
| Unsupported version | Version byte > current (1) | `"backup created by a newer relicario; upgrade required"` | Update binary |
| Bad magic | First 4 bytes ≠ `"RBAK"` | `"not a Relicario backup file"` | Verify file |
| Unsupported version | Version byte > current (1) | `"backup created by a newer Relicario; upgrade required"` | Update binary |
| Wrong backup passphrase | AEAD authentication fails | `"wrong backup passphrase, or the file is corrupt"` (deliberately ambiguous) | Retry |
| Target dir already has a vault | `target/.relicario/` exists | `"target dir already contains a relicario vault; restore refuses to overwrite — use an empty directory"` | Choose empty dir |
| Schema mismatch | envelope.schema_version != current | `"backup is schema v<N>; this relicario reads v<M>"` | Use matching binary |
| Target dir already has a vault | `target/.relicario/` exists | `"target dir already contains a Relicario vault; restore refuses to overwrite — use an empty directory"` | Choose empty dir |
| Schema mismatch | envelope.schema_version != current | `"backup is schema v<N>; this Relicario reads v<M>"` | Use matching binary |
| Mid-restore crash | (no detection) | — | User deletes target dir, retries |
Atomicity: best-effort. If interrupted mid-write, target dir has partial files — user cleans up and retries. Documented limitation. Restore is rare enough that engineering atomic-rename of multiple files is not worth the complexity.

View File

@@ -24,7 +24,7 @@ Sidebar + detail pane, similar to 1Password's desktop app:
```
┌──────────────────────────────────────────────────┐
│ 🔒 relicario [lock] [settings] │
│ 🔒 Relicario [lock] [settings] │
├────────────────┬─────────────────────────────────┤
│ [search...] │ │
│ │ (detail view for selected │

View File

@@ -7,7 +7,7 @@
## Background
relicario's two-factor model derives `master_key = Argon2id(len-prefixed(passphrase) || image_secret, salt, params)` (`crates/relicario-core/src/crypto.rs:207`). Lose either factor and the vault is unrecoverable. The reference image is the more loseable factor — it lives outside the user's head, often as a "dead drop" on social media or a personal site, and a single platform takedown or accidental deletion permanently bricks the vault.
Relicario's two-factor model derives `master_key = Argon2id(len-prefixed(passphrase) || image_secret, salt, params)` (`crates/relicario-core/src/crypto.rs:207`). Lose either factor and the vault is unrecoverable. The reference image is the more loseable factor — it lives outside the user's head, often as a "dead drop" on social media or a personal site, and a single platform takedown or accidental deletion permanently bricks the vault.
The original design spec already sketched a post-V1 recovery path (`docs/superpowers/specs/2026-04-11-relicario-design.md:342-349`): a small encrypted file containing only `image_secret`, locked under the passphrase via a separate Argon2id derivation, stored offline. This spec finalizes that sketch with three refinements landed during brainstorming: