85 lines
2.7 KiB
Go
85 lines
2.7 KiB
Go
package server
|
|
|
|
import (
|
|
"io"
|
|
"log/slog"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/danyel/go-loose/internal/config"
|
|
"github.com/danyel/go-loose/internal/session"
|
|
)
|
|
|
|
func newInstallerTestServer() *Server {
|
|
secret := strings.Repeat("s", 32)
|
|
return &Server{
|
|
cfg: config.Config{BaseURL: "http://localhost:8080", SessionSecret: secret},
|
|
sessions: session.New(secret, false),
|
|
logger: slog.New(slog.NewTextHandler(io.Discard, nil)),
|
|
}
|
|
}
|
|
|
|
func TestFaviconDoesNotRedirectToInstaller(t *testing.T) {
|
|
server := newInstallerTestServer()
|
|
request := httptest.NewRequest(http.MethodGet, "/favicon.ico", nil)
|
|
recorder := httptest.NewRecorder()
|
|
server.Handler().ServeHTTP(recorder, request)
|
|
if recorder.Code != http.StatusNotFound {
|
|
t.Fatalf("favicon status = %d, want 404; location %q", recorder.Code, recorder.Header().Get("Location"))
|
|
}
|
|
if recorder.Header().Get("Set-Cookie") != "" {
|
|
t.Fatal("favicon response set a cookie")
|
|
}
|
|
}
|
|
|
|
func TestUninstalledRootRedirectsToInstaller(t *testing.T) {
|
|
server := newInstallerTestServer()
|
|
request := httptest.NewRequest(http.MethodGet, "/", nil)
|
|
recorder := httptest.NewRecorder()
|
|
server.Handler().ServeHTTP(recorder, request)
|
|
if recorder.Code != http.StatusSeeOther || recorder.Header().Get("Location") != "/install" {
|
|
t.Fatalf("status %d location %q", recorder.Code, recorder.Header().Get("Location"))
|
|
}
|
|
}
|
|
|
|
func TestInstallerCSRFTokenSurvivesRepeatedPageLoad(t *testing.T) {
|
|
server := newInstallerTestServer()
|
|
first := httptest.NewRecorder()
|
|
server.Handler().ServeHTTP(first, httptest.NewRequest(http.MethodGet, "/install", nil))
|
|
if first.Code != http.StatusOK {
|
|
t.Fatalf("first install page status = %d", first.Code)
|
|
}
|
|
cookie := first.Result().Cookies()[0]
|
|
token := csrfTokenFromInstaller(t, first.Body.String())
|
|
if cookie.Value != token {
|
|
t.Fatalf("cookie %q does not match form token %q", cookie.Value, token)
|
|
}
|
|
|
|
secondRequest := httptest.NewRequest(http.MethodGet, "/install", nil)
|
|
secondRequest.AddCookie(cookie)
|
|
second := httptest.NewRecorder()
|
|
server.Handler().ServeHTTP(second, secondRequest)
|
|
if got := csrfTokenFromInstaller(t, second.Body.String()); got != token {
|
|
t.Fatalf("second page rotated CSRF token to %q", got)
|
|
}
|
|
if second.Result().Cookies()[0].Value != token {
|
|
t.Fatal("second response rotated CSRF cookie")
|
|
}
|
|
}
|
|
|
|
func csrfTokenFromInstaller(t *testing.T, page string) string {
|
|
t.Helper()
|
|
const marker = `name="csrf_token" value="`
|
|
start := strings.Index(page, marker)
|
|
if start < 0 {
|
|
t.Fatal("installer page has no csrf token")
|
|
}
|
|
start += len(marker)
|
|
end := strings.Index(page[start:], `"`)
|
|
if end < 0 {
|
|
t.Fatal("installer csrf token is unterminated")
|
|
}
|
|
return page[start : start+end]
|
|
}
|