No description
  • Python 62.7%
  • HTML 22.5%
  • JavaScript 14.8%
Find a file
Patrick Mulligan 2bc4a01edc feat(ui): edit doors from the admin page (add Edit action)
The PUT /api/v1/doors/{id} endpoint already existed and preserves the
controller token when it isn't resent, but the admin UI only exposed
create / reveal-token / delete. Add a per-row Edit (pencil) button that
reuses the door dialog as create-or-update (saveDoor: POST when new, PUT
when editing), so a door's Home Assistant webhook URL / boltcards base /
timeout can be changed without deleting + recreating (which would churn
the controller token the reader uses). Bump to 0.0.3.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-08 23:56:52 +02:00
__pycache__ feat: access extension — NFC door access via boltcards SUN + Home Assistant 2026-08-07 22:47:41 +02:00
static feat(ui): edit doors from the admin page (add Edit action) 2026-09-08 23:56:52 +02:00
templates/access feat(ui): edit doors from the admin page (add Edit action) 2026-09-08 23:56:52 +02:00
__init__.py feat: access extension — NFC door access via boltcards SUN + Home Assistant 2026-08-07 22:47:41 +02:00
config.json feat(ui): edit doors from the admin page (add Edit action) 2026-09-08 23:56:52 +02:00
crud.py feat: access extension — NFC door access via boltcards SUN + Home Assistant 2026-08-07 22:47:41 +02:00
manifest.json feat: access extension — NFC door access via boltcards SUN + Home Assistant 2026-08-07 22:47:41 +02:00
migrations.py feat: access extension — NFC door access via boltcards SUN + Home Assistant 2026-08-07 22:47:41 +02:00
models.py feat: access extension — NFC door access via boltcards SUN + Home Assistant 2026-08-07 22:47:41 +02:00
README.md feat: access extension — NFC door access via boltcards SUN + Home Assistant 2026-08-07 22:47:41 +02:00
services.py feat: access extension — NFC door access via boltcards SUN + Home Assistant 2026-08-07 22:47:41 +02:00
views.py feat: access extension — NFC door access via boltcards SUN + Home Assistant 2026-08-07 22:47:41 +02:00
views_api.py feat: access extension — NFC door access via boltcards SUN + Home Assistant 2026-08-07 22:47:41 +02:00
views_reader.py feat: access extension — NFC door access via boltcards SUN + Home Assistant 2026-08-07 22:47:41 +02:00

Access — LNbits extension

NFC door access for LNbits. A tapped Bolt Card (NTAG424) is authenticated via the boltcards SUN check, authorized against per-door grants, and — if allowed — the door's local Home Assistant webhook is fired to unlock a Z-Wave lock. Every tap is logged.

Runs on the on-prem LNbits on the door's LAN, so the unlock path stays local and the door does not depend on the internet.

Flow

Pi + PN532 reader
  → POST /access/api/v1/check   (X-Controller-Token: <door token>)
        { "doorId": "...", "external_id": "...", "p": "...", "c": "..." }
        1. authenticate  → boltcards /verify  (valid, non-replayed SUN?)
        2. authorize     → active grant for this external_id on this door?
        3. actuate       → POST door.ha_webhook_url  (→ lock.unlock → Z-Wave)
        4. log           → access.logs (allow/deny + reason)
  → { "allow": true|false, "reason": "..." }

The reader never unlocks directly; this extension owns the allow/deny decision and the Home Assistant call. Fails closed at every step.

Data model

  • doors — a resource: name, controller_token (reader secret), ha_webhook_url (local HA webhook), boltcards_base_url (blank = this instance), unlock_timeout_ms, enabled.
  • grants — external_id → door permission, enabled/expires_at.
  • logs — every allow/deny with a reason.

Admin API (wallet admin key)

  • GET/POST /access/api/v1/doors, PUT/DELETE /access/api/v1/doors/{id}
  • GET/POST /access/api/v1/grants, DELETE /access/api/v1/grants/{id}
  • GET /access/api/v1/logs

Reader API (controller token)

POST /access/api/v1/check
X-Controller-Token: <door.controller_token>
Content-Type: application/json

{ "doorId": "front-door", "external_id": "abc123", "p": "<32-hex>", "c": "<16-hex>" }

Setup

  1. Install on the on-prem LNbits (same instance as boltcards).
  2. Create a door, set its Home Assistant webhook URL, copy its controller token to the reader config.
  3. Issue Bolt Cards in boltcards as usual; add a grant (the card's external_id → the door).
  4. Point the door reader (Pi) at /access/api/v1/check with the token.

Notes

  • Card authentication delegates to boltcards over loopback HTTP via its /api/v1/verify/{external_id} endpoint (aiolabs fork ≥ 1.1.1-aio.2) — a side-effect-light SUN check that returns {"authenticated": true, …} without /scan's spend semantics (no withdrawRequest, no daily-limit, no "hit"), while still advancing the SUN counter for replay protection.
  • Requires boltcards 1.1.1-aio.2+ installed on the same LNbits.
  • Empty ha_webhook_url = authorize + log only (bring-up mode; no unlock).
  • Keep this on the LAN; use a strong per-door controller token; never expose Home Assistant publicly.