Commit Graph

167 Commits

Author SHA1 Message Date
adlee-was-taken
2d1f0926ae refactor(cli): move cmd_add + 7 build_*_item helpers into commands/add.rs 2026-05-08 21:58:49 -04:00
adlee-was-taken
64275bc64f refactor(cli): move cmd_edit family into commands/edit.rs 2026-05-08 21:48:35 -04:00
adlee-was-taken
2d5b86bf20 refactor(cli): move cmd_device + load_gitea_client into commands/device.rs 2026-05-08 19:32:39 -04:00
adlee-was-taken
08bdfbc7c4 refactor(cli): move cmd_settings into commands/settings.rs 2026-05-06 19:42:22 -04:00
adlee-was-taken
3811b07014 refactor(cli): move cmd_recovery_qr family into commands/recovery_qr.rs 2026-05-06 19:41:04 -04:00
adlee-was-taken
6676d2502b refactor(cli): move attach family (attach/attachments/extract/detach) into commands/ 2026-05-06 19:40:13 -04:00
adlee-was-taken
615afd7483 refactor(cli): move cmd_import into commands/import.rs 2026-05-06 19:37:35 -04:00
adlee-was-taken
c2f3c35ac9 refactor(cli): move cmd_backup into commands/backup.rs 2026-05-06 18:53:40 -04:00
adlee-was-taken
530c479f19 refactor(cli): move trash family (rm/restore/purge/trash) into commands/ 2026-05-06 18:48:00 -04:00
adlee-was-taken
da7d7d162c refactor(cli): move cmd_get/list/history/status/sync into commands/ 2026-05-06 18:43:41 -04:00
adlee-was-taken
13c2fc2bd7 refactor(cli): hoist commit_paths + resolve_query into commands/mod.rs 2026-05-06 18:36:01 -04:00
adlee-was-taken
b9b07ec68d refactor(cli): move cmd_init into commands/init.rs (carries inline ParamsFile) 2026-05-06 18:32:36 -04:00
adlee-was-taken
17bde162cd refactor(cli): move cmd_generate + cmd_rate into commands/ 2026-05-06 18:27:41 -04:00
adlee-was-taken
52400230e0 refactor(cli): move parse helpers into parse.rs 2026-05-06 18:23:37 -04:00
adlee-was-taken
272b6a3845 refactor(cli): move prompt helpers into prompt.rs 2026-05-06 18:20:33 -04:00
adlee-was-taken
02e05f7a05 refactor(cli): add commands/, prompt.rs, parse.rs scaffold (no-op) 2026-05-06 17:42:38 -04:00
adlee-was-taken
cf66bd97b7 chore: bump crate and extension versions to 0.5.0
Catches the workspace and the extension manifests up to the v0.5.x
release line (was still showing 0.2.0).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-05 17:49:09 -04:00
adlee-was-taken
f17944a404 fix(core,wasm): correct QR version comment, expect msg, zeroize image_secret in closure 2026-05-03 21:09:02 -04:00
adlee-was-taken
a6071b4c0c feat(cli): recovery-qr generate / unwrap subcommands
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-03 21:01:29 -04:00
adlee-was-taken
ada00895d4 feat(wasm): expose generate_recovery_qr and unwrap_recovery_qr bindings 2026-05-03 20:57:55 -04:00
adlee-was-taken
42b746f9af feat(wasm): session stores image_secret for recovery QR generation 2026-05-03 20:56:39 -04:00
adlee-was-taken
762a008171 test(core): recovery_qr roundtrip + error cases 2026-05-03 20:53:59 -04:00
adlee-was-taken
f93bce7388 chore(core): re-export recovery_qr module 2026-05-03 20:51:36 -04:00
adlee-was-taken
8eabaf5f31 feat(core): recovery_qr generate + unwrap + SVG functions 2026-05-03 20:51:33 -04:00
adlee-was-taken
04142dc116 feat(core): add derive_master_key_raw + RecoveryQr error variant 2026-05-03 20:51:29 -04:00
adlee-was-taken
8739f1f67b chore(core): add qrcode dependency for recovery QR 2026-05-03 20:48:38 -04:00
adlee-was-taken
4d02a50cc8 chore(core): fix pre-existing clippy warnings (-D warnings gate)
Resolves pre-existing lint issues in imgsecret.rs, time.rs, totp.rs,
and crypto.rs that blocked the cargo clippy --workspace -D warnings
gate. No logic changes: loop-index → iterator, manual div_ceil →
.div_ceil(), manual range contains → .contains(), auto-deref cleanup.

