feat(access): access-control gate — npub-QR badge + PIN + dev bypass (ADR-003)
Squashed skeleton (was 11 commits on feat/access-control-skeleton) for a clean rebase onto dev. Adds a `locked` gate the terminal boots into until a credential is presented; opt-in and non-breaking (defaults off → boots straight to idle as before). - state-machine: `locked` state + ACCESS_GRANTED/ACCESS_DENIED/DEV_UNLOCK events + accessBypass/devUnlockAllowed guards (packages/state-machine). - services/access: reader abstraction, npub+PIN authorize() (nostr-tools nip19; accepts nostr:/nprofile), camera npub-QR reader, mock reader. - LockedView.vue + ColorModeToggle: branded viewfinder, PIN pad, denied reason, dev-unlock; camera off-by-default + idle return. - store/main/electron.d.ts: seed gate config, grant/deny/devUnlock wiring, access.json provisioning (no rebuild), get-config surface. - deploy: access.example.json + provision-access.sh; ADR-003. Credential union is npub today; UID (NFC tap) is the next step.
This commit is contained in:
parent
2ea3df01d1
commit
a7b409b109
20 changed files with 1534 additions and 28 deletions
5
deploy/nixos/access.example.json
Normal file
5
deploy/nixos/access.example.json
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"enabled": true,
|
||||
"openEnrollment": true,
|
||||
"devUnlock": true
|
||||
}
|
||||
69
deploy/nixos/provision-access.sh
Executable file
69
deploy/nixos/provision-access.sh
Executable file
|
|
@ -0,0 +1,69 @@
|
|||
#!/usr/bin/env bash
|
||||
# Provision the access-control gate (ADR-003) to a deployed bitSpire ATM.
|
||||
# Pushes an access.json to /var/lib/bitspire/ and restarts the service, so the
|
||||
# gate can be toggled on a machine without an image rebuild (mirrors
|
||||
# provision-branding.sh). Env defaults are overridden by whatever this file sets.
|
||||
#
|
||||
# Usage:
|
||||
# bash provision-access.sh <access.json> # SSH to localhost:2222 (QEMU)
|
||||
# bash provision-access.sh <access.json> 192.168.1.50 # a real ATM on the LAN
|
||||
# bash provision-access.sh <access.json> 192.168.1.50 22 # custom SSH port
|
||||
#
|
||||
# access.json schema (all keys optional; omitted keys fall back to env/defaults):
|
||||
# {
|
||||
# "enabled": true, // master switch for the gate
|
||||
# "openEnrollment": true, // prototype: admit any valid npub
|
||||
# "devUnlock": true, // allow the on-screen dev/operator unlock
|
||||
# "salt": "per-machine", // hashing salt (provision a real one for prod)
|
||||
# "allowList": [ // authorized identities (hashed); empty in open mode
|
||||
# { "idHash": "<hashId(hexpubkey,salt)>", "role": "user", "pinHash": "<hashPin(pin,salt)>" }
|
||||
# ]
|
||||
# }
|
||||
#
|
||||
# To DISABLE the gate again: push a file with {"enabled": false} (or delete
|
||||
# /var/lib/bitspire/access.json on the machine) and restart.
|
||||
set -euo pipefail
|
||||
|
||||
ACCESS_FILE="${1:-}"
|
||||
ATM_HOST="${2:-localhost}"
|
||||
ATM_SSH_PORT="${3:-2222}"
|
||||
ATM_USER="bitspire"
|
||||
REMOTE_FILE="/var/lib/bitspire/access.json"
|
||||
|
||||
if [ -z "$ACCESS_FILE" ]; then
|
||||
echo "Usage: $0 <access.json> [host] [port]" >&2
|
||||
echo " $0 ./access.json (QEMU on localhost:2222)" >&2
|
||||
echo " $0 ./access.json 192.168.1.50 (real ATM)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$ACCESS_FILE" ]; then
|
||||
echo "ERROR: access file not found: $ACCESS_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Fail fast on malformed JSON before touching the machine.
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
jq empty "$ACCESS_FILE" || { echo "ERROR: $ACCESS_FILE is not valid JSON" >&2; exit 1; }
|
||||
fi
|
||||
|
||||
echo "=== Provisioning access gate to $ATM_HOST:$ATM_SSH_PORT ==="
|
||||
echo "Local file : $ACCESS_FILE"
|
||||
echo "Remote file: $REMOTE_FILE"
|
||||
cat "$ACCESS_FILE"
|
||||
echo ""
|
||||
|
||||
# Copy over SSH. --rsync-path=sudo because /var/lib/bitspire is owned by the
|
||||
# bitspire service user, not the SSH user.
|
||||
rsync -avz \
|
||||
--rsync-path="sudo rsync" \
|
||||
-e "ssh -o StrictHostKeyChecking=no -p $ATM_SSH_PORT" \
|
||||
"$ACCESS_FILE" \
|
||||
"$ATM_USER@$ATM_HOST:$REMOTE_FILE"
|
||||
|
||||
# Restart so loadAccessControl() re-reads the file.
|
||||
ssh -o StrictHostKeyChecking=no -p "$ATM_SSH_PORT" "$ATM_USER@$ATM_HOST" \
|
||||
"sudo systemctl restart bitspire"
|
||||
|
||||
echo ""
|
||||
echo "=== Access gate provisioned. Service restarted. ==="
|
||||
Loading…
Add table
Add a link
Reference in a new issue