Add Web Push, mobile login and manual escalate for the mobile companion

Sandbar sends Web Push (VAPID + aes128gcm, standard library only) to devices
registered for a topic, serves the companion PWA at /app/, allows one CORS
origin, and exposes a read-only Hammerhead edge view and POST .../escalate.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
VeillaxandClaude Sonnet 5.5 committed 2026-10-27 16:57:07 -06:00
1 parent b4fd31a182
commit 042a60152c
12 files changed
+1056 -18

No files matched your search

+13 -1
View File
@@ -37,6 +37,15 @@ func (s *Server) Handler() http.Handler {
mux.HandleFunc("POST /api/v1/login", s.apiLogin)
mux.HandleFunc("POST /api/v1/logout", func(w http.ResponseWriter, r *http.Request) { s.logout(w, r); writeJSON(w, 200, ok) })
// mobile companion
mux.HandleFunc("POST /api/v1/mobile/login", s.mobileLogin)
mux.HandleFunc("GET /api/v1/push/key", s.auth(false, s.pushKeyHTTP))
mux.HandleFunc("GET /api/v1/push/subscriptions", s.auth(false, s.listPushSubs))
mux.HandleFunc("POST /api/v1/push/subscriptions", s.auth(false, s.savePushSub))
mux.HandleFunc("DELETE /api/v1/push/subscriptions/{id}", s.auth(false, s.deletePushSub))
mux.HandleFunc("POST /api/v1/push/test", s.auth(false, s.testPush))
mux.HandleFunc("GET /api/v1/hammerhead/edges", s.auth(false, s.hammerheadEdges))
// topics, ntfy-style
mux.HandleFunc("POST /{topic}", s.auth(false, s.publishHTTP))
mux.HandleFunc("PUT /{topic}", s.auth(false, s.publishHTTP))
@@ -151,6 +160,9 @@ func (s *Server) Handler() http.Handler {
mux.HandleFunc("POST /api/v1/alerts/{id}/ack", s.auth(false, func(w http.ResponseWriter, r *http.Request) {
fail2(w, s.AckAlert(r.PathValue("id"), userFrom(r.Context()).Name))
}))
mux.HandleFunc("POST /api/v1/alerts/{id}/escalate", s.auth(false, func(w http.ResponseWriter, r *http.Request) {
fail2(w, s.EscalateAlert(r.PathValue("id"), userFrom(r.Context()).Name))
}))
mux.HandleFunc("POST /api/v1/alerts/{id}/resolve", s.auth(false, func(w http.ResponseWriter, r *http.Request) {
fail2(w, s.ResolveAlert(r.PathValue("id"), userFrom(r.Context()).Name))
}))
@@ -217,7 +229,7 @@ func (s *Server) Handler() http.Handler {
fail2(w, s.st.del("incident", r.PathValue("id")))
}))
return secureHeaders(mux)
return s.appRoutes(secureHeaders(mux))
}
var ok = map[string]bool{"ok": true}