feat: support a public browser demo of the kiosk #88
4 changed files with 51 additions and 4 deletions
feat(machine): VITE_DEMO_TAG for the public web demo
The browser path (no electronAPI) is already a first-class code path: initializeWithLightning() resolves an EPHEMERAL LocalSigner, allows mock fallback and leaves debugMode on, so the bill simulator stands in for the validator. That is what makes a hosted kiosk demo possible at all. Two things still needed fixing for it. 1. Cursor. `cursor: none` was applied globally for the touchscreen, which in an ordinary browser reads as a broken page. Scope it to `.kiosk`, set on <html> by main.ts unless VITE_DEMO_TAG is present — so every real machine keeps today's behavior and only the demo build shows a pointer. 2. Cleanup. An ephemeral identity per page load is the right call (it isolates concurrent visitors, and each fresh account gets its own auto-credit under LNBITS_DEMO_MODE, whereas a single baked-in key would be credited once and then drain). The cost is a throwaway LNbits account per visit, and nothing in an auto-created row distinguishes one: pubkey-set/prvkey-NULL equally describes a real ATM. A nostr pubkey can't carry a marker — grinding a vanity prefix is far too slow to do on page load — and the account/wallet the server auto-creates isn't nameable by the client. So when VITE_DEMO_TAG is set the ATM mints one extra, never-used wallet whose NAME is the tag, turning the sweep into an exact string match instead of a heuristic about what looks disposable. Both are inert on a real machine: the var is unset outside the demo build. The marker call is fire-and-forget — losing it degrades cleanup, not the demo. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013A6683cCHnQxFUosx1krY4
commit
8264dd7472
|
|
@ -73,6 +73,18 @@ VITE_SPIRE_SEED=
|
|||
# Show "Under Service" screen and block all transactions
|
||||
# VITE_MAINTENANCE_MODE=true
|
||||
|
||||
# =============================================================================
|
||||
# Public Web Demo
|
||||
# =============================================================================
|
||||
|
||||
# Set ONLY for the browser demo build (atm.demo.aiolabs.dev). Leave blank on
|
||||
# every real machine. When set it:
|
||||
# - keeps the mouse cursor visible (kiosk builds hide it)
|
||||
# - mints one extra, never-used LNbits wallet named with this exact string,
|
||||
# so the throwaway accounts the demo creates (one per page load, each with
|
||||
# its own ephemeral identity) can be swept by name instead of guessed at.
|
||||
# VITE_DEMO_TAG=bitspire-web-demo
|
||||
|
||||
# =============================================================================
|
||||
# Mock Fallback (Production Safety)
|
||||
# =============================================================================
|
||||
|
|
|
|||
|
|
@ -24,6 +24,13 @@ const router = createRouter({
|
|||
],
|
||||
})
|
||||
|
||||
// Kiosk chrome (hidden cursor) is the default — every real machine is a
|
||||
// touchscreen. The public web demo (VITE_DEMO_TAG) runs in a normal browser,
|
||||
// where an invisible pointer just reads as broken.
|
||||
if (!import.meta.env.VITE_DEMO_TAG) {
|
||||
document.documentElement.classList.add('kiosk')
|
||||
}
|
||||
|
||||
// Create Pinia store
|
||||
const pinia = createPinia()
|
||||
|
||||
|
|
|
|||
|
|
@ -505,6 +505,31 @@ export async function initializeLightningServices(options?: {
|
|||
}
|
||||
console.log('[Lightning] LNbits wallet:', lnbitsWalletId)
|
||||
|
||||
// ── Public web demo: stamp the throwaway account so it can be swept ──────
|
||||
// The browser demo (atm.demo.aiolabs.dev) runs with an EPHEMERAL identity —
|
||||
// a fresh keypair per page load — so LNbits mints a new account + a fresh
|
||||
// auto-credited wallet for every visitor. That isolation is the point (a
|
||||
// single baked-in key would be credited exactly once and then drain), but it
|
||||
// leaves throwaway accounts behind, and nothing in an auto-created row says
|
||||
// "demo": pubkey-set/prvkey-NULL also describes a real ATM.
|
||||
//
|
||||
// A nostr pubkey can't carry a marker (you'd have to grind a vanity prefix,
|
||||
// far too slow to do on page load), and the account/wallet the server
|
||||
// auto-creates isn't nameable by the client. So we mint one extra,
|
||||
// never-used wallet whose NAME is the tag: sweeping is then an exact string
|
||||
// match on wallet name rather than a heuristic about what looks disposable.
|
||||
//
|
||||
// Unset on every real machine, so this is inert outside the demo build. The
|
||||
// call is fire-and-forget: losing the marker degrades cleanup, not the demo.
|
||||
const demoTag = (import.meta.env.VITE_DEMO_TAG as string | undefined)?.trim()
|
||||
if (demoTag) {
|
||||
void lnbits
|
||||
.createWallet(demoTag)
|
||||
// Never log the reply — create_wallet returns adminkey/inkey.
|
||||
.then(() => console.log('[Lightning] Demo marker wallet created:', demoTag))
|
||||
.catch((e) => console.warn('[Lightning] Demo marker wallet failed:', e))
|
||||
}
|
||||
|
||||
// #70 P1: pull operator pubkey + fee config from LNbits over the authenticated
|
||||
// transport (spirekeeper#41 `get_machine_config`). A seed-only machine has no
|
||||
// VITE_OPERATOR_PUBKEYS, so without this it can't trust its fee config and sits
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
@import 'tailwindcss';
|
||||
@import 'tw-animate-css';
|
||||
|
||||
/* Hide cursor completely on touchscreen kiosk */
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
/* Hide cursor completely on touchscreen kiosk.
|
||||
Scoped to .kiosk (set on <html> by main.ts) so the public web demo, which
|
||||
runs in an ordinary browser with a mouse, keeps a visible pointer. */
|
||||
.kiosk,
|
||||
.kiosk *,
|
||||
.kiosk *::before,
|
||||
.kiosk *::after {
|
||||
cursor: none !important;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue