Skip to content

Add in-app PGP key setup wizard for YubiKey onboarding - #36

Open
jordan-unchained wants to merge 2 commits into
unchained-capital:mainfrom
jordan-unchained:pgp-key-setup
Open

Add in-app PGP key setup wizard for YubiKey onboarding#36
jordan-unchained wants to merge 2 commits into
unchained-capital:mainfrom
jordan-unchained:pgp-key-setup

Conversation

@jordan-unchained

@jordan-unchained jordan-unchained commented May 28, 2026

Copy link
Copy Markdown

Summary

Adds a guided, in-app setup wizard for YubiKey PGP key provisioning and day-to-day card management. Today these steps are performed manually via terminal commands (ykman, gpg, Homebrew/winget installs, agent configuration, etc.). This change wraps those operations in a step-by-step UI so Coordinators and clients can onboard a new YubiKey, register an existing key on a new computer, change PINs, or unblock a blocked User PIN without leaving GPG Bridge.

The private key always remains on the YubiKey — the wizard generates keys on-card or imports a public-key stub; it never handles secret key material as a file transfer.

Motivation

  • New YubiKey / lost key replacement — install dependencies, reset the OpenPGP applet, generate an Ed25519 signing key on-card, set touch policy, change factory default PINs, and verify signing.
  • New computer — install dependencies, configure the GPG agent, register the existing YubiKey with GPG via gpg --card-status, and verify signing. No private key export is required because the key lives on the hardware token.
  • Ongoing PIN management — change User/Admin PINs or unblock a blocked User PIN from the main window, tray menu, or menu bar without running ykman manually.
  • Key transfer helper — export the armored public key to disk (for FlowCrypt transfer to a new machine) via a native save dialog from the YubiKey menu / tray.

Architecture

New files

File Role
setup-handler.js Main-process module. Runs all gpg / ykman / package-manager operations. Streams progress back to the wizard via a callback.
setup.html Wizard UI shell — pathway selection, step screens, progress output panel.
setup.js Renderer logic — pathway routing, form validation, step orchestration, IPC calls.

Modified files

File Role
main.js Setup window lifecycle, IPC handler registration, YubiKey menu + tray entries, export-public-key dialog, Edit menu (macOS clipboard shortcuts), before-quit cleanup for detached ykman children.
preload.js Exposes setupAPI (wizard IPC bridge) and main-window helpers (openSetupWizard, openChangePins, openUnblockPin).
index.html Adds launcher buttons for setup, change PINs, and unblock PIN below the log panel.
renderer.js Wires the new buttons to preload IPC helpers.

Wizard pathways

  1. New YubiKey Setup (new) — deps → GPG agent → detect card → reset OpenPGP → user info → set key attributes → generate key on-card → touch policy → change default PINs → test sign.
  2. Moving to a New Computer (migrate) — deps → GPG agent → detect card → import card stub (gpg --card-status) → test sign. Optional public-key file import if keyserver lookup fails.
  3. Change PINs (change-pin) — detect card → PIN form → run ykman openpgp keys set-retries + PIN change commands.
  4. Unblock User PIN (unblock-pin) — detect card → admin PIN + new user PIN form → run unblock.

Pathways can be opened from the welcome screen, or launched directly (skipping welcome) via URL hash / tray / menu bar shortcuts for PIN operations.

IPC design

  • All wizard operations use ipcMain.handle channels prefixed with setup:.
  • Handlers are wrapped in safeHandle(), which returns a uniform { ok: true, value } or { ok: false, error } envelope instead of throwing across the IPC boundary. Errors are surfaced in the wizard's output panel rather than polluting the main bridge window log.
  • Long-running steps emit setup:progress events with typed messages (info, output, success, warning, error).
  • Factory default YubiKey PINs (123456 / 12345678) are applied only in the main process during the new-setup PIN-change step — the renderer never sees or transmits them.
  • The window close button is locked while an async operation is in progress; attempting to close shows a confirmation dialog to prevent leaving the card in a half-finished state.

