Skip to content

feat(vpn/wireguard): display the public key as a QR code - #234

Open
RISK-alt wants to merge 1 commit into
cloud-gouv:mainfrom
RISK-alt:feat/wireguard-pubkey-qrcode
Open

feat(vpn/wireguard): display the public key as a QR code#234
RISK-alt wants to merge 1 commit into
cloud-gouv:mainfrom
RISK-alt:feat/wireguard-pubkey-qrcode

Conversation

@RISK-alt

@RISK-alt RISK-alt commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

What

wireguard-<vpn-name>-pubkey now renders the WireGuard public key as a QR code, below the text it already prints.

Why

Registering a machine with a VPN peer means moving a 44-character base64 key across machines by hand. A scannable code removes the retyping, and the typos that come with it.

importkey already calls pubkey, so the QR code also shows up right after key generation, which is where it is most useful. No new dependency is introduced: qrencode is already part of the project's package set in modules/tools/default.nix.

Implementation notes

-t ANSIUTF8 rather than -t UTF8. UTF8 emits no colour escape at all, so the blocks take the terminal's own palette; on a light background the quiet zone renders dark, the code is inverted, and most phone scanners refuse to read it. ANSIUTF8 emits \e[40;37;1m, pinning background and foreground, so the polarity stays correct on any theme.

The key is bound to a shell variable instead of being computed twice. The private key is read from the YubiKey, whose touch policy is always (set in importkey via --touch-policy always), so a second call would ask for another physical touch to run a single command.

Testing

Verified locally:

  • nixfmt -sc, statix check --config statix.toml and reuse --root . lint all pass — the same commands the CI workflows run.
  • The pubkey derivation builds. The module was instantiated on its own with a dummy WireGuard profile and the generated script inspected: qrencode resolves to a store path, so it does not rely on $PATH.
  • QR round-trip: a throwaway key (wg genkey | wg pubkey) encoded with the qrencode version pinned by the derivation, then decoded back with zbarimg, returns the identical 44-character string.
  • The ANSIUTF8 output was scanned with a phone from a terminal, on both a light and a dark theme.

Not verified: the full path through the YubiKey, for lack of the hardware. That path is untouched by this PR — the only new code is the two lines after wg pubkey.

I did not run nix-build -A tests locally: no test in tests/ enables securix.vpn.wireguard, so the suite would not exercise this code path. Happy to add a test if you would like one.

Closes #223

Registering a machine with a VPN peer currently means transferring the
WireGuard public key by hand: 44 base64 characters, retyped or copied
between machines. `wireguard-<vpn-name>-pubkey` now renders that key as
a QR code below the text it already prints, so it can be scanned
instead.

No new dependency: qrencode is already part of the project's package
set in modules/tools/default.nix.

`importkey` already calls `pubkey`, so the QR code also appears right
after key generation, which is where it is most useful.

Two implementation details worth noting:

- `-t ANSIUTF8` rather than `-t UTF8`. UTF8 emits no colour escape at
  all, so the blocks inherit the terminal palette and the code comes
  out inverted on a light background, which most phone scanners reject.
  ANSIUTF8 pins the colours, keeping the polarity correct on any theme.

- The public key is bound to a shell variable instead of being computed
  twice. The private key is read from the YubiKey, whose touch policy
  is `always`, so a second call would ask for another touch to run a
  single command.

@rlahfa-dinum rlahfa-dinum left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks reasonable to me.

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.

Add QRCode for wireguard public key

2 participants