157 lines
5.0 KiB
Go
157 lines
5.0 KiB
Go
package api
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/benzjeremy/benzcloud-server/internal/core/auth"
|
|
"github.com/benzjeremy/benzcloud-server/internal/core/config"
|
|
"github.com/benzjeremy/benzcloud-server/internal/core/crypto"
|
|
"github.com/benzjeremy/benzcloud-server/internal/core/dns"
|
|
"github.com/benzjeremy/benzcloud-server/internal/core/drive"
|
|
"github.com/benzjeremy/benzcloud-server/internal/core/nebula"
|
|
"github.com/benzjeremy/benzcloud-server/internal/core/plugins"
|
|
)
|
|
|
|
func TestAPISetupAndPairing(t *testing.T) {
|
|
tempDir, err := os.MkdirTemp("", "benzcloud_api_test")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(tempDir)
|
|
|
|
cfg := config.DefaultConfig(tempDir)
|
|
salt, _ := crypto.GenerateSalt(16)
|
|
masterKey := crypto.DeriveKey("MasterTestKey123", salt)
|
|
|
|
authMgr, err := auth.NewManager(tempDir)
|
|
if err != nil {
|
|
t.Fatalf("auth.NewManager: %v", err)
|
|
}
|
|
|
|
dnsSrv := dns.NewServer("intern", "10.42.0.1", 15354)
|
|
nebulaMgr := nebula.NewManager(tempDir)
|
|
driveMgr, err := drive.NewDriveManager(tempDir, masterKey)
|
|
if err != nil {
|
|
t.Fatalf("drive.NewDriveManager: %v", err)
|
|
}
|
|
pluginMgr := plugins.NewManager(tempDir, "intern", "token123")
|
|
|
|
apiServer := NewServer(cfg, authMgr, dnsSrv, nebulaMgr, driveMgr, pluginMgr)
|
|
handler := apiServer.Handler()
|
|
|
|
// 1. Check /api/status before setup
|
|
rec := httptest.NewRecorder()
|
|
req := httptest.NewRequest(http.MethodGet, "/api/status", nil)
|
|
handler.ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("Expected 200 on /api/status, got %d", rec.Code)
|
|
}
|
|
var statusResp map[string]interface{}
|
|
_ = json.NewDecoder(rec.Body).Decode(&statusResp)
|
|
if statusResp["setup_completed"] != false {
|
|
t.Fatal("Expected setup_completed to be false")
|
|
}
|
|
|
|
// 2. Perform /api/setup
|
|
setupPayload := map[string]string{
|
|
"base_domain": "benzjeremy.de",
|
|
"admin_username": "admin",
|
|
"admin_password": "SuperSecretAdminPassword2026!",
|
|
}
|
|
body, _ := json.Marshal(setupPayload)
|
|
rec = httptest.NewRecorder()
|
|
req = httptest.NewRequest(http.MethodPost, "/api/setup", bytes.NewReader(body))
|
|
handler.ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("Expected 200 on /api/setup, got %d: %s", rec.Code, rec.Body.String())
|
|
}
|
|
var setupResp map[string]interface{}
|
|
_ = json.NewDecoder(rec.Body).Decode(&setupResp)
|
|
adminToken := setupResp["session_token"].(string)
|
|
|
|
if cfg.BaseDomain != "benzjeremy.de" {
|
|
t.Fatalf("Expected base_domain benzjeremy.de, got %s", cfg.BaseDomain)
|
|
}
|
|
if !cfg.SetupCompleted {
|
|
t.Fatal("Expected SetupCompleted to be true")
|
|
}
|
|
|
|
// 3. Client-Kopplung via /api/pair
|
|
pairPayload := map[string]string{
|
|
"username": "admin",
|
|
"password": "SuperSecretAdminPassword2026!",
|
|
}
|
|
pairBody, _ := json.Marshal(pairPayload)
|
|
rec = httptest.NewRecorder()
|
|
req = httptest.NewRequest(http.MethodPost, "/api/pair", bytes.NewReader(pairBody))
|
|
handler.ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("Expected 200 on /api/pair, got %d: %s", rec.Code, rec.Body.String())
|
|
}
|
|
var pairResp map[string]interface{}
|
|
_ = json.NewDecoder(rec.Body).Decode(&pairResp)
|
|
if pairResp["status"] != "paired" {
|
|
t.Fatalf("Expected status paired, got %v", pairResp["status"])
|
|
}
|
|
if pairResp["client_config_yaml"] == "" {
|
|
t.Fatal("Expected non-empty client_config_yaml in pairing response")
|
|
}
|
|
|
|
// 4. Test Drive Upload & Download via API
|
|
fileContent := []byte("BenzCloud Enterprise Shared File via API")
|
|
rec = httptest.NewRecorder()
|
|
req = httptest.NewRequest(http.MethodPost, "/api/drive/upload?path=report.txt", bytes.NewReader(fileContent))
|
|
req.Header.Set("Authorization", "Bearer "+adminToken)
|
|
handler.ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("Drive upload failed with %d: %s", rec.Code, rec.Body.String())
|
|
}
|
|
|
|
rec = httptest.NewRecorder()
|
|
req = httptest.NewRequest(http.MethodGet, "/api/drive/download?path=report.txt", nil)
|
|
req.Header.Set("Authorization", "Bearer "+adminToken)
|
|
handler.ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("Drive download failed with %d: %s", rec.Code, rec.Body.String())
|
|
}
|
|
if !bytes.Equal(rec.Body.Bytes(), fileContent) {
|
|
t.Fatalf("Downloaded file mismatch: %s", rec.Body.String())
|
|
}
|
|
|
|
// 5. Test User Creation and Invariant Enforcement
|
|
userPayload := map[string]interface{}{
|
|
"username": "charlie",
|
|
"password": "CharliePassword2026!",
|
|
"permissions": map[string]bool{
|
|
"admin": false,
|
|
"drive": true,
|
|
"vpn": false, // Trying to revoke
|
|
"dns": false, // Trying to revoke
|
|
},
|
|
}
|
|
uBody, _ := json.Marshal(userPayload)
|
|
rec = httptest.NewRecorder()
|
|
req = httptest.NewRequest(http.MethodPost, "/api/users", bytes.NewReader(uBody))
|
|
req.Header.Set("Authorization", "Bearer "+adminToken)
|
|
handler.ServeHTTP(rec, req)
|
|
|
|
if rec.Code != http.StatusCreated {
|
|
t.Fatalf("Create user failed: %d: %s", rec.Code, rec.Body.String())
|
|
}
|
|
var createdUser auth.User
|
|
_ = json.NewDecoder(rec.Body).Decode(&createdUser)
|
|
if !createdUser.Permissions.VPN || !createdUser.Permissions.DNS {
|
|
t.Fatal("CRITICAL INVARIANT VIOLATION: Created user must have VPN and DNS set to true!")
|
|
}
|
|
}
|