Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
145255cb51 |
@@ -30,15 +30,20 @@ P2: security: referer blacklist
|
|||||||
# Completed Steps
|
# Completed Steps
|
||||||
|
|
||||||
- 2026-10-04 the metrics basic auth, CORS preflight, request logging and
|
- 2026-10-04 the metrics basic auth, CORS preflight, request logging and
|
||||||
metrics recording have tests (closes #79): the basic auth in front of
|
metrics recording have tests (closes #79): `MetricsAuth` on its own answers
|
||||||
`/metrics` answers 401 with a challenge without credentials or with a wrong
|
401 with a challenge without credentials or with a wrong username or password
|
||||||
username or password and lets the configured ones through; a preflight
|
and lets the configured ones through; a preflight request gets `*` for any
|
||||||
request gets `*` for any origin when `access_control_allow_origin` is `*` and
|
origin when `access_control_allow_origin` is `*` and no
|
||||||
no `Access-Control-Allow-Origin` from another origin than the configured
|
`Access-Control-Allow-Origin` from another origin than the configured one; a
|
||||||
one; a `POST /` carrying the signing key leaves no trace of it in the log
|
`POST /` carrying the signing key leaves no trace of it in the request log
|
||||||
line; the metrics middleware records a request it served, and the router
|
line, and the login handler's own log lines leave out the submitted key; the
|
||||||
records nothing while no metrics username is set. Tests only; the basic auth
|
metrics middleware on its own records a request it served, and the router
|
||||||
library already compares the password in constant time.
|
records nothing while no metrics username is set. Not tested: that the router
|
||||||
|
puts the basic auth in front of `/metrics` and records requests when a
|
||||||
|
metrics username is set. Only one test per package can set up `/metrics`, and
|
||||||
|
in `internal/server` that is `TestMaintenanceModeKeepsOtherRoutes`, which
|
||||||
|
needs the owner's approval to change; #180 holds it. Tests only; the basic
|
||||||
|
auth library already compares the password in constant time.
|
||||||
- 2026-10-04 routes, encrypted URLs and config file documented (closes #75):
|
- 2026-10-04 routes, encrypted URLs and config file documented (closes #75):
|
||||||
"Routes" in `README.md` lists every route with its method, purpose, what it
|
"Routes" in `README.md` lists every route with its method, purpose, what it
|
||||||
needs and the status codes it answers with, and says `q` and `fit` are part
|
needs and the status codes it answers with, and says `q` and `fit` are part
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"log/slog"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"sneak.berlin/go/pixa/internal/config"
|
||||||
|
"sneak.berlin/go/pixa/internal/session"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TestLoginLogLeavesOutSubmittedKey verifies that the log lines for a
|
||||||
|
// failed and for a successful login do not contain the submitted key.
|
||||||
|
func TestLoginLogLeavesOutSubmittedKey(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
const wrongKey = "wrong-signing-key-fedcba9876543210"
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
|
||||||
|
sessMgr, err := session.NewManager(testSigningKey)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("session.NewManager() error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
h := &Handlers{
|
||||||
|
log: slog.New(slog.NewJSONHandler(&buf, nil)),
|
||||||
|
config: &config.Config{SigningKey: testSigningKey},
|
||||||
|
sessMgr: sessMgr,
|
||||||
|
}
|
||||||
|
|
||||||
|
submittedKeys := []string{wrongKey, testSigningKey}
|
||||||
|
|
||||||
|
for _, key := range submittedKeys {
|
||||||
|
form := url.Values{loginKeyField: {key}}
|
||||||
|
req := httptest.NewRequestWithContext(
|
||||||
|
t.Context(), http.MethodPost, "/",
|
||||||
|
strings.NewReader(form.Encode()))
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
|
||||||
|
h.handleLoginPost(httptest.NewRecorder(), req)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, msg := range []string{"failed login attempt", "successful login"} {
|
||||||
|
if !strings.Contains(buf.String(), msg) {
|
||||||
|
t.Fatalf("log missing %q; got %q", msg, buf.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, key := range submittedKeys {
|
||||||
|
if strings.Contains(buf.String(), key) {
|
||||||
|
t.Errorf("log contains submitted key %q; got %q", key, buf.String())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -112,10 +112,11 @@ func TestCORSAnswersPreflightWithConfiguredOrigin(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestMetricsAuthRequiresConfiguredCredentials checks that the basic auth
|
// TestMetricsAuthRequiresConfiguredCredentials checks that MetricsAuth on
|
||||||
// in front of /metrics answers 401 with a challenge to a request without
|
// its own answers 401 with a challenge to a request without credentials or
|
||||||
// credentials or with a wrong username or password, and lets a request with
|
// with a wrong username or password, and lets a request with the configured
|
||||||
// the configured username and password through.
|
// username and password through. That the router puts it in front of
|
||||||
|
// /metrics is not tested.
|
||||||
func TestMetricsAuthRequiresConfiguredCredentials(t *testing.T) {
|
func TestMetricsAuthRequiresConfiguredCredentials(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user