From 0a3156855cf2a3f395343d93b9c33715a707fd7b Mon Sep 17 00:00:00 2001 From: Patrick Mulligan Date: Wed, 5 Aug 2026 05:01:08 +0200 Subject: [PATCH] feat(deploy): authorize bitspire for pcscd (polkit) + NFC diagnostics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit pcscd gates clients via polkit; the sandboxed bitspire user was "Rejected unauthorized PC/SC client", so add a polkit rule granting it access_pcsc/access_card. Also log NFC reader status + taps from the main process to journald (value redacted — it carries the card's SUN p/c) so reader detection and taps are observable during testing. Co-Authored-By: Claude Opus 4.8 --- apps/machine/electron/main.ts | 13 +++++++++++-- deploy/nixos/hardware/batm3.nix | 13 +++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/apps/machine/electron/main.ts b/apps/machine/electron/main.ts index ac15f6e..81676cf 100644 --- a/apps/machine/electron/main.ts +++ b/apps/machine/electron/main.ts @@ -833,8 +833,17 @@ app.whenReady().then(() => { // best-effort: if the reader/pcscd is absent it just reports 'unavailable' // and the cash-out QR path is unaffected. void startNfcReader( - (lnurlw) => mainWindow?.webContents.send('nfc:card-tapped', lnurlw), - (status) => mainWindow?.webContents.send('nfc:status', status) + (lnurlw) => { + // Don't log the value — it carries the card's single-use SUN p/c. + console.log(`[NFC] card tapped — lnurlw (${lnurlw.length} chars) → renderer`) + mainWindow?.webContents.send('nfc:card-tapped', lnurlw) + }, + (status: NfcStatus) => { + console.log( + `[NFC] status=${status.state}${status.reader ? ` reader="${status.reader}"` : ''}${status.message ? ` — ${status.message}` : ''}` + ) + mainWindow?.webContents.send('nfc:status', status) + } ) app.on('activate', () => { diff --git a/deploy/nixos/hardware/batm3.nix b/deploy/nixos/hardware/batm3.nix index a03c830..40983c9 100644 --- a/deploy/nixos/hardware/batm3.nix +++ b/deploy/nixos/hardware/batm3.nix @@ -92,6 +92,19 @@ # attached — pcscd just idles. services.pcscd.enable = true; + # pcscd gates client access via polkit; without a rule the sandboxed + # `bitspire` service user is "Rejected unauthorized PC/SC client". Authorize + # it to talk to the daemon and the card. + security.polkit.extraConfig = '' + polkit.addRule(function(action, subject) { + if ((action.id == "org.debian.pcsc-lite.access_pcsc" || + action.id == "org.debian.pcsc-lite.access_card") && + subject.user == "bitspire") { + return polkit.Result.YES; + } + }); + ''; + # Disable suspend/hibernate for kiosk systemd.targets = { sleep.enable = false;