setup-handler.js highlights

  • Dependency management — detects and auto-installs platform tools: macOS (Homebrew → gnupg, pinentry-mac, ykman), Windows (winget → GPG4Win, YubiKey Manager), Linux (apt/dnf).
  • GPG agent configuration — writes gpg-agent.conf to the correct GPG home (including %APPDATA%\gnupg on Windows), sets pinentry, reloads scdaemon/agent with settle delays to avoid intermittent "card not present" errors.
  • On-card key generation — sets Ed25519 attributes, generates the key via loopback pinentry, purges stale local secret keys for the same email, configures touch policy.
  • Migration — imports the card stub and optionally accepts a public key file via native open dialog.
  • PIN operations — validates PIN length/constraints, changes PINs, unblocks blocked User PINs.
  • Verification — test signing step confirms the key is usable end-to-end.
  • Export — finds YubiKey-backed fingerprints and writes an armored public key for cross-machine transfer.

Entry points

  • Main window buttons: PGP Key Setup, Change PINs, Unblock User PIN
  • Menu bar: YubiKey menu with setup, PIN, and export actions
  • System tray context menu: same actions

Export Public Key is intentionally limited to native menus (not exposed through preload) to keep the IPC attack surface minimal.

Other notes

  • macOS Edit menu added so cut/copy/paste keyboard shortcuts work in wizard text fields (PIN inputs, name/email).
  • Detached ykman child processes are tracked and killed on app quit so they do not survive a parent crash.

Test plan

Testing should be performed on macOS, Windows, and Linux. Each platform uses a different dependency install path (Homebrew, winget, apt/dnf) and GPG home layout, so all three need explicit verification — not just a macOS pass with spot checks elsewhere.

macOS

  • New YubiKey pathway — launch wizard from main window; complete full new-key flow on a factory-reset or test YubiKey. Confirm Homebrew deps install (or are detected), GPG agent config is written, card is detected, key generation + PIN change from defaults succeed, and test signing passes.
  • New computer pathway — on a machine without an existing card stub, run migrate with a YubiKey that already has a key. Confirm card stub import and test signing pass.
  • PIN management — open Change PINs from tray/menu; change User and Admin PINs. Block User PIN (3 wrong attempts), then run Unblock User PIN with Admin PIN.
  • Export — save public key via tray/menu; confirm valid armored .asc output.
  • Clipboard — confirm cut/copy/paste work in wizard PIN and name/email fields (Edit menu).
  • Regression — existing signing server and main window log unchanged; wizard close-confirmation appears during long-running steps.

Windows

  • New YubiKey pathway — complete full new-key flow. Confirm winget installs GPG4Win and YubiKey Manager (or detects existing installs), GPG agent config lands in %APPDATA%\gnupg, card is detected, key generation + PIN change succeed, and test signing passes.
  • New computer pathway — run migrate on a fresh Windows install with an existing YubiKey. Confirm card stub import and test signing pass.
  • Public key file import — test the open-file dialog fallback on migrate if keyserver lookup is unavailable.
  • PIN management — change PINs and unblock a blocked User PIN via tray menu entry points.
  • Export — save public key to Desktop; confirm valid armored output.
  • Regression — existing signing server and main window log unchanged; wizard close-confirmation during long-running steps.

Linux

  • New YubiKey pathway — complete full new-key flow. Confirm apt or dnf dependency install succeeds (or detects existing packages), GPG agent config is written to ~/.gnupg, card is detected, key generation + PIN change succeed, and test signing passes.
  • New computer pathway — run migrate on a machine without an existing card stub. Confirm import and test signing pass.
  • PIN management — change PINs and unblock a blocked User PIN.
  • Export — save public key; confirm valid armored output.
  • Regression — existing signing server and main window log unchanged; wizard close-confirmation during long-running steps.

Cross-platform (after per-OS passes)

  • Verify GPG Bridge signing flow works with the configured key on each platform after setup completes.
  • Confirm entry points (main window buttons, tray menu, YubiKey menu bar on macOS) all open the correct wizard pathway.

…ment.

Introduces a guided setup flow covering new YubiKey provisioning, new-computer
migration, PIN changes, and PIN unblocking, with all GPG/ykman operations
running in the main process behind a structured IPC layer.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread setup-handler.js Outdated
Comment thread setup-handler.js Outdated
…ard.

Avoid curl|bash Homebrew bootstrap and in-app package managers; detect missing tools and show targeted brew, winget, apt, and dnf commands with Retry instead.

Co-authored-by: Cursor <cursoragent@cursor.com>
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