package proxy import ( "crypto/subtle" "net/http" "strings" "sneak.berlin/go/smallwebwaf/internal/requestlog" ) // answerAdmin answers a request for smallwebwaf itself, under // /_smallwebwaf/, once it has passed the checks: GET MetricsPath with // SWWAF_METRICS_TOKEN gets the metrics, and without it is refused with // 401. Any other request gets 404, as the metrics do while // SWWAF_METRICS_TOKEN is unset. func (rq *request) answerAdmin() { rq.line.Action = requestlog.ActionAdmin rq.startClientResponseTimeout() token := rq.h.config.MetricsToken switch { case token == "" || rq.in.Method != http.MethodGet || rq.in.URL.Path != MetricsPath: http.Error(rq.out, http.StatusText(http.StatusNotFound), http.StatusNotFound) case !hasToken(rq.in, token): rq.out.Header().Set("WWW-Authenticate", "Bearer") rq.answer(refusal{ status: http.StatusUnauthorized, action: requestlog.ActionAdmin, }) default: rq.h.metrics.ServeHTTP(rq.out, rq.in) } } // hasToken reports whether r carries token, as Authorization: Bearer // . func hasToken(r *http.Request, token string) bool { scheme, sent, _ := strings.Cut(r.Header.Get("Authorization"), " ") return strings.EqualFold(scheme, "Bearer") && subtle.ConstantTimeCompare([]byte(sent), []byte(token)) == 1 }