Files
lrc-local/public_server_test.go
T

109 lines
3.6 KiB
Go

package main
import (
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strings"
"testing"
"testing/fstest"
)
func newTestPublicApp(t *testing.T, downloads string) (*publicApp, http.Handler) {
t.Helper()
web := fstest.MapFS{
"app.html": &fstest.MapFile{Data: []byte("public app")},
"app.js": &fstest.MapFile{Data: []byte("js")},
"styles.css": &fstest.MapFile{Data: []byte("css")},
}
app, err := newPublicApp("https://lrc.flechazo.xin", downloads, web, fakeQQ{})
if err != nil {
t.Fatal(err)
}
return app, app.routes()
}
func publicRequest(method, path, body string) *http.Request {
request := httptest.NewRequest(method, "https://lrc.flechazo.xin"+path, strings.NewReader(body))
request.Header.Set("Origin", "https://lrc.flechazo.xin")
request.Header.Set("Content-Type", "application/json")
request.Header.Set("X-Real-IP", "203.0.113.7")
return request
}
func TestPublicPageNeedsNoSession(t *testing.T) {
_, handler := newTestPublicApp(t, "")
w := httptest.NewRecorder()
handler.ServeHTTP(w, publicRequest(http.MethodGet, "/", ""))
if w.Code != http.StatusOK || w.Body.String() != "public app" {
t.Fatalf("status=%d body=%q", w.Code, w.Body.String())
}
}
func TestPublicAPIRejectsWrongOrigin(t *testing.T) {
_, handler := newTestPublicApp(t, "")
request := publicRequest(http.MethodPost, "/api/search", `{"keyword":"test","limit":2}`)
request.Header.Set("Origin", "https://attacker.example")
w := httptest.NewRecorder()
handler.ServeHTTP(w, request)
if w.Code != http.StatusForbidden {
t.Fatalf("expected 403, got %d", w.Code)
}
}
func TestPublicSearchWorksWithoutCookie(t *testing.T) {
_, handler := newTestPublicApp(t, "")
w := httptest.NewRecorder()
handler.ServeHTTP(w, publicRequest(http.MethodPost, "/api/search", `{"keyword":"测试","limit":2}`))
if w.Code != http.StatusOK || !strings.Contains(w.Body.String(), "测试") {
t.Fatalf("status=%d body=%s", w.Code, w.Body.String())
}
}
func TestPublicPerClientRateLimit(t *testing.T) {
_, handler := newTestPublicApp(t, "")
for attempt := 1; attempt <= publicClientLimit+1; attempt++ {
w := httptest.NewRecorder()
handler.ServeHTTP(w, publicRequest(http.MethodPost, "/api/search", `{"keyword":"test","limit":1}`))
if attempt <= publicClientLimit && w.Code != http.StatusOK {
t.Fatalf("attempt %d unexpectedly returned %d", attempt, w.Code)
}
if attempt == publicClientLimit+1 && w.Code != http.StatusTooManyRequests {
t.Fatalf("expected final attempt to return 429, got %d", w.Code)
}
}
}
func TestPublicDownloadWhitelistAndRange(t *testing.T) {
directory := t.TempDir()
name := "lrc-local-windows-amd64.exe"
if err := os.WriteFile(filepath.Join(directory, name), []byte("0123456789"), 0o600); err != nil {
t.Fatal(err)
}
_, handler := newTestPublicApp(t, directory)
request := publicRequest(http.MethodGet, "/download/"+name, "")
request.Header.Set("Range", "bytes=2-5")
w := httptest.NewRecorder()
handler.ServeHTTP(w, request)
if w.Code != http.StatusPartialContent || w.Body.String() != "2345" {
t.Fatalf("status=%d body=%q", w.Code, w.Body.String())
}
if !strings.Contains(w.Header().Get("Content-Disposition"), name) {
t.Fatal("download disposition is missing")
}
w = httptest.NewRecorder()
handler.ServeHTTP(w, publicRequest(http.MethodGet, "/download/not-allowed", ""))
if w.Code != http.StatusNotFound {
t.Fatalf("unexpected non-whitelist status %d", w.Code)
}
}
func TestPublicOriginConfigurationMustUseHTTPS(t *testing.T) {
_, err := newPublicApp("http://lrc.flechazo.xin", "", fstest.MapFS{}, fakeQQ{})
if err == nil {
t.Fatal("expected insecure public origin to be rejected")
}
}