Also fixes pre-existing warnings in relicario-cli (main.rs, session.rs,
device.rs, gitea.rs, helpers.rs, test helpers): dead_code suppression,
too_many_arguments, literal_with_empty_format_string, manual_char_cmp,
map_or → is_none_or, and repeat().take() → vec! in test helpers.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 19:32:45 -04:00
adlee-was-taken
006e67c361 fix(cli): cfg-gate RELICARIO_NO_GROUPS_CACHE to debug builds (audit S3)
The groups-cache opt-out is a developer debugging knob, not a
user-facing config. Gating the env-var lookup behind cfg!(debug_assertions)
makes release builds ignore the variable; the optimiser removes the
lookup entirely, so the variable name doesn't appear in release binary
strings output.

Doc-comments updated to reflect the new behaviour.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-02 18:51:15 -04:00
adlee-was-taken
6a1c6d5875 fix(core,cli): harden backup-restore tar unpack against path traversal (audit S2)
cmd_backup_restore previously called tar::Archive::unpack with default
settings, allowing malicious .relbak archives to escape the target
directory via .. entries, absolute paths, or symlinks. No size cap
meant tar bombs could exhaust disk space.

Replaced with relicario_core::safe_unpack_git_archive which:
- Rejects .. (ParentDir), absolute (RootDir), and drive-prefix
  (Prefix) components with "path traversal blocked" error.
- Rejects symlinks and hardlinks outright.
- Checks declared header size before reading body; rejects entries or
  cumulative totals exceeding the caller's cap.
- Returns (relative-path, bytes) pairs; the CLI re-checks
  dest.starts_with(git_dir) after OS-level path resolution.
- CLI cap: min(100 × compressed size, 1 GiB).

Acceptance: 5 unit tests in relicario-core (traversal, absolute path,
symlink, size bomb, happy path); existing CLI backup roundtrip tests
remain green.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 17:16:11 -04:00
adlee-was-taken
efac53d527 fix(server): real signature verification in pre-receive hook (audit S1)
verify_commit previously loaded devices.json/revoked.json and threw
both away, accepting any commit whose stderr contained "GOODSIG" or
"Good signature". This left device registration and revocation as
no-ops: unregistered keys could push, revoked keys kept working.

The fix:
- Build a temp gpg.ssh.allowedSignersFile from devices.json at the
  commit, passed via GIT_CONFIG_COUNT/KEY/VALUE env (no global git
  config mutation).
- Run git verify-commit --raw and parse SHA256 fingerprint from stderr
  regardless of exit code (SSH git outputs the "Good" line even for
  keys not in allowed-signers, with "No principal matched" + exit 1).
- Check revoked.json FIRST: reject if committer_ts >= revoked_at;
  accept historical commits (committer_ts < revoked_at).
- Reject if fingerprint is not in active devices.json.
- Bootstrap: accept only when BOTH devices.json AND revoked.json are
  empty/absent (not just devices.json alone).

Acceptance: 4 integration tests covering the matrix.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 16:34:37 -04:00
adlee-was-taken
d539050aec chore(server): add assert_cmd/predicates/tempfile dev-deps
Needed for the upcoming verify-commit acceptance suite (audit S1).

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-02 16:23:24 -04:00
adlee-was-taken
8a72b5e192 feat(core): add device::fingerprint helper for SSH SHA256 fingerprints
Wraps ssh-key's PublicKey::fingerprint(HashAlg::Sha256). Output format
matches ssh-keygen -lf and git verify-commit --raw stderr
(SHA256:<43-char base64>). Used by the upcoming relicario-server
verify-commit rewrite (audit S1).

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-05-02 16:23:10 -04:00
adlee-was-taken
fb1f28161c feat(wasm): secure device API (private keys never cross to JS)
- register_device() generates signing + deploy keypairs via core device
  module, stores them in DEVICE_STATE (once_cell Lazy<Mutex>), and
  returns only public keys to JS
- sign_for_git() signs data using the internal signing key
- get_device_info() returns name and public keys; returns null if not
  registered
- clear_device() zeroes and drops device state (logout / re-registration)
- Removed generate_device_keypair() which exposed raw private key bytes

Fixes audit I5: private key material no longer crosses the WASM boundary.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 12:27:50 -04:00
adlee-was-taken
15d691abb2 feat(cli): implement device revoke
- Remove device from devices.json
- Append to revoked.json with timestamp and revoked_by
- Delete Gitea deploy key (best-effort, warns if env vars missing)
- Always commit both devices.json and revoked.json together
- Print revoked signing public key for audit confirmation
- Guard against revoking the current device (would lose push access)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 12:22:59 -04:00
adlee-was-taken
b1f9f2fbfc feat(cli): implement device add with signing + deploy key
- Create crates/relicario-cli/src/device.rs: local key storage under
  ~/.config/relicario/devices/<name>/, current-device tracking, and
  git signing config (gpg.format=ssh, user.signingkey, core.sshCommand)
- Add Device command to CLI with add/revoke/list subcommands
- cmd_device add: generates two ed25519 keypairs (signing + deploy),
  registers deploy key via Gitea API, stores keys at 0600, configures
  git SSH signing, updates .relicario/devices.json and commits
