184 lines
4.3 KiB
Go
184 lines
4.3 KiB
Go
package v1
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/md5"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
argon2 "github.com/alexedwards/argon2id"
|
|
"reichard.io/antholume/database"
|
|
)
|
|
|
|
func TestAPILogin(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
cfg := testConfig()
|
|
server := NewServer(db, cfg)
|
|
|
|
// First, create a user
|
|
createTestUser(t, db, "testuser", "testpass")
|
|
|
|
// Test login
|
|
reqBody := LoginRequest{
|
|
Username: "testuser",
|
|
Password: "testpass",
|
|
}
|
|
body, _ := json.Marshal(reqBody)
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/login", bytes.NewReader(body))
|
|
w := httptest.NewRecorder()
|
|
|
|
server.ServeHTTP(w, req)
|
|
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("Expected 200, got %d: %s", w.Code, w.Body.String())
|
|
}
|
|
|
|
var resp LoginResponse
|
|
if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
|
|
t.Fatalf("Failed to unmarshal response: %v", err)
|
|
}
|
|
|
|
if resp.Username != "testuser" {
|
|
t.Errorf("Expected username 'testuser', got '%s'", resp.Username)
|
|
}
|
|
}
|
|
|
|
func TestAPILoginInvalidCredentials(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
cfg := testConfig()
|
|
server := NewServer(db, cfg)
|
|
|
|
reqBody := LoginRequest{
|
|
Username: "testuser",
|
|
Password: "wrongpass",
|
|
}
|
|
body, _ := json.Marshal(reqBody)
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/login", bytes.NewReader(body))
|
|
w := httptest.NewRecorder()
|
|
|
|
server.ServeHTTP(w, req)
|
|
|
|
if w.Code != http.StatusUnauthorized {
|
|
t.Fatalf("Expected 401, got %d", w.Code)
|
|
}
|
|
}
|
|
|
|
func TestAPILogout(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
cfg := testConfig()
|
|
server := NewServer(db, cfg)
|
|
|
|
// Create user and login
|
|
createTestUser(t, db, "testuser", "testpass")
|
|
|
|
// Login first
|
|
reqBody := LoginRequest{Username: "testuser", Password: "testpass"}
|
|
body, _ := json.Marshal(reqBody)
|
|
loginReq := httptest.NewRequest(http.MethodPost, "/api/v1/auth/login", bytes.NewReader(body))
|
|
loginResp := httptest.NewRecorder()
|
|
server.ServeHTTP(loginResp, loginReq)
|
|
|
|
// Get session cookie
|
|
cookies := loginResp.Result().Cookies()
|
|
if len(cookies) == 0 {
|
|
t.Fatal("No session cookie returned")
|
|
}
|
|
|
|
// Logout
|
|
req := httptest.NewRequest(http.MethodPost, "/api/v1/auth/logout", nil)
|
|
req.AddCookie(cookies[0])
|
|
w := httptest.NewRecorder()
|
|
|
|
server.ServeHTTP(w, req)
|
|
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("Expected 200, got %d", w.Code)
|
|
}
|
|
}
|
|
|
|
func TestAPIGetMe(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
cfg := testConfig()
|
|
server := NewServer(db, cfg)
|
|
|
|
// Create user and login
|
|
createTestUser(t, db, "testuser", "testpass")
|
|
|
|
// Login first
|
|
reqBody := LoginRequest{Username: "testuser", Password: "testpass"}
|
|
body, _ := json.Marshal(reqBody)
|
|
loginReq := httptest.NewRequest(http.MethodPost, "/api/v1/auth/login", bytes.NewReader(body))
|
|
loginResp := httptest.NewRecorder()
|
|
server.ServeHTTP(loginResp, loginReq)
|
|
|
|
// Get session cookie
|
|
cookies := loginResp.Result().Cookies()
|
|
if len(cookies) == 0 {
|
|
t.Fatal("No session cookie returned")
|
|
}
|
|
|
|
// Get me
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/auth/me", nil)
|
|
req.AddCookie(cookies[0])
|
|
w := httptest.NewRecorder()
|
|
|
|
server.ServeHTTP(w, req)
|
|
|
|
if w.Code != http.StatusOK {
|
|
t.Fatalf("Expected 200, got %d", w.Code)
|
|
}
|
|
|
|
var resp UserData
|
|
if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil {
|
|
t.Fatalf("Failed to unmarshal response: %v", err)
|
|
}
|
|
|
|
if resp.Username != "testuser" {
|
|
t.Errorf("Expected username 'testuser', got '%s'", resp.Username)
|
|
}
|
|
}
|
|
|
|
func TestAPIGetMeUnauthenticated(t *testing.T) {
|
|
db := setupTestDB(t)
|
|
cfg := testConfig()
|
|
server := NewServer(db, cfg)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/v1/auth/me", nil)
|
|
w := httptest.NewRecorder()
|
|
|
|
server.ServeHTTP(w, req)
|
|
|
|
if w.Code != http.StatusUnauthorized {
|
|
t.Fatalf("Expected 401, got %d", w.Code)
|
|
}
|
|
}
|
|
|
|
func createTestUser(t *testing.T, db *database.DBManager, username, password string) {
|
|
t.Helper()
|
|
|
|
// MD5 hash for KOSync compatibility (matches existing system)
|
|
md5Hash := fmt.Sprintf("%x", md5.Sum([]byte(password)))
|
|
|
|
// Then argon2 hash the MD5
|
|
hashedPassword, err := argon2.CreateHash(md5Hash, argon2.DefaultParams)
|
|
if err != nil {
|
|
t.Fatalf("Failed to hash password: %v", err)
|
|
}
|
|
|
|
authHash := "test-auth-hash"
|
|
|
|
_, err = db.Queries.CreateUser(t.Context(), database.CreateUserParams{
|
|
ID: username,
|
|
Pass: &hashedPassword,
|
|
AuthHash: &authHash,
|
|
Admin: true,
|
|
})
|
|
if err != nil {
|
|
t.Fatalf("Failed to create user: %v", err)
|
|
}
|
|
} |