feat(app): CORS for appen, en billet til live-synk, og /ping siger hvad den er
Andet trin mod iOS-appen. Appen henter sin flade fra capacitor://localhost og taler med den server, ejeren har skrevet ind, så hver anmodning er cross-origin. - CORS på /api/v1 for appens origin og ingen andres. Ingen Allow-Credentials: appen bærer sin session som bearer, aldrig som cookie. Alle andre origins får ingen headere, præcis som før. - POST /ws-ticket giver en engangsbillet, der lever 30 sekunder, og /ws?ticket=… åbner socket'en med den. En browser kan ikke sætte en header på et WebSocket-håndtryk, og tokenet selv i URL'en ville ligge i hver proxy-log i månedsvis. En socket med billet springer origin-tjekket over, fordi den ikke bærer nogen cookie, som en fremmed side kunne låne. - Et håndtryk fra appens origin uden billet afvises. Prøven fandt hvorfor: biblioteket sammenligner kun værtsnavne, og capacitor://localhost har samme værtsnavn som en instans på http://localhost. - /ping svarer med product, edition og api, så appen kan kende en Verdande fra en routers login-side, før nogen er logget ind. Ingen version: /version er bag et login med vilje. Fem plantede fejl, hver fanget af sin egen prøve: CORS til enhver origin, genbrugelig billet, billet uden udløb, app-origin på en cookie, og Allow-Credentials. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
a8db761a4b
commit
a71af41d9e
@@ -45,11 +45,15 @@ func (s *Server) publishToOwner(r *http.Request, event string, payload any) {
|
||||
func (s *Server) handleWebSocket(w http.ResponseWriter, r *http.Request) {
|
||||
user := userFrom(r.Context())
|
||||
|
||||
ticketed, _ := r.Context().Value(ctxTicket).(bool)
|
||||
conn, err := websocket.Accept(w, r, &websocket.AcceptOptions{
|
||||
// The socket is same-origin only. Without this, any page on the internet
|
||||
// could open a socket carrying the user's cookie and watch their tasks —
|
||||
// the same-origin policy does not apply to WebSocket handshakes.
|
||||
OriginPatterns: s.allowedOrigins(),
|
||||
// Except one opened with a ticket, which carries no cookie for a foreign
|
||||
// page to borrow: see handleWebSocketEntry.
|
||||
InsecureSkipVerify: ticketed,
|
||||
})
|
||||
if err != nil {
|
||||
s.log.Debug("websocket handshake", "err", err)
|
||||
|
||||
Reference in New Issue
Block a user