- Gitea config read from flags or RELICARIO_GITEA_{URL,TOKEN,OWNER,REPO}
- --no-gitea flag skips API registration for non-Gitea remotes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 12:19:55 -04:00
adlee-was-taken
61f2f9c18f feat(server): add relicario-server for pre-receive hook
- verify-commit command checks signature against devices.json
- generate-hook outputs installable pre-receive script
- Foundation for server-side enforcement

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-02 12:15:57 -04:00
adlee-was-taken
7e07d5d664 feat(cli): add Gitea API client for deploy keys
Create, delete, and list deploy keys via Gitea REST API.
Foundation for device authentication.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-02 12:14:46 -04:00
adlee-was-taken
dc683c7e4c feat(core): add device module with ed25519 signing
OpenSSH-format keypair generation, signing, and verification.
Foundation for device authentication.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-02 12:13:57 -04:00
adlee-was-taken
b9f44a3d4f fix(cli): enforce per-vault attachment bytes cap (audit I3)
per_vault_soft_cap_bytes and per_vault_hard_cap_bytes were defined in
VaultSettings but never checked. Now enforced in cmd_attach with
warning at soft cap, error at hard cap.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-02 09:34:33 -04:00
adlee-was-taken
d6703be2b1 fix(cli): sanitize item titles in commit messages (audit I1)
Control characters (newlines, tabs) in item titles corrupted git log
output. Now strips control chars and truncates to 50 chars.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-02 09:29:49 -04:00
adlee-was-taken
81f1f8ec31 fix(cli): validate IDs on backup restore (audit B4)
Crafted .relbak files with IDs like "../../.bashrc" could escape the
target directory. Now validates that item/attachment IDs are hex-only
via is_valid() before any fs::write.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-02 02:21:49 -04:00
adlee-was-taken
2739eb4194 fix(cli): gate test env vars with #[cfg(debug_assertions)] (audit B3)
RELICARIO_TEST_PASSPHRASE and friends were checked in production code,
exposing the passphrase via /proc/<pid>/environ and shell history.

Now only compiled into debug binaries via cfg(debug_assertions) helper
functions. Release builds compile the helpers to return None, so the
env var names are absent from the release binary (verified via strings).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-02 01:46:13 -04:00
adlee-was-taken
628e2bd636 fix(core): disable HOTP with clear error (audit I6)
HOTP requires incrementing and persisting the counter after each use.
Without vault-save machinery in compute_totp_code, HOTP would desync
immediately. Now returns HotpNotSupported error.

TOTP and Steam codes continue to work.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-02 01:36:31 -04:00
adlee-was-taken
466efe4b8a fix(core): expand AttachmentId to 128 bits, add is_valid (audit I2, B4)
- AttachmentId now uses 16 bytes of SHA-256 (128 bits) instead of 8,
  requiring ~2^64 work for birthday collision instead of ~2^32.
- Added is_valid() to ItemId and AttachmentId for path traversal
  prevention during backup restore.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-02 01:32:48 -04:00
adlee-was-taken
bbdbcca87b fix(core): NFC normalize backup passphrase (audit B2)
Backup KDF was passing raw passphrase bytes to Argon2id without NFC
normalization, causing cross-platform restore failures for non-ASCII
passphrases (macOS NFD vs Linux NFC).

Now matches derive_master_key behavior from crypto.rs.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-05-02 01:29:08 -04:00
adlee-was-taken
315967f4a1 Merge feature/fullscreen-ux-phase-2a: smart-input affordances
Phase 2A of the fullscreen UX redesign — 8 form-level smart-input
affordances (URL fill-from-tab + hostname chip, group autocomplete,
password reveal + strength bar, TOTP live preview + QR decode, notes
monospace toggle), shared between popup and fullscreen vault tabs via
the new extension/src/shared/form-affordances/ module set.

CLI parity:
- relicario rate <passphrase> (zxcvbn score / guess estimate)
- relicario completions <SHELL> (bash/zsh/fish via clap_complete)
- --group <TAB> dynamic enumeration via .relicario/groups.cache
  (plaintext leak surface; opt out with RELICARIO_NO_GROUPS_CACHE=1)
- --totp-qr <path> on add login + edit (rqrr decode)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 22:37:18 -04:00
adlee-was-taken
8855078179 cli: --totp-qr <path> flag on add login + edit (rqrr decode)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 22:22:20 -04:00
adlee-was-taken
ed2d299a92 cli: add 'rate <passphrase>' subcommand (zxcvbn) 2026-05-01 19:53:29 -04:00
adlee-was-taken
f7e245d6b0 cli: write groups.cache for shell-completion --group enumeration
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-01 18:19:53 -04:00
adlee-was-taken
6cbd011705 cli: add 'completions <SHELL>' subcommand via clap_complete 2026-05-01 18:13:17 -04:00