Replace username-based admin bootstrap with a one-time setup secret, rate-limit login/register, equalize login bcrypt timing, cap passwords at 72 bytes, destroy sessions on logout, and require Secure cookies when PORT is set.
58 lines
1.5 KiB
Go
58 lines
1.5 KiB
Go
package web
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestPasswordMaxBytes(t *testing.T) {
|
|
if ok, _ := passwordValid(strings.Repeat("a", 8)); !ok {
|
|
t.Fatal("8 ascii runes should pass")
|
|
}
|
|
if ok, msg := passwordValid(strings.Repeat("a", 73)); ok || !strings.Contains(msg, "72") {
|
|
t.Fatalf("73 bytes should fail: ok=%v msg=%q", ok, msg)
|
|
}
|
|
}
|
|
|
|
func TestLogoutDestroysSession(t *testing.T) {
|
|
srv, _ := newTestServer(t, Config{})
|
|
h := srv.Handler()
|
|
name := uniq("out")
|
|
cookies := registerUser(t, h, name, "hunter22")
|
|
|
|
rec := httptest.NewRecorder()
|
|
req := httptest.NewRequest(http.MethodGet, "/profile", nil)
|
|
for _, c := range cookies {
|
|
req.AddCookie(c)
|
|
}
|
|
h.ServeHTTP(rec, req)
|
|
if rec.Code != 200 {
|
|
t.Fatalf("profile before logout %d", rec.Code)
|
|
}
|
|
csrf := csrfFrom(rec.Body.String())
|
|
form := strings.NewReader("_csrf=" + csrf)
|
|
req = httptest.NewRequest(http.MethodPost, "/logout", form)
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
for _, c := range cookies {
|
|
req.AddCookie(c)
|
|
}
|
|
rec = httptest.NewRecorder()
|
|
h.ServeHTTP(rec, req)
|
|
if rec.Code != http.StatusSeeOther {
|
|
t.Fatalf("logout %d", rec.Code)
|
|
}
|
|
postLogout := mergeCookies(cookies, rec.Result().Cookies())
|
|
|
|
req = httptest.NewRequest(http.MethodGet, "/profile", nil)
|
|
for _, c := range postLogout {
|
|
req.AddCookie(c)
|
|
}
|
|
rec = httptest.NewRecorder()
|
|
h.ServeHTTP(rec, req)
|
|
if rec.Code != http.StatusSeeOther {
|
|
t.Fatalf("profile after logout should redirect, got %d", rec.Code)
|
|
}
|
|
}
|