upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
AgeCommit message (Collapse)Author
2026-05-19fix: use default httpd socket settings to prevent socket exhaustionfeature/tollgate-core-componentYour Name
- Remove max_open_sockets=2 override from both httpd servers (use ESP-IDF default of 4) - Increase LWIP_MAX_SOCKETS from 16 to 20 (matching standalone tollgate) - The previous custom tuning (max_open_sockets=2, keep_alive_enable=false, linger_timeout=0) caused socket leaks by interfering with ESP-IDF's internal session management - Verified: 50/50 sequential requests pass, full payment flow works
2026-05-19docs: update E2E fix plan with hardware blocker and validation statusYour Name
2026-05-19fix: E2E test stability — socket exhaustion, auto-grant, HTTP robustnessYour Name
Root causes discovered: - RC-0: LWIP socket exhaustion (CONFIG_LWIP_MAX_SOCKETS=10, need 14) - Two HTTP servers (5 sockets each) + DNS + DoT + wifistr WS = 14 > 10 - Fix: increase to 16, reduce max_open_sockets to 2 on both servers - RC-1: Port 80 captive portal crashes under load - Fix: Connection: close on all handlers, stack 16384 - RC-2: Owner auto-grant makes tests non-deterministic - Fix: remove tollgate_core_fw_grant() from client_connected() Also adds: - /grant_access and /reset_authentication on API server (port 2121) - /portal-config endpoint for future JS-based portal config - Error-checked URI handler registration - Connection: close on captive portal handlers E2E test fixes: - dig +short instead of nslookup for DNS checks - port 2121 for grant/reset/usage/whoami in all tests - pre-mint tokens before blocking internet - increased timeouts and sleeps for reliability
2026-05-19feat: WPA auto-detect from SPIFFS config.jsonYour Name
Parse wifi_auth_mode from config.json to set STA auth threshold. Defaults to WPA2-PSK (fixes reason=211 with WPA2-only routers). SPIFFS generated by Makefile auto-detects WPA2/WPA3 from host scan. Root cause: config.c hardcoded WIFI_AUTH_WPA3_PSK threshold, making WPA2-only APs invisible during ESP32 scan (reason=211 NO_AP_FOUND). With this fix, STA connects to WPA2 upstream and Cashu payment verification works end-to-end.
2026-05-19fix: add per-board mutex locks to flash targetsYour Name
flash-a and flash-b now require lock-a/lock-b to be held before flashing. Prevents cross-session hardware conflicts when multiple LLM agents share the same ESP32 boards. Lock infrastructure matches main repo and price-discovery worktrees: - HARDWARE_LOCK_DIR = physical-router-test-automation/locks - require_lock_a/require_lock_b macros - lock-a/lock-b/unlock-a/unlock-b/force-unlock-a/force-unlock-b/lock-status targets
2026-05-19fix: start services without upstream WiFi + channel 10 + disconnect reasonYour Name
- Start services after 30s timeout if STA never connects (reason=211) - Set AP channel to 10 for APSTA overlap with upstream router - Add upstream WiFi credentials in default config - Log WiFi disconnect reason code for debugging - Previously: remove stop_services() on STA disconnect
2026-05-18fix: don't stop services on STA disconnectYour Name
Services (API server on 2121, captive portal on 80, DNS hijack, firewall) should stay running even when STA WiFi disconnects. Previously, every STA disconnect would tear down all services, making the board unreachable on its own AP. Also set default wifi_networks to empty since upstream WiFi config should be provisioned, not hardcoded.
2026-05-18feat: add E2E test helpers and update checklist for physical board testingYour Name
2026-05-18fix: build-verify tollgate_core component extractionYour Name
- Remove display/cvm/font deps from CMakeLists (not yet merged branches) - Add tollgate_platform.h include to session header - Add tollgate_core_session_set_platform declaration - Remove duplicate tollgate_core_dns_stop wrapper (dns module has own impl) - Update captive_portal.c to use tollgate_core_* API - Remove display/cvm calls from tollgate_main.c - Add tollgate_get_platform declaration to config.h - Fix nucula wallet.hpp submodule (save_proofs visibility) - Add tollgate_core include paths to test Makefile - Build passes, all unit tests pass (61/61)
2026-05-18feat: extract tollgate_core ESP-IDF componentYour Name
Extract shared TollGate business logic into a reusable ESP-IDF component that can be consumed by esp-miner via the IDF Component Manager. Component structure: components/tollgate_core/ include/tollgate_core.h — public API include/tollgate_platform.h — platform interface (config callbacks) src/tollgate_core.c — orchestrator (init, payment, tick, owner) src/tollgate_core_cashu.c/h — Cashu V3 token decode/verify src/tollgate_core_dns.c/h — per-client DNS hijack/forward src/tollgate_core_firewall.c/h — per-client NAT filter src/tollgate_core_session.c/h — session lifecycle Key design decisions: - Platform interface pattern: consumers implement tollgate_platform_t (config getters + optional spend_proofs wallet hook) - Cross-module wiring (session→firewall→dns) stays internal - No direct config.h dependency — all config via platform callbacks - spend_proofs can be NULL (accepts payment without local wallet) Standalone app updated: - main/tollgate_platform.c implements platform via config singleton - main/tollgate_main.c calls tollgate_core_init/tick/dns_start - main/tollgate_api.c routes payment through tollgate_core_process_payment - Removed cashu.c, dns_server.c, firewall.c, session.c from CMakeLists Not yet build-verified — blocked on multi-mint, price-discovery, cvm-integration, and display-fix branches merging to master.
2026-05-18docs: add tollgate_core component architecture design planYour Name
Design document for extracting core TollGate modules (cashu, dns, firewall, session) into a reusable ESP-IDF component consumed by esp-miner via the IDF Component Manager. Includes platform interface specification, wallet integration design, dependency analysis, and phased implementation checklist. Refs: feature/tollgate-core-component
2026-05-18fix: EVENT msg buffer underflow + WS write loop + WPA3 authYour Name
- Fix buffer size for ["EVENT",...] wrapper: was 8+event_len+1, needed 10+event_len+2 (9 char prefix + ] + null). snprintf was truncating the closing bracket, causing relay JSON parse errors. - Add write loop in ws_send_text for large payloads that don't fit in a single esp_tls_conn_write call. - Change STA auth threshold from WPA2_PSK to WPA3_PSK for compatibility with WPA3 access points. - Announcements now successfully stored on relay.primal.net!
2026-05-18feat: ContextVM (MCP over Nostr) server with WS masking fixYour Name
- Full CVM server: persistent WS relay listener, kind 25910 subscription - MCP protocol handlers: initialize, tools/list, tools/call, ping - 10 MCP tools: get_config, set_config, get_balance, wallet_send, get_sessions, get_usage, set_payout, set_metric, set_price, wallet_melt - CEP-6 announcements via WS (kinds 11316, 11317, 10002) - Auth check: owner npub only - Fix: WebSocket client-to-server frame masking (RFC 6455 requirement) - Fix: Raw event JSON in EVENT wrapper (no re-parsing that breaks sig) - SNTP init after STA gets IP - 282 unit tests passing (61 CVM + 60 MCP handler + 161 existing) - Integration test scaffold: tests/integration/test-cvm.mjs
2026-05-18fix: move MAC set after wifi_set_mode, start services without STAYour Name
- esp_wifi_set_mac requires WIFI_MODE_APSTA set first (fixes Board B crash) - Start services immediately when no STA network is configured (standalone TollGate without upstream WiFi)
2026-05-17refactor: reorganize test suite, add integration tests for NAT filterYour Name
- Move integration tests (api, network, phase2, smoke) to tests/integration/ - Move Playwright specs (captive-portal, interop-happy-path) to tests/e2e/ - Move playwright.config.mjs to tests/e2e/ - Fix hardcoded IP fallbacks: 192.168.4.1 → 10.192.45.1 - Add test-reset-auth.mjs: reset→pay→allow→revoke→block cycle - Add test-session-expiry.mjs: pay→wait 65s→verify blocked (slow test) - Add test-dns-firewall.mjs: DNS hijack/forward + per-client NAT filter - Update Makefile with test-unit, test-integration, test-e2e, test-all targets - Update package.json scripts for new paths - Fix Playwright video: retain-on-failure instead of always-on - Update AGENTS.md: per-client NAT filter description - Update CHECKLIST.md: mark completed items, add Board B identity - Board B nsec: 9af47906... → SSID TollGate-b96d80, AP IP 10.185.47.1 - 186 unit tests passing
2026-05-17feat: per-client NAT filtering via LWIP_HOOK_IP4_CANFORWARDYour Name
- Add lwip_tollgate_hooks.h defining LWIP_HOOK_IP4_CANFORWARD macro - Inject hook into lwIP build via CMakeLists.txt ESP_IDF_LWIP_HOOK_FILENAME - Filter forwarded packets by source IP against firewall allowed list - Only filter packets from AP subnet (10.192.45.0/24), allow all others - Fix byte order bug: use network byte order for firewall_is_client_allowed - NAT always enabled, removed global NAT toggle functions - Remove spent-secret tracking from session.c (mint is authority) - Remove unused get_ap_netif() function - Reduce API server stack from 32KB to 16KB (fixes ESP_ERR_HTTPD_TASK) - Add esp_random.h stub for unit tests - All 186 unit tests passing - Verified on hardware: block->pay->allow->revoke->block E2E works
2026-05-17Bug fixes: reset_auth clears sessions, port 80 /usage shows real data, ↵Your Name
metric defaults to milliseconds, fix sys_evt stack overflow
2026-05-17Playwright interop tests: 18 tests (ESP32 happy path + OpenWRT comparison)Your Name
- interop-happy-path.spec.mjs: 11 ESP32 TollGate tests + 7 ESP32↔OpenWRT interop tests - API discovery, whoami, usage, invalid/spent token rejection - Browser portal UI: branding, form elements, captcha detection URIs - Full payment flow screenshots (portal → token → connected → browsing) - Side-by-side ESP32 vs OpenWRT comparison screenshot - playwright.config.mjs: video on, screenshot on, 120s timeout - package.json: test:happy-path, test:interop, test:playwright scripts
2026-05-17Phase 7: MCP handler (25 tests), NIP-04 encrypt/decrypt (15 tests), CVM ↵Your Name
server skeleton - mcp_handler.c/h: 4 tools (get_config, set_config, get_balance, wallet_send) - nip04.c/h: AES-256-CBC + ECDH with 0x02 compressed pubkey prefix - Fixed IV copy bug: mbedTLS AES-CBC modifies IV in-place - Base64 encode/decode for ciphertext transport - PKCS7 padding - cvm_server.c/h: Nostr DM listener with FreeRTOS task - config: cvm_enabled, cvm_relays fields - 156 total tests passing across 10 test binaries
2026-05-17feat(phase6): bytes-based billing - dual metric supportYour Name
- session_create_bytes() + session_add_bytes() for bytes-metric sessions - session_is_expired() dispatches on config metric (bytes vs milliseconds) - cashu_calculate_allotment() unified dispatcher for both metrics - tollgate_api discovery/usage/session_event use configured metric - config: metric field defaults to 'bytes', step_size_bytes=22020096 (21MB) - 14 new unit tests (148 total passing) - ASSERT_EQ_UINT64 macro added to test framework
2026-05-17Phase 5: Lightning auto-payout with LNURL-pay and NUT-05 meltYour Name
- New lnurl_pay.c/h: LNURL-pay protocol (GET .well-known/lnurlp + callback) - New lightning_payout.c/h: threshold-based auto-payout with multi-recipient split - Extended nucula_wallet bridge with nucula_wallet_melt() (NUT-05) - Config: payout section with multi-mint, multi-recipient, fee_tolerance - Default: enabled, TollGate@coinos.io, min_payout=128, min_balance=64 - 18 new unit tests (all passing), 134 total
2026-05-17Phase 4: TollGate client detection + auto-paymentYour Name
- New tollgate_client.c/h: detect upstream TollGate (kind=10021), auto-pay via nucula wallet, session monitoring with 20% renewal - State machine: IDLE→DETECTING→NEEDS_PAY→PAYING→PAID→RENEWING - Blocking: upstream payment before local services start - Synchronous wallet init (was async task) - Client config: enabled, steps_to_buy, renewal_threshold_pct - Updated PLAN.md with Phases 4-7 (client, payout, bytes, CVM) - Updated CHECKLIST.md with all new phase items - 30 new unit tests (all passing), 116 total
2026-05-17interop: ESP32 ↔ OpenWRT TollGate cross-platform test suiteYour Name
- interop/Makefile: 10 targets for 4 test scenarios - interop-status: show device status for all devices - interop-laptop-esp32: laptop pays ESP32 with V3 token - interop-laptop-openwrt: laptop pays OpenWRT with V4 token - interop-openwrt-esp32: OpenWRT daemon auto-pays ESP32 upstream - interop-esp32-esp32: cross-board payment (needs Board B) - interop-setup/cleanup: mint alignment + wallet funding - INTEROP_PLAN.md: full test plan with scenarios and token format details - PROGRESS.md: checklist of setup/interop tasks - AGENTS.md: standing instructions for interop testing - routers.env.example: device config template - Verified interop-status against real hardware (OpenWRT + ESP32 Board A)
2026-05-17test_cashu (10/10) + test_session (18/18): all 86 unit tests passingYour Name
- Expand esp_http_client.h stub: full config struct + method enum + init/perform/cleanup - Add portTICK_PERIOD_MS + esp_err_to_name to stubs - session.c: reject duplicate spent secrets in session_create (double-spend protection) - .gitignore: add test binaries
2026-05-17test_nostr_event: 23/23 passing — NIP-01 event ID, Schnorr signing, JSON ↵Your Name
serialization
2026-05-17test_identity: 24/24 passing — HMAC-SHA512 derivation, MAC bits, SSID/IP ↵Your Name
determinism
2026-05-17Testing infrastructure: AGENTS.md rules + unit test framework + geohash ↵Your Name
tests (11/11 pass) - Add AGENTS.md: full project context + mandatory testing rules for AI sessions - Add tests/unit/ with host-compiled C unit test infrastructure - Clean stubs approach: ESP-IDF type stubs in tests/unit/stubs/, no source modifications - Fix geohash.c bit extraction bug (3-byte span) found by unit tests - test_geohash: 11/11 passing with reference vectors (Munich, NYC, origin, boundaries)
2026-05-16Phase 3: Nostr identity derivation + wifistr service discoveryYour Name
- Add identity.c/h: HMAC-SHA512 derivation from nsec → npub, STA/AP MAC, SSID, AP IP - Add nostr_event.c/h: NIP-01 event serialization + Schnorr signing (BIP-340) - Add geohash.c/h: lat/lon to geohash encoding - Add wifistr.c/h: kind 38787 event builder + WebSocket publish to Nostr relays - Update config.c/h: nsec-based identity, Nostr relay/geo config, remove static SSID/IP - Replace custom mbedTLS wallet with nucula library (libsecp256k1) - Remove wallet.c/h, wallet_persist.c/h (replaced by nucula_lib component) - Verified on Board A: derived SSID, captive portal, payment, wallet, wifistr publish
2026-05-16Phase 3: on-device Cashu wallet with mbedTLS secp256k1 + SPIFFS persistence ↵Your Name
+ PSRAM - wallet.c/h: secp256k1 ECP primitives (hash_to_curve, scalar_mul, point_add) - wallet_persist.c/h: SPIFFS persistence with threshold-based write protection - Fee accounting for swap (input_fee_ppk from /v1/keysets) - Keyset fetch via /v1/keysets (586 bytes vs 21KB for /v1/keys) - Wallet API: GET /wallet, POST /wallet/swap, POST /wallet/send - Payment proofs auto-stored to wallet + persisted on SPIFFS - PSRAM enabled for large allocations (ESP32-S3 has 8MB) - Wallet init deferred to dedicated task (avoids sys_evt stack overflow) - Cashu proof ID buffer size fixed (66 hex chars, not 16) - HTTP client: added fetch_headers() call for proper response handling - persist_threshold_sats config parameter (default: 1 sat)
2026-05-16Fix test 22: use dynamic TOLLGATE_IP instead of hardcoded 192.168.4.1 for ↵Your Name
route management
2026-05-16Fix captive portal detection on GrapheneOS + embed mint URL in portal HTMLYour Name
- Add esp_netif_set_dns_info() on AP interface so DHCP advertises AP as DNS server to clients (fixes captive portal on GrapheneOS) - Embed price and mint URL directly in portal HTML via server-side template substitution (no JavaScript fetch to :2121 needed) - Move supported mints section below the token input field - Add Playwright tests: no unresolved placeholders, embedded mint/price, DOM order verification (14/14 passing)
2026-05-16Unique SSID/IP per board + captive detection fix + mint list in portalYour Name
- Derive unique SSID (TollGate-{MAC4}{MAC5}) and AP IP (10.{b5}.{subnet}.1) from factory MAC — boards no longer conflict - Board A: TollGate-377C @ 10.55.85.1, Board B: TollGate-5050 @ 10.80.10.1 - Captive portal detection URIs return 200 with portal HTML (matching esp32-mesh working approach) instead of 302 redirect - Dynamic AP IP in portal HTML via __AP_IP__ template substitution - Supported mints section in portal page (shows mint URL, tap to copy) - Fixed mint URL to testnut.cashu.space (was stale in SPIFFS) - DoT reject server on port 853 for DNS-over-TLS fallback - DNS hijack: NXDOMAIN for all non-A queries, no forwarding for unauthed - Playwright tests updated for 200 response on detection URIs - Phase 2 test suite: 20/21 pass (test 22 expiry ping route issue) - Tests 25-27 deferred to Phase 3 (Board B as second client)
2026-05-16Phase 2 Playwright tests: 10/10 passing (portal, captive detection, API)Your Name
- Updated from Phase 1 tests to Phase 2 (302 redirects, Cashu token input) - Test captive detection URIs return 302 (using request API) - Test invalid token via request API (no CORS issues) - Tests: portal branding, price, token input, pay button, detection redirects - Tests: whoami, usage, API advertisement, invalid token
2026-05-16Phase 2 tests 22-23 passing: session expiry + renewal (21/21)Your Name
- Test 22: session expires after allotment, internet blocked, usage returns -1/-1 - Test 23: second token renews session, internet restored - Test 18 fix: add route through TollGate before ping, pipe sudo password - All 21 Phase 2 tests pass
2026-05-16Captive portal detection fix + Phase 2 tests 16-18,20 passing (17/17)Your Name
- Add DoT reject server on port 853 (TCP RST forces DNS-over-TLS fallback) - DNS hijack returns NXDOMAIN for all non-A query types (no forwarding for unauthed) - Shorter TTL on hijack responses (10s) for faster captive detection - Explicit 302 redirect handlers for /generate_204, /hotspot-detect.html, etc. - HTTP and DNS request logging for debugging captive detection - Per-MAC tracking in firewall (find_by_mac, get_mac_for_ip with ARP fallback) - Session MAC tracking (session_find_by_mac) - Phase 2 test 18: add route through TollGate before ping test - All 17 Phase 2 tests pass (15-21 + whoami + portal form)
2026-05-16gitignore: exclude generated config.json (contains WiFi credentials)Your Name
2026-05-16Phase 2 WIP: token decode works, TLS checkstate succeeds (crashes after ↵Your Name
response) - cashu.c: dynamic json_buf sizing (was 2048 stack, now heap based on token length) - cashu.c: strip trailing newline/CR from token input (cashu CLI appends 'Balance: 0 sat') - cashu.c: esp_crt_bundle_attach for HTTPS to mint API - cashu.c: esp_http_client_open/write/fetch_headers/read pattern for HTTPS POST - cashu.c: remove debug b64url_decode logging - tollgate_api.c: loop httpd_req_recv for full body (was single call, missed TCP segments) - tollgate_api.c: stack_size=32768 for TLS in httpd handler - config.c: fix default mint URL from nofee.testnut to testnut.cashu.space - CMakeLists.txt: add esp-tls dependency for cert bundle - CHECKLIST.md: updated with infrastructure status and TDD plan Known issue: device reboots after checkstate returns 966 bytes with status=200. Crash likely in post-response processing (JSON parse or session create).
2026-05-15Fix stack overflow and heap-allocate large buffers in Cashu/payment pathYour Name
- tollgate_api.c: increase httpd stack_size to 16384 (was default 4096) - cashu.c: heap-allocate b64, json_buf, post_body, resp_buf instead of stack - cashu.c: proper free() on all error paths - Makefile: replace Go-based tokens target with nutshell wallet targets - Makefile: add wallet-setup, wallet-info, wallet-balance, mint-token, send-token
2026-05-15Phase 2 WIP: Cashu payment endpoints, session tracking, updated checklistYour Name
- Add cashu.c/h: Cashu token decode (cashuA/base64url), proof state check via mint API, allotment calculator - Add session.c/h: time-based session management with allotment/expiry, spent secret tracking - Add tollgate_api.c/h: HTTP server on :2121 with GET / (kind=10021 discovery), POST / (payment processing), /usage, /whoami - Update captive portal HTML: replace Grant Free Access with Cashu token paste form + Pay & Connect button - Update tollgate_main.c: wire in session manager, TollGate API, 1s session tick loop - Add tests/phase2.mjs: Phase 2 test suite (discovery, invalid token, wrong mint, valid payment) - Update CHECKLIST.md: reflect Phase 1 complete, Phase 2 in progress with known bugs Known issues (not yet flashed): - Stack overflow crash in httpd POST handler (need stack_size=16384 + heap allocations) - cashu_decode_token uses 2KB stack buffer (needs heap alloc) - Mint URL should be testnut.cashu.space (nofee.testnut has API compat issues)
2026-05-15Phase 1 working: captive portal, DNS hijack, NAT-based access controlYour Name
- Fix WiFi init order: netif creation before esp_wifi_init, set mode before set_config - Replace broken netif input filter with NAPT on/off per authentication state - NAPT disabled by default, enabled when client granted, disabled on revoke - Fix test helpers: use -I wlp59s0 for ping, handle nslookup exit code 1 - All 20 API tests pass, all 6 smoke tests pass
2026-05-15initiall commitYour Name