Skip to content

Add Rust+WASM OpenPGP client with post-quantum vault (Vue, Kleopatra-style) - #1

Merged
l5z12 merged 14 commits into
mainfrom
claude/gpg-rust-wasm-frontend-B45VN
Jun 9, 2026
Merged

Add Rust+WASM OpenPGP client with post-quantum vault (Vue, Kleopatra-style)#1
l5z12 merged 14 commits into
mainfrom
claude/gpg-rust-wasm-frontend-B45VN

Conversation

@l5z12

@l5z12 l5z12 commented Jun 9, 2026

Copy link
Copy Markdown
Owner

crypto-core (Rust -> WASM):

  • Full OpenPGP via rPGP: key generation (Curve25519/Ed25519/RSA/NIST),
    encrypt/decrypt to multiple recipients, inline/detached/cleartext
    signatures and verification, key inspection and public-key extraction.
  • draft-pqc post-quantum OpenPGP keys (ML-DSA, SLH-DSA, ML-KEM).
  • Post-quantum local vault: ML-KEM-768 + AES-256-GCM + Argon2id.

web (Vue 3 + Vite + Pinia):

  • Kleopatra-style UI: certificates, notepad, sign/verify, settings, about.
  • Encrypted localStorage keyring guarded by the post-quantum vault.
  • Portable .gnupg home export (importable by the real gpg binary).
  • Responsive desktop + mobile layout.

Includes a Node runtime test harness and CI workflow.

claude added 14 commits June 8, 2026 11:08
…style)

crypto-core (Rust -> WASM):
- Full OpenPGP via rPGP: key generation (Curve25519/Ed25519/RSA/NIST),
  encrypt/decrypt to multiple recipients, inline/detached/cleartext
  signatures and verification, key inspection and public-key extraction.
- draft-pqc post-quantum OpenPGP keys (ML-DSA, SLH-DSA, ML-KEM).
- Post-quantum local vault: ML-KEM-768 + AES-256-GCM + Argon2id.

web (Vue 3 + Vite + Pinia):
- Kleopatra-style UI: certificates, notepad, sign/verify, settings, about.
- Encrypted localStorage keyring guarded by the post-quantum vault.
- Portable .gnupg home export (importable by the real gpg binary).
- Responsive desktop + mobile layout.

Includes a Node runtime test harness and CI workflow.
- Replace package-lock.json with bun.lock
- Add packageManager field; update dev scripts docs to bun run
- CI uses oven-sh/setup-bun and bun for install/build/test
- cloudflare-build.sh: installs Bun, uses committed WASM (or rebuilds the
  Rust core when REBUILD_WASM=1), runs bun install + build into web/dist
- web/public/_headers: long-cache for hashed assets + strict CSP
  (script-src includes 'wasm-unsafe-eval' for WebAssembly)
- wasm script now uses bun for the d.ts fixup
- README: Cloudflare Pages deployment section
- gitignore web/src/wasm/ and untrack the generated artifacts
- add a prebuild hook so 'bun run build' compiles the Rust core first
- cloudflare-build.sh now installs the Rust + wasm-pack toolchain and
  builds the WASM during deploy (no committed artifact)
- simplify CI and update README accordingly
Bars and label shade red → orange → amber → green as the score climbs,
with a smooth transition, instead of a fixed green.
Replace the custom-CSS / interim component layer with Nuxt UI:
- @nuxt/ui Vite plugin + vue-plugin; <UApp> root, useToast bridged to the
  existing toast() helpers
- Views/components rebuilt with U-components (UButton, UInput, USelect,
  UTextarea, UModal, UTabs, UCard, UFormField, UAlert, UBadge,
  UNavigationMenu, UButtonGroup, UInputNumber, USwitch)
- App shell reuses Nuxt UI semantic tokens (--ui-*) so chrome follows the
  dark/light setting via the .dark class
- Icons: bundle a curated Lucide subset (used icons + Nuxt UI defaults) via
  addCollection so nothing is fetched from the Iconify API at runtime —
  keeps the app offline and compatible with the strict CSP
- Generated auto-imports.d.ts / components.d.ts are gitignored

Type-check + build are green; production preview serves correctly.
On a fresh checkout the Vite plugin's generated auto-imports.d.ts doesn't
exist yet when 'vue-tsc' runs (it runs before vite build), so the auto-import
global 'useToast' was unresolved (TS2304). Import it from
'@nuxt/ui/composables' instead. Verified by building with the generated
d.ts files removed.
- Certificates view renders keys as tappable cards on narrow screens
  (≤820px) instead of the cramped table; table stays on desktop
- Scope the swap to the certificate table only (.cert-table) so the
  detail view's subkey table is unaffected
- Mobile: stack page header, full-width toolbar buttons, full-width
  search + segmented filter control, tighter content padding
- useAutoLock composable tracks last interaction and locks the vault once
  the configured idle timeout elapses; uses a timestamp + 5s interval so it
  also locks after device sleep/wake and re-checks on tab visibility
- New autoLockMinutes setting (default 15) with a Security section in
  Settings: Never / 1 / 5 / 15 / 30 / 60 minutes
- App resets the idle window on unlock and toasts on auto-lock
Security features:
- Warning banner when not served from l5z12.dev (or a subdomain); the
  allowed list is overridable at build time via VITE_OFFICIAL_DOMAINS.
  Banner sits above all screens (incl. lock screen), dismissible per session.
- Secret keys are now stored individually post-quantum-encrypted in the vault
  (secretKeyEnc) and decrypted on demand only for the key being used. Opening
  sec 2 no longer decrypts sec 1. The master password is retained in memory
  while unlocked (and wiped on lock/auto-lock) to enable per-key decryption.
  Includes migration of any legacy plaintext secretKey, and bulk on-demand
  decryption for .gnupg / secret-key export.
Add vault_unseal/vault_decrypt_with_key to the crypto core: at unlock the
password unseals the ML-KEM decapsulation key once, and only that derived
session key is kept in memory (wiped on lock/auto-lock). Per-key on-demand
secret decryption now uses the session key, so the plaintext master password
never persists past unlock. Unsealing with a wrong password fails the AEAD
tag, which also serves as password verification.

Updates the store (sessionKey replaces masterPassword), TS wrappers, README,
and the crypto-core test harness.
- Notepad now signs: with no recipients it produces a clear-signed message
  (-----BEGIN PGP SIGNED MESSAGE-----), matching Kleopatra; with recipients it
  encrypts (and signs inline if a key is chosen). Tabs renamed to
  'Sign / Encrypt' and 'Decrypt / Verify'.
- Decrypt / Verify auto-detects clear-signed input and verifies it against the
  keyring (no secret key needed), otherwise decrypts.
- Key generation uses a real 'valid until' date (default +2 years, Kleopatra
  style) with a never-expires toggle, instead of an 'expires in N days' field.
…parity

- Core: binary file functions encrypt_file / decrypt_file (auto-detects
  armor) / sign_file_detached / verify_file_detached, exposed over WASM as
  Uint8Array in/out; encrypt refactored onto a shared encrypt_bytes.
- New Files view with drag-and-drop: encrypt to recipients (+ optional inline
  sign, binary .gpg or armored .asc), detached-sign when no recipients
  (.sig.asc), decrypt to the original bytes, and verify a file against a
  detached signature. Added to the sidebar + router.
- Verified byte-exact round-trips on non-UTF-8 data in the Node test harness.
- About: 'Source & license' card linking github.com/l5z12/gpg4web and the
  GPL-3.0 text; sidebar footer shows a repo link + 'GPL-3.0'
- index.html: author/license meta + rel=license / rel=source links
- web/package.json: license, repository, homepage, bugs fields
- Bundle the github/scale Lucide icons
@l5z12
l5z12 merged commit 93bab35 into main Jun 9, 2026
3 checks passed
@l5z12
l5z12 deleted the claude/gpg-rust-wasm-frontend-B45VN branch June 9, 2026 05:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants