Skip to content

fix: splash stub clientmac passthrough + NDS session timeout config - #363

Merged
c03rad0r merged 1 commit into
OpenTollGate:mainfrom
felixfelix-bot:fix/splash-clientmac-nds-sessiontimeout
Aug 30, 2026
Merged

c03rad0r merged 1 commit into
OpenTollGate:mainfrom
felixfelix-bot:fix/splash-clientmac-nds-sessiontimeout

Conversation

@felixfelix-bot

Copy link
Copy Markdown
Contributor

Summary

Two fixes for captive-portal session handling:

1. Splash stub drops ?clientmac= query param

File: packaging/files/etc/uci-defaults/90-tollgate-captive-portal-symlink

The JavaScript redirect stub did:

location.replace('http://' + location.hostname + ':2051/splash.html');

NDS appends ?clientmac=XX:XX:… to the splash URL, but the stub dropped it. The SPA on port 2051 then had no MAC to work with, breaking the backend's MAC-based session logic.

Fix: Append location.search:

location.replace('http://' + location.hostname + ':2051/splash.html' + location.search);

2. NDS sessiontimeout defaults to 1200s (20 min)

File: packaging/files/etc/uci-defaults/99-tollgate-setup

setup_nodogsplash() did not set sessiontimeout or authidletimeout. NDS defaults to 1200 seconds (20 min), which deauths users mid-session regardless of the Go backend's purchased duration.

Fix: Set large ceilings so the Go backend is the sole authority on session lifetime:

uci set nodogsplash.@nodogsplash[0].sessiontimeout='86400'   # 24h
uci set nodogsplash.@nodogsplash[0].authidletimeout='3600'     # 1h

Testing

  • gofmt -l . — clean (no output)
  • go vet ./... — clean
  • go build ./... — clean
  • go test -race -count=1 -tags testenv ./... — all pass

Notes

  • These are router-packaging scripts (uci-defaults), not Go code — unit tests cover existing Go logic; the script changes need on-hardware validation.
  • Not deployed to router yet.
  • CHANGELOG entries added under [Unreleased] → Fixed.

@felixfelix-bot

Copy link
Copy Markdown
Contributor Author

E2E Test Evidence (physical router, OpenWrt 24.10.4 GL-MT3000)

Deployed both fixes from this PR to a physical test router and verified live.

1. Splash stub clientmac passthrough ✅

Router file /etc/nodogsplash/htdocs/splash.html after deploy:

location.replace("http://" + location.hostname + ":2051/splash.html" + location.search);

location.search preserves the ?clientmac=XX:XX:... param that NDS appends — SPA now receives the real client MAC.

2. NDS session timeout ✅

uci get nodogsplash.@nodogsplash[0].sessiontimeout  → 86400  (was 1200)
uci get nodogsplash.@nodogsplash[0].authidletimeout → 3600   (was 120)

Go backend now controls session lifetime — users who buy 1h no longer get kicked at 20min by NDS defaults.

Playwright E2E (video)

End-to-end flow through the redirect chain recorded:
test1-session-expiry-redirect.mp4

Portal + balance page screenshots:
portal

Unit tests

gofmt -l . clean, go vet ./... clean, go build ./... clean, go test -race -count=1 -tags testenv ./... all pass (12.6s).

Test files: evidence/2026-08-27-portal-fixes/

@felixfelix-bot

Copy link
Copy Markdown
Contributor Author

Correction: earlier evidence was captured in degraded mode — replaced with full-mode proof (upstream online, mints reachable).

The previous evidence run (comment) was taken while the test router had no upstream internet, so the deployed backend returned kind:21023 ("No reachable mints detected") and portal-level verification was limited to DOM structure. That proof was insufficient. The router's upstream WiFi STA has now been attached to a live internet uplink (LAN untouched, still 192.168.1.x), and everything was rerun in FULL mode.

Backend mint probe recovery (from the router):

