mirror of
https://github.com/MeshTender/MeshTender.git
synced 2026-09-01 17:38:15 +00:00
Clean up old confirm page copy
This commit is contained in:
@@ -202,7 +202,7 @@ func run(logger *slog.Logger) error {
|
||||
}
|
||||
|
||||
// Shutdown doesn't close hijacked/WebSocket connections, so close the active
|
||||
// console/confirm sockets and give their handlers time to unwind and stamp
|
||||
// console sockets and give their handlers time to unwind and stamp
|
||||
// their session's ended_at (see core.WSDrainTimeout) before we stop the flusher
|
||||
// and close the pool. Too short and drained sessions stay "in progress" forever.
|
||||
wsCtx, wsCancel := context.WithTimeout(context.Background(), core.WSDrainTimeout)
|
||||
|
||||
@@ -268,8 +268,7 @@ func (s *Handlers) wsConsole(w http.ResponseWriter, r *http.Request) {
|
||||
debug := r.URL.Query().Get("debug") == "1"
|
||||
if debug {
|
||||
// Dump every inbound KISS frame as hex so we can see exactly what the modem
|
||||
// reports back (e.g. whether the repeater replies at all). Same aid the
|
||||
// dedicated confirm page used to offer.
|
||||
// reports back (e.g. whether the repeater replies at all).
|
||||
bridge.SetObserver(func(f *hardware.KissFrame) {
|
||||
_ = bridge.Status("debug", fmt.Sprintf("rx frame cmd=0x%02x len=%d data=%x", f.Command, len(f.Data), f.Data))
|
||||
})
|
||||
@@ -378,9 +377,9 @@ func (s *Handlers) wsConsole(w http.ResponseWriter, r *http.Request) {
|
||||
if userPathSet {
|
||||
reportPathOutcome(bridge, lr)
|
||||
}
|
||||
// A successful login proves we reached the repeater, so treat connecting from
|
||||
// the console as a confirmation (the same as the dedicated confirm flow) — for
|
||||
// guest access too, which records the access level. This is cheap (no extra
|
||||
// A successful login proves we reached the repeater, so connecting the console
|
||||
// IS how a repeater becomes confirmed — for guest access too, which records the
|
||||
// access level. This is cheap (no extra
|
||||
// packets). Fetching the location is deferred to an explicit "getloc" request
|
||||
// so a plain console session doesn't pay for a location round-trip it doesn't
|
||||
// need; the page offers a "Fetch location" button that sends it.
|
||||
@@ -389,7 +388,8 @@ func (s *Handlers) wsConsole(w http.ResponseWriter, r *http.Request) {
|
||||
} else if lr.IsAdmin {
|
||||
_ = bridge.Status("confirmed", "Repeater confirmed with admin access. ✓")
|
||||
} else {
|
||||
// Guests can't run CLI commands, so warn as the confirm flow did.
|
||||
// Guests can't run CLI commands, so say so rather than leaving the user to
|
||||
// discover it one refused command at a time.
|
||||
_ = bridge.Status("warning", fmt.Sprintf("Repeater reached, but MeshTender only has GUEST access (permissions=%d). Guest is open to anyone with a blank password, so MeshTender can't administer this repeater — re-run `%s` to grant admin.", lr.Permissions, s.Identity.SetPermCommand()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +180,7 @@ func TestConsoleRoundTrip(t *testing.T) {
|
||||
}
|
||||
|
||||
// Connecting from the console with a successful admin login confirms the
|
||||
// repeater — the same as running the dedicated confirm flow.
|
||||
// repeater: connecting the console is what confirms it.
|
||||
confirmed, err := st.GetRepeaterForUser(ctx, user.ID, rep.ID)
|
||||
must(err, "reload repeater")
|
||||
if !confirmed.Confirmed {
|
||||
@@ -343,7 +343,7 @@ func TestConsoleGetLatUpdatesLocation(t *testing.T) {
|
||||
|
||||
// TestConsoleGuestLoginConfirms: connecting the console to a repeater that only
|
||||
// grants GUEST access still records the confirmation (with is_admin=false) and
|
||||
// warns the user — the same as the dedicated confirm flow did. It must NOT emit a
|
||||
// warns the user. It must NOT emit a
|
||||
// "confirmed" (admin) status.
|
||||
func TestConsoleGuestLoginConfirms(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -91,8 +91,8 @@ func TestConsoleFetchesLocation(t *testing.T) {
|
||||
shared, _ := repeater.SharedSecret(serverID)
|
||||
|
||||
_ = ws.Write(rw, websocket.MessageText, []byte(`{"type":"ready"}`))
|
||||
// The console fetches location only on request (unlike the old confirm flow's
|
||||
// eager fetch). Queue the getloc; the console processes it after login.
|
||||
// The console fetches location only on request. Queue the getloc; the console
|
||||
// processes it after login.
|
||||
_ = ws.Write(rw, websocket.MessageText, []byte(`{"type":"getloc"}`))
|
||||
|
||||
// Reply to login (PATH) then to get lat / get lon (TXT_MSG).
|
||||
@@ -166,9 +166,9 @@ func TestConsoleFetchesLocation(t *testing.T) {
|
||||
break // socket closed; check the DB below
|
||||
}
|
||||
if typ == websocket.MessageText {
|
||||
// Unlike the old confirm flow, the console stays open after fetching
|
||||
// location (it's an interactive session), so it never closes the socket
|
||||
// on its own. It signals success with a "location" status — stop then.
|
||||
// The console is an interactive session: it stays open after fetching the
|
||||
// location and never closes the socket on its own. It signals success with
|
||||
// a "location" status — stop then.
|
||||
var m struct{ State, Message string }
|
||||
if json.Unmarshal(data, &m) == nil && m.State == "location" {
|
||||
break
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
</script>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="card-body"><p class="text-secondary mb-0">No repeater locations yet. Enable “store location” when editing a repeater and confirm it with a modem to place it on the map.</p></div>
|
||||
<div class="card-body"><p class="text-secondary mb-0">No repeater locations yet. Open a repeater's console, connect your modem, and use “Fetch location” to read its coordinates onto the map — or set them when you add it.</p></div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -32,7 +32,7 @@ type Handlers struct {
|
||||
Auth *auth.Service
|
||||
|
||||
// wsCtx is the base context for WebSocket handlers; cancelling it (on shutdown)
|
||||
// signals active console/confirm sockets to close. wsWG tracks those handlers so
|
||||
// signals active console sockets to close. wsWG tracks those handlers so
|
||||
// shutdown can wait for them — http.Server.Shutdown does not close hijacked
|
||||
// (WebSocket) connections.
|
||||
wsCtx context.Context
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
"github.com/chromedp/chromedp"
|
||||
)
|
||||
|
||||
// TestE2EConsoleConfirmBanner is the browser regression for folding the old
|
||||
// confirm page into the console: an unconfirmed repeater shows the "not
|
||||
// TestE2EConsoleConfirmBanner covers the console's two state banners, which are
|
||||
// the only place confirmation surfaces: an unconfirmed repeater shows the "not
|
||||
// confirmed yet" banner, and a confirmed repeater with no known location shows
|
||||
// the location prompt with a "Fetch location" button. Both must render under the
|
||||
// strict CSP with no violations (the console's inline nonce'd bootstrap plus
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
aria-label="setperm command with MeshTender's public key" readonly>
|
||||
<button type="button" class="btn" data-copy-target="#setperm-cmd">Copy</button>
|
||||
</div>
|
||||
<p class="text-secondary small mb-0">The long value is <strong>MeshTender's</strong> public key — not your repeater's. If you see a guest-access warning after confirming a repeater, this is the fix: run the command above, then confirm again.</p>
|
||||
<p class="text-secondary small mb-0">The long value is <strong>MeshTender's</strong> public key — not your repeater's. If you see a guest-access warning when the console connects, this is the fix: run the command above, then connect again.</p>
|
||||
{{else}}
|
||||
<p class="text-secondary mb-0">Run <code>setperm <MeshTender's public key> 3</code> on your repeater. Sign in and start adding a repeater to see the exact command with the key filled in.</p>
|
||||
{{end}}
|
||||
@@ -42,9 +42,9 @@
|
||||
<p>There are two ways in, matching how you reach the repeater:</p>
|
||||
<ul class="mb-2">
|
||||
<li><strong>Set up a brand-new repeater (USB)</strong> — connect a freshly-flashed repeater over USB serial and MeshTender runs the whole setup for you: identity, radio, region, name, and the admin grant. Best for a repeater that isn't on the mesh yet.</li>
|
||||
<li><strong>Add one that's already on the network (over the air)</strong> — for a repeater you've already configured, MeshTender reaches it over the air through a <a href="#kiss">KISS modem</a> attached to your browser. You grant MeshTender admin with the <a href="#setperm"><code>setperm</code></a> command yourself first, then <em>confirm</em> it here.</li>
|
||||
<li><strong>Add one that's already on the network (over the air)</strong> — for a repeater you've already configured, MeshTender reaches it over the air through a <a href="#kiss">KISS modem</a> attached to your browser. You grant MeshTender admin with the <a href="#setperm"><code>setperm</code></a> command yourself first, then register it here.</li>
|
||||
</ul>
|
||||
<p>Confirming does a live login round-trip to prove MeshTender can reach and administer the repeater. If it reports guest access, the <code>setperm</code> grant hasn't been applied yet.</p>
|
||||
<p>A registered repeater shows as <strong>confirmed</strong> once MeshTender has actually reached it. There's nothing to click for that: open the repeater's <strong>console</strong> and connect your modem, and the signed login that opens every session doubles as the proof — it confirms the repeater the first time it replies. If the reply reports guest access, the <code>setperm</code> grant hasn't been applied yet; run it, then connect again.</p>
|
||||
<p class="mb-0">Either way, the device must already be running MeshCore's <strong>Repeater</strong> firmware — MeshTender configures repeaters, it doesn't flash them. A MeshCore device runs one firmware at a time (Repeater, a Companion variant, or KISS modem), so switching roles means re-flashing.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -251,7 +251,7 @@ func seedRepeaters(ctx context.Context, st *store.Store, f *gofakeit.Faker, user
|
||||
_ = st.UpdateRepeater(ctx, u.ID, rep.ID, rep.Name, preset.freq, preset.bw, preset.sf, preset.cr, showOnOrg, true)
|
||||
}
|
||||
_ = st.UpdateRepeaterDocs(ctx, u.ID, rep.ID, f.Paragraph(1, 3, 14, " "), f.Paragraph(1, 2, 10, " "))
|
||||
// ~70% confirmed with admin access (perms 3 = admin, per the confirm flow).
|
||||
// ~70% confirmed with admin access (perms 3 = admin).
|
||||
if chance(f, 70) {
|
||||
_ = st.SetRepeaterConfirmed(ctx, rep.ID, u.ID, true, 3)
|
||||
}
|
||||
|
||||
+1
-1
@@ -435,7 +435,7 @@ var compressHTML = middleware.Compress(5, compressibleTypes...)
|
||||
// command lists, markdown docs) — so 1 MiB is generous while stopping a client
|
||||
// from streaming an arbitrarily large body into memory before per-field limits
|
||||
// can apply. WebSocket upgrades carry no request body, so this doesn't affect
|
||||
// the console/confirm sockets.
|
||||
// the console socket.
|
||||
const maxRequestBody = 1 << 20 // 1 MiB
|
||||
|
||||
// limitBody caps r.Body so an oversized request fails fast — a read past the
|
||||
|
||||
Reference in New Issue
Block a user