Pairing: scan a QR off the terminal once; the cookie lasts a year
The key already persisted across restarts, but the cookie was a session cookie — Safari eventually drops those and the paste ritual returned. The pairing cookie now lasts a year, and startup prints a QR code of the pairing URL (qrcode dep, ASCII render) so a phone pairs by pointing its camera at the terminal. Revoke every paired device by deleting data/.lan_key. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016jXZFSTZQKzAC8fqpWSz9g
This commit is contained in:
co-authored by
Claude Fable 5
parent
78debdd62f
commit
44dd03d06a
@@ -61,7 +61,7 @@
|
||||
<h2 id="files">Your data, on disk</h2>
|
||||
<div class="card prose">
|
||||
<p>Everything lives in flat files under <code>data/</code> — inspectable, hand-editable, and git-friendly. The pipeline artifacts: <code>titles.json</code> (what was read), <code>matches.csv</code> (what it matched), <code>to_add.csv</code>/<code>to_update.csv</code> (what upload will do), <code>upload_log.csv</code> (what it did), <code>games.json</code> (the library). Your curation: <code>title_edits.json</code>, <code>title_splits.json</code>, <code>title_removals.json</code>, <code>unidentified_dismissed.json</code>.</p>
|
||||
<p>Credentials never live in files — only environment variables, set up by <code>bggpipe init</code>. The app serves localhost only, unless started with <code>--lan</code> — that opens it to your network behind a per-run access key printed at startup (no login beyond the key; trusted networks only).</p>
|
||||
<p>Credentials never live in files — only environment variables, set up by <code>bggpipe init</code>. The app serves localhost only, unless started with <code>--lan</code> — that opens it to your network behind an access key: scan the QR code the server prints (or open the printed link) once per device, and a year-long cookie keeps it paired. Delete <code>data/.lan_key</code> to revoke every device. No login beyond the key; trusted networks only.</p>
|
||||
<p>More depth: the README covers setup and photo technique; <code>docs/bgg-upload-flow.md</code> documents the upload automation.</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -380,8 +380,15 @@ def create_app(
|
||||
status_code=303,
|
||||
headers={"Location": request.url.path or "/"},
|
||||
)
|
||||
# a YEAR, not a session: pairing a device should be a
|
||||
# one-time act (the key file persists too; delete
|
||||
# data/.lan_key to revoke every paired device)
|
||||
response.set_cookie(
|
||||
LAN_COOKIE, lan_token, httponly=True, samesite="lax"
|
||||
LAN_COOKIE,
|
||||
lan_token,
|
||||
max_age=365 * 24 * 3600,
|
||||
httponly=True,
|
||||
samesite="lax",
|
||||
)
|
||||
return response
|
||||
if request.method not in ("GET", "HEAD", "OPTIONS") and (
|
||||
@@ -1105,6 +1112,21 @@ def _dev_app() -> FastAPI:
|
||||
return create_app(load_config(Path(path) if path else None), lan_token=token)
|
||||
|
||||
|
||||
def _print_qr(url: str) -> None:
|
||||
"""Pairing without typing: the phone's camera reads the URL straight
|
||||
off the terminal."""
|
||||
import io as _io
|
||||
|
||||
import qrcode
|
||||
|
||||
qr = qrcode.QRCode(border=1)
|
||||
qr.add_data(url)
|
||||
buffer = _io.StringIO()
|
||||
qr.print_ascii(out=buffer, invert=True)
|
||||
for line in buffer.getvalue().splitlines():
|
||||
typer.echo(f" {line}")
|
||||
|
||||
|
||||
def _lan_key(cfg: Config) -> str:
|
||||
"""The --lan access key: created once, reused across restarts so a
|
||||
phone's cookie keeps working. Delete the file to rotate the key."""
|
||||
@@ -1143,6 +1165,8 @@ def run_web_review(
|
||||
typer.echo(f"bggpipe web UI: {url} (this machine needs no key)")
|
||||
if primary:
|
||||
typer.echo(f" on your phone, open: http://{primary}:{port}/?k={token}")
|
||||
typer.echo(" or point its camera at this code:")
|
||||
_print_qr(f"http://{primary}:{port}/?k={token}")
|
||||
if spares:
|
||||
typer.echo(
|
||||
" (several network interfaces here — if that address "
|
||||
|
||||
Reference in New Issue
Block a user