wget -qO- http://localhost:2121/ now returns kind:10021 (not 21023) with price_per_step tags for 7/7 configured mints — all reachable:

  • https://mint.coinos.io
  • https://mint.minibits.cash/Bitcoin
  • https://mint.lnserver.com
  • https://mint.macadamia.cash
  • https://mint.westernbtc.com
  • https://kashu.me
  • https://mint.cubabitcoin.org

Router online proof (ping -c 3 8.8.8.8): 3 packets transmitted, 3 packets received, 0% packet loss, round-trip avg 27.9 ms.

E2E rerun in full mode — 2/2 PASS (backend gate baked into the test: kind:10021 + price_per_step required, 21023 hard-fails):

  • Test 1 — session-expiry redirect: balance page "Get Access" links to http://192.168.1.1:2050/ (NDS gateway), not a relative splash.html. ✅
  • Test 2 — Cashu tab UX with live pricing: Lightning tab shows 4 size-selection buttons (100 MB / 1 GB / 10 GB / More); Cashu tab has .size-choices removed from the DOM, zero .size-btn elements, no selectedSats/"X sats" text, and the token input (placeholder="cashuxyz…") present; switching back to Lightning restores the buttons. ✅

New evidence (full mode):

Video — Test 2, Cashu tab UX: https://raw.githubusercontent.com/felixfelix-bot/physical-router-test-automation/evidence/portal-fixes-20260827/evidence/2026-08-27-portal-fixes/test2-cashu-tab-ux.mp4

Video — Test 1, Get Access → :2050: https://raw.githubusercontent.com/felixfelix-bot/physical-router-test-automation/evidence/portal-fixes-20260827/evidence/2026-08-27-portal-fixes/test1-session-expiry-redirect.mp4

Cashu tab with live mint list served by the backend:

Cashu tab — accepted mints

Lightning tab with live pricing:

Lightning tab — size buttons

The old evidence files at the same URLs have been overwritten with these full-mode captures; full set + test source: evidence/2026-08-27-portal-fixes (branch evidence/portal-fixes-20260827).

c03rad0r pushed a commit to OpenTollGate/physical-router-test-automation that referenced this pull request Aug 27, 2026
Amperstrand added a commit to felixfelix-bot/tollgate-module-basic-go that referenced this pull request Aug 27, 2026
Rebase of OpenTollGate#363 onto rewritten main — carries only the two captive-portal
session fixes:

1. Splash stub redirect appends location.search so the NDS-provided
   ?clientmac= survives the redirect to the SPA on :2051.
2. setup_nodogsplash() sets sessiontimeout=86400 / authidletimeout=3600
   so NDS defaults (1200 s) no longer deauth users mid-session; the Go
   backend becomes the sole authority on session lifetime.

