package api import ( "encoding/json" "git.misaka.ren/m1saka/dsh-web/internal/store" "golang.org/x/crypto/bcrypt" "net/http" "net/http/httptest" "path/filepath" "strings" "testing" ) func TestAuthenticationAndAdmin(t *testing.T) { s, e := store.Open(filepath.Join(t.TempDir(), "test.sqlite")) if e != nil { t.Fatal(e) } defer s.Close() h, _ := bcrypt.GenerateFromPassword([]byte("test-password-123"), bcrypt.MinCost) if e = s.CreateUser(store.User{ID: "admin", Username: "admin", Admin: true, Quota: 1024}, string(h)); e != nil { t.Fatal(e) } a := New(s, t.TempDir()) a.origin = "http://panel.test" var access *http.Cookie request := func(method, path, body, csrf string, cookie *http.Cookie) *httptest.ResponseRecorder { r := httptest.NewRequest(method, path, strings.NewReader(body)) r.Header.Set("Origin", a.origin) r.Header.Set("X-CSRF-Token", csrf) if cookie != nil { r.AddCookie(cookie) if access != nil { r.AddCookie(access) } } w := httptest.NewRecorder() a.Handler().ServeHTTP(w, r) return w } if w := request("GET", "/api/me", "", "", nil); w.Code != 401 { t.Fatal(w.Code) } w := request("POST", "/api/login", `{"username":"admin","password":"test-password-123"}`, "", nil) if w.Code != 200 { t.Fatal(w.Code, w.Body.String()) } var login struct { CSRF string `json:"csrf_token"` } json.Unmarshal(w.Body.Bytes(), &login) var cookie *http.Cookie for _, c := range w.Result().Cookies() { if c.Name == "dsh_access" { access = c } if c.Name == "dsh_session" { cookie = c } } if cookie == nil || !cookie.HttpOnly || cookie.Secure { t.Fatal("wrong local cookie settings") } if w = request("GET", "/api/users", "", "", cookie); w.Code != 200 { t.Fatal(w.Code, w.Body.String()) } if w = request("POST", "/api/users", `{"username":"member","password":"member-password-123"}`, "", cookie); w.Code != 403 { t.Fatal("CSRF accepted", w.Code) } if w = request("POST", "/api/users", `{"username":"member","password":"member-password-123"}`, login.CSRF, cookie); w.Code != 200 { t.Fatal(w.Code, w.Body.String()) } if w = request("POST", "/api/logout", "", login.CSRF, cookie); w.Code != 200 { t.Fatal(w.Code) } if w = request("GET", "/api/me", "", "", cookie); w.Code != 401 { t.Fatal("session not revoked") } } func TestOriginRequiredWithoutPublicURL(t *testing.T) { a := &API{} for _, tc := range []struct { origin string want bool }{{"", false}, {"http://evil.test", false}, {"http://panel.test", true}} { r := httptest.NewRequest("POST", "http://panel.test/api/login", nil) r.Header.Set("Origin", tc.origin) if a.panelOriginAllowed(r) != tc.want { t.Fatalf("origin %q", tc.origin) } } }