server: relay a test device's adb endpoint, because mDNS does not cross subnets
The beacon this replaces was a separate service wildcard-bound to 0.0.0.0:443 - it silently occupied port 443 on the reserved measurement addresses, voiding the IPv4 interception proof for as long as it ran, and it accepted a port report from anyone who could reach it. So this lives where the repo's own post-mortem said it belongs: POST on the control plane authenticated by the device credential, GET on the admin UI behind the existing apiAdmin helper. No new listener, no new port, no wildcard. Entries expire after 24h (ECHOLOT_ADB_ENDPOINT_RETENTION_H) on both write and read - a LAN address is a breadcrumb for driving a test device, not measurement data worth keeping. Also records the BLE peer-comparison design: the case for it is that BLE is out-of-band, which is what makes client isolation measurable at all - silence over IP cannot distinguish an isolating AP from an absent peer, and a peer confirming out-of-band that it was listening turns that silence into proof. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
ab6e278272
commit
ae63bd7c7f
@@ -8,6 +8,7 @@ import (
|
||||
"html/template"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@@ -26,6 +27,20 @@ var tpl = template.Must(template.New("base").Funcs(template.FuncMap{
|
||||
return "v-unknown"
|
||||
}
|
||||
},
|
||||
// ago renders an age the way someone says it out loud. The dev relay reports a port that
|
||||
// rotates every few minutes, so "4 m ago" is the entire question a reader has about a row.
|
||||
"ago": func(seconds int) string {
|
||||
switch {
|
||||
case seconds < 45:
|
||||
return "just now"
|
||||
case seconds < 90*60:
|
||||
return strconv.Itoa((seconds+30)/60) + " min ago"
|
||||
case seconds < 48*3600:
|
||||
return strconv.Itoa((seconds+1800)/3600) + " h ago"
|
||||
default:
|
||||
return strconv.Itoa(seconds/86400) + " d ago"
|
||||
}
|
||||
},
|
||||
// verdictLabel says what the light means rather than what it is called. "yellow" is a colour;
|
||||
// "worth a look" is a finding, and the reader is here to act on it.
|
||||
"verdictLabel": func(v string) string {
|
||||
@@ -321,6 +336,31 @@ const baseHTML = `<!doctype html>
|
||||
</div>
|
||||
{{end}}
|
||||
{{end}}
|
||||
{{with .ADBEndpoints}}
|
||||
<h2>Dev relay</h2>
|
||||
<p class="lede">Wireless-debug endpoints reported by Echolot instances on a test network. mDNS
|
||||
does not cross subnets, so a device on that network relays adbd’s rotating port here for
|
||||
a developer sitting elsewhere. Nothing here is a measurement, and the entries expire —
|
||||
a port older than a few minutes has probably already rotated.</p>
|
||||
<div class="recs">
|
||||
{{range .}}
|
||||
<div class="rec">
|
||||
<div class="rec-head">
|
||||
<span class="id">{{if .DeviceName}}{{.DeviceName}}{{else}}{{.Device}}{{end}}</span>
|
||||
<span class="tag v-unknown">{{ago .AgeS}}</span>
|
||||
</div>
|
||||
<ul class="readout">
|
||||
<li><span class="k">adb connect</span><span class="lead"></span>
|
||||
<span class="v">{{.Host}}:{{.Port}}</span></li>
|
||||
<li><span class="k">device</span><span class="lead"></span><span class="v">{{.Device}}</span></li>
|
||||
<li><span class="k">reported from</span><span class="lead"></span>
|
||||
<span class="v">{{if .SourceIP}}{{.SourceIP}}{{else}}—{{end}}</span></li>
|
||||
</ul>
|
||||
{{with .Note}}<div class="why">{{.}}</div>{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
|
||||
{{else if eq .Page "devices"}}
|
||||
<h2>{{if .Admin}}Devices{{else}}Your devices{{end}}</h2>
|
||||
|
||||
Reference in New Issue
Block a user