Dropped: deploy-backup-20260730/ (leaked secrets, incident #364),
DEPENDS packaging change, pre-commit config, local-build script,
token-recovery binary, unrelated go.mod churn.

Original-PR: OpenTollGate#363
@Amperstrand
Amperstrand force-pushed the fix/splash-clientmac-nds-sessiontimeout branch from 28163ee to 1ba1646 Compare August 27, 2026 12:09
@Amperstrand

Copy link
Copy Markdown
Collaborator

⚠️ Branch cleaned up (force-push by maintainer side) — Felix, please sanity-check the new head.

Thanks for these two fixes — both are real problems we've hit in the lab (our own router backups show NDS sessiontimeout='1200' cutting paid sessions short at 20 min).

Your branch was based on pre-incident history and carried deploy-backup-20260730/ (the router backup with the merchant private key that was purged from main via history rewrite — incident #364), plus a few unrelated changes (DEPENDS packaging change, pre-commit config, local-build script, token-recovery binary, go.mod churn). With your standing OK for maintainer-side rebases, the branch was rebased onto rewritten main.

New head 1f03a67 carries exactly your two fixes + CHANGELOG entries:

  1. 90-tollgate-captive-portal-symlink — stub redirect now appends location.search (clientmac passthrough)
  2. 99-tollgate-setup — sessiontimeout='86400', authidletimeout='3600'

Shell syntax verified; go build clean. Since you flagged that these are uci-defaults changes needing on-hardware validation — an e2e cloud-lab run (OpenWrt VM, full payment suite + post-install NDS config verification) is in flight on this head; results will be posted here. If you'd rather rebase yourself or drop anything else, feel free to force-push over it.

@c03rad0r
c03rad0r self-requested a review August 27, 2026 14:46
@Amperstrand

Copy link
Copy Markdown
Collaborator

E2E results (follow-up to review): deployed head 6c96425 as ci-pr-363.197.6c96425 (ipk built by CI from this branch + a ci-only workflow patch) on an OpenWrt x86_64 QEMU lab:

Suite Result
api/test_quote_persistence 4/4 passed
api/test_lightning_backoff 3/3 passed
api/test_payment_regression (e2e Cashu payment, local FakeWallet mint) 3/3 passed

Both fixes validated on-router:

  • uci get nodogsplash...sessiontimeout → 86400, authidletimeout → 3600 after a full setup run (values confirmed absent on the pre-fix image — NDS defaults apply, exactly the bug described).
  • The stub redirect now carries + location.search (verified present in the shipped 90-tollgate-captive-portal-symlink).

⚠️ One finding for your consideration (non-blocking): the new uci values only apply on the full setup path. 99-tollgate-setup early-exits to "verify wireless APs only" when /etc/tollgate-setup-done matches SETUP_VERSION — which is still v0.6.2 in this PR. Existing routers that reinstall/upgrade will not receive the sessiontimeout ceilings until SETUP_VERSION is bumped (the repo has done exactly this for prior fixes, e.g. the v0.6.2 bump). Recommend bumping it in this PR or a follow-up before release.

Approving — thanks for the fix. (Lab note: SHC cloud was unavailable for nested-virt reasons, so this ran on the local QEMU virtual lab; the deployed ipk is the CI-built artifact.)

@Amperstrand Amperstrand left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both fixes verified end-to-end on a deployed OpenWrt VM (details in the E2E comment). The SETUP_VERSION-bump note is the only suggestion — merge at your discretion.

Rebase of OpenTollGate#363 onto rewritten main — carries only the two captive-portal
session fixes:

1. Splash stub redirect appends location.search so the NDS-provided
   ?clientmac= survives the redirect to the SPA on :2051.
2. setup_nodogsplash() sets sessiontimeout=86400 / authidletimeout=3600
   so NDS defaults (1200 s) no longer deauth users mid-session; the Go
   backend becomes the sole authority on session lifetime.

Dropped: deploy-backup-20260730/ (leaked secrets, incident #364),
DEPENDS packaging change, pre-commit config, local-build script,
token-recovery binary, unrelated go.mod churn.

Original-PR: OpenTollGate#363
@felixfelix-bot
felixfelix-bot force-pushed the fix/splash-clientmac-nds-sessiontimeout branch from aaf7382 to 781ea1d Compare August 30, 2026 13:37
@c03rad0r
c03rad0r merged commit ce46fa1 into OpenTollGate:main Aug 30, 2026
felixfelix-bot added a commit to felixfelix-bot/tollgate-module-basic-go that referenced this pull request Sep 20, 2026
…penTollGate#363)

Rebase of OpenTollGate#363 onto rewritten main — carries only the two captive-portal
session fixes:

1. Splash stub redirect appends location.search so the NDS-provided
   ?clientmac= survives the redirect to the SPA on :2051.
2. setup_nodogsplash() sets sessiontimeout=86400 / authidletimeout=3600
   so NDS defaults (1200 s) no longer deauth users mid-session; the Go
   backend becomes the sole authority on session lifetime.

Dropped: deploy-backup-20260730/ (leaked secrets, incident #364),
DEPENDS packaging change, pre-commit config, local-build script,
token-recovery binary, unrelated go.mod churn.

Original-PR: OpenTollGate#363

Co-authored-by: Amperstrand <amperstrand@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants