feat(config): add security feature toggle support

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.
This commit is contained in:
2026-05-03 23:07:21 +03:00
parent 290a3d15db
commit 43baade930
15 changed files with 78 additions and 12 deletions

View File

@@ -22,6 +22,9 @@ func TestDefaults(t *testing.T) {
if !cfg.GuestUploadsEnabled || !cfg.APIEnabled || !cfg.ZipDownloadsEnabled || !cfg.OneTimeDownloadsEnabled {
t.Fatal("expected default guest/API/download toggles to be enabled")
}
if !cfg.SecurityEnabled {
t.Fatal("expected security features to be enabled by default")
}
if cfg.AdminUsername != "admin" {
t.Fatalf("unexpected admin username: %s", cfg.AdminUsername)
}
@@ -39,6 +42,7 @@ func TestEnvironmentOverrides(t *testing.T) {
t.Setenv("WARPBOX_BOX_POLL_INTERVAL_MS", "2000")
t.Setenv("WARPBOX_ADMIN_USERNAME", "root")
t.Setenv("WARPBOX_ONE_TIME_DOWNLOAD_RETRY_ON_FAILURE", "true")
t.Setenv("WARPBOX_SECURITY_ENABLED", "false")
cfg, err := Load()
if err != nil {
@@ -63,6 +67,9 @@ func TestEnvironmentOverrides(t *testing.T) {
if !cfg.OneTimeDownloadRetryOnFailure {
t.Fatal("expected one-time retry-on-failure env override to be applied")
}
if cfg.SecurityEnabled {
t.Fatal("expected security features toggle from environment to be applied")
}
if cfg.Source(SettingAPIEnabled) != SourceEnv {
t.Fatalf("expected API setting source to be env, got %s", cfg.Source(SettingAPIEnabled))
}
@@ -191,6 +198,7 @@ func clearConfigEnv(t *testing.T) {
"WARPBOX_BOX_POLL_INTERVAL_MS",
"WARPBOX_THUMBNAIL_BATCH_SIZE",
"WARPBOX_THUMBNAIL_INTERVAL_SECONDS",
"WARPBOX_SECURITY_ENABLED",
} {
t.Setenv(name, "")
}

View File

@@ -21,6 +21,7 @@ var Definitions = []SettingDefinition{
{Key: SettingThumbnailBatchSize, EnvName: "WARPBOX_THUMBNAIL_BATCH_SIZE", Label: "Thumbnail batch size", Type: SettingTypeInt, Editable: true, Minimum: 1},
{Key: SettingThumbnailIntervalSeconds, EnvName: "WARPBOX_THUMBNAIL_INTERVAL_SECONDS", Label: "Thumbnail interval seconds", Type: SettingTypeInt, Editable: true, Minimum: 1},
{Key: SettingActivityRetentionSeconds, EnvName: "WARPBOX_ACTIVITY_RETENTION_SECONDS", Label: "Activity retention seconds", Type: SettingTypeInt64, Editable: true, Minimum: 60},
{Key: SettingSecurityEnabled, EnvName: "WARPBOX_SECURITY_ENABLED", Label: "Security features enabled", Type: SettingTypeBool, Editable: true},
{Key: SettingSecurityIPWhitelist, EnvName: "WARPBOX_SECURITY_IP_WHITELIST", Label: "Security IP whitelist", Type: SettingTypeText, Editable: true},
{Key: SettingSecurityAdminIPWhitelist, EnvName: "WARPBOX_SECURITY_ADMIN_IP_WHITELIST", Label: "Security admin IP whitelist", Type: SettingTypeText, Editable: true},
{Key: SettingTrustedProxyCIDRs, EnvName: "WARPBOX_TRUSTED_PROXY_CIDRS", Label: "Trusted proxy CIDRs", Type: SettingTypeText, Editable: true},

View File

@@ -27,6 +27,7 @@ func Load() (*Config, error) {
ThumbnailBatchSize: 10,
ThumbnailIntervalSeconds: 30,
ActivityRetentionSeconds: 7 * 24 * 60 * 60,
SecurityEnabled: true,
SecurityLoginWindowSeconds: 10 * 60,
SecurityLoginMaxAttempts: 8,
SecurityBanSeconds: 30 * 60,
@@ -91,6 +92,7 @@ func Load() (*Config, error) {
{SettingOneTimeDownloadRetryFail, "WARPBOX_ONE_TIME_DOWNLOAD_RETRY_ON_FAILURE", &cfg.OneTimeDownloadRetryOnFailure},
{SettingRenewOnAccessEnabled, "WARPBOX_RENEW_ON_ACCESS_ENABLED", &cfg.RenewOnAccessEnabled},
{SettingRenewOnDownloadEnabled, "WARPBOX_RENEW_ON_DOWNLOAD_ENABLED", &cfg.RenewOnDownloadEnabled},
{SettingSecurityEnabled, "WARPBOX_SECURITY_ENABLED", &cfg.SecurityEnabled},
}
for _, item := range envBools {
if err := cfg.applyBoolEnv(item.key, item.name, item.target); err != nil {
@@ -209,6 +211,7 @@ func (cfg *Config) captureDefaults() {
cfg.captureDefaultValue(SettingThumbnailBatchSize, strconv.Itoa(cfg.ThumbnailBatchSize))
cfg.captureDefaultValue(SettingThumbnailIntervalSeconds, strconv.Itoa(cfg.ThumbnailIntervalSeconds))
cfg.captureDefaultValue(SettingActivityRetentionSeconds, strconv.FormatInt(cfg.ActivityRetentionSeconds, 10))
cfg.captureDefaultValue(SettingSecurityEnabled, formatBool(cfg.SecurityEnabled))
cfg.captureDefaultValue(SettingSecurityIPWhitelist, cfg.SecurityIPWhitelist)
cfg.captureDefaultValue(SettingSecurityAdminIPWhitelist, cfg.SecurityAdminIPWhitelist)
cfg.captureDefaultValue(SettingTrustedProxyCIDRs, cfg.TrustedProxyCIDRs)

View File

@@ -37,6 +37,7 @@ const (
SettingThumbnailIntervalSeconds = "thumbnail_interval_seconds"
SettingDataDir = "data_dir"
SettingActivityRetentionSeconds = "activity_retention_seconds"
SettingSecurityEnabled = "security_enabled"
SettingSecurityIPWhitelist = "security_ip_whitelist"
SettingSecurityAdminIPWhitelist = "security_admin_ip_whitelist"
SettingTrustedProxyCIDRs = "trusted_proxy_cidrs"
@@ -108,6 +109,7 @@ type Config struct {
ThumbnailBatchSize int
ThumbnailIntervalSeconds int
ActivityRetentionSeconds int64
SecurityEnabled bool
SecurityIPWhitelist string
SecurityAdminIPWhitelist string
TrustedProxyCIDRs string

View File

@@ -95,6 +95,8 @@ func (cfg *Config) assignBool(key string, value bool, source Source) {
cfg.RenewOnAccessEnabled = value
case SettingRenewOnDownloadEnabled:
cfg.RenewOnDownloadEnabled = value
case SettingSecurityEnabled:
cfg.SecurityEnabled = value
}
cfg.setValue(key, formatBool(value), source)
}