Implements a master toggle for security features across config, CLI, and application logic. This allows granular control over whether the advanced security middleware and protections are active globally.
126 lines
3.8 KiB
Go
126 lines
3.8 KiB
Go
package server
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
"warpbox/lib/activity"
|
|
"warpbox/lib/alerts"
|
|
"warpbox/lib/config"
|
|
"warpbox/lib/security"
|
|
)
|
|
|
|
func TestAdminSecurityActionsWriteAuditTrail(t *testing.T) {
|
|
app, router := setupAdminSecurityTest(t)
|
|
|
|
for _, body := range []string{
|
|
`{"action":"ban","ip":"203.0.113.7"}`,
|
|
`{"action":"unban","ip":"203.0.113.7"}`,
|
|
} {
|
|
request := httptest.NewRequest(http.MethodPost, "/admin/security/actions", strings.NewReader(body))
|
|
request.Header.Set("Content-Type", "application/json")
|
|
request.AddCookie(authCookie(app))
|
|
response := httptest.NewRecorder()
|
|
router.ServeHTTP(response, request)
|
|
if response.Code != http.StatusOK {
|
|
t.Fatalf("expected 200, got %d body=%s", response.Code, response.Body.String())
|
|
}
|
|
}
|
|
|
|
events, err := app.activityStore.List(100, app.config.ActivityRetentionSeconds)
|
|
if err != nil {
|
|
t.Fatalf("activity list error: %v", err)
|
|
}
|
|
if len(events) < 2 {
|
|
t.Fatalf("expected activity events, got %d", len(events))
|
|
}
|
|
alertsList, err := app.alertStore.List(100)
|
|
if err != nil {
|
|
t.Fatalf("alerts list error: %v", err)
|
|
}
|
|
if len(alertsList) < 2 {
|
|
t.Fatalf("expected alerts for manual actions, got %d", len(alertsList))
|
|
}
|
|
}
|
|
|
|
func TestAdminSecurityBulkUnbanAndUnbanAll(t *testing.T) {
|
|
app, router := setupAdminSecurityTest(t)
|
|
app.securityGuard.Ban("203.0.113.8", 300)
|
|
app.securityGuard.Ban("203.0.113.9", 300)
|
|
|
|
request := httptest.NewRequest(http.MethodPost, "/admin/security/actions", strings.NewReader(`{"action":"bulk_unban","ips":["203.0.113.8"]}`))
|
|
request.Header.Set("Content-Type", "application/json")
|
|
request.AddCookie(authCookie(app))
|
|
response := httptest.NewRecorder()
|
|
router.ServeHTTP(response, request)
|
|
if response.Code != http.StatusOK {
|
|
t.Fatalf("bulk_unban expected 200, got %d", response.Code)
|
|
}
|
|
if app.securityGuard.IsBanned("203.0.113.8") {
|
|
t.Fatal("expected selected IP to be unbanned")
|
|
}
|
|
if !app.securityGuard.IsBanned("203.0.113.9") {
|
|
t.Fatal("expected non-selected IP to remain banned")
|
|
}
|
|
|
|
requestAll := httptest.NewRequest(http.MethodPost, "/admin/security/actions", strings.NewReader(`{"action":"unban_all"}`))
|
|
requestAll.Header.Set("Content-Type", "application/json")
|
|
requestAll.AddCookie(authCookie(app))
|
|
responseAll := httptest.NewRecorder()
|
|
router.ServeHTTP(responseAll, requestAll)
|
|
if responseAll.Code != http.StatusOK {
|
|
t.Fatalf("unban_all expected 200, got %d", responseAll.Code)
|
|
}
|
|
if len(app.securityGuard.BanList()) != 0 {
|
|
t.Fatal("expected all bans to be removed")
|
|
}
|
|
}
|
|
|
|
func setupAdminSecurityTest(t *testing.T) (*App, *gin.Engine) {
|
|
t.Helper()
|
|
gin.SetMode(gin.TestMode)
|
|
cwd, _ := os.Getwd()
|
|
root := filepath.Clean(filepath.Join(cwd, "..", ".."))
|
|
if err := os.Chdir(root); err != nil {
|
|
t.Fatalf("chdir: %v", err)
|
|
}
|
|
t.Cleanup(func() { _ = os.Chdir(cwd) })
|
|
|
|
clearAdminSettingsEnv(t)
|
|
t.Setenv("WARPBOX_DATA_DIR", t.TempDir())
|
|
t.Setenv("WARPBOX_ADMIN_PASSWORD", "secret")
|
|
t.Setenv("WARPBOX_ADMIN_ENABLED", "true")
|
|
|
|
cfg, err := config.Load()
|
|
if err != nil {
|
|
t.Fatalf("config load: %v", err)
|
|
}
|
|
if err := cfg.EnsureDirectories(); err != nil {
|
|
t.Fatalf("ensure dirs: %v", err)
|
|
}
|
|
|
|
app := &App{
|
|
config: cfg,
|
|
activityStore: activity.NewStore(filepath.Join(cfg.DBDir, "activity.json")),
|
|
alertStore: alerts.NewStore(filepath.Join(cfg.DBDir, "alerts.json")),
|
|
securityGuard: security.NewGuard(),
|
|
}
|
|
if err := app.reloadSecurityConfig(); err != nil {
|
|
t.Fatalf("reload security config: %v", err)
|
|
}
|
|
t.Cleanup(func() { _ = app.securityGuard.Close() })
|
|
|
|
router := gin.New()
|
|
admin := router.Group("/admin")
|
|
admin.GET("/login", app.handleAdminLogin)
|
|
protected := router.Group("/admin", app.adminAuthMiddleware)
|
|
protected.POST("/security/actions", app.handleAdminSecurityAction)
|
|
return app, router
|
|
}
|