feat(config): add box owner policy settings
Adds configuration options and environment variables to manage box owner policies, including settings for refresh counts and expiry.
This commit is contained in:
@@ -28,6 +28,12 @@ func TestDefaults(t *testing.T) {
|
||||
if cfg.AdminPassword != "" {
|
||||
t.Fatal("expected default admin password to be empty")
|
||||
}
|
||||
if !cfg.BoxOwnerEditEnabled || !cfg.BoxOwnerRefreshEnabled || !cfg.BoxOwnerPasswordEditEnabled {
|
||||
t.Fatal("expected box owner policy defaults to be enabled")
|
||||
}
|
||||
if cfg.BoxOwnerMaxRefreshCount != 3 || cfg.BoxOwnerMaxRefreshAmountSeconds != 86400 || cfg.BoxOwnerMaxTotalExpirySeconds != 604800 {
|
||||
t.Fatalf("unexpected box owner policy defaults: %#v", cfg)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEnvironmentOverrides(t *testing.T) {
|
||||
@@ -39,6 +45,8 @@ 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_BOX_OWNER_MAX_REFRESH_COUNT", "5")
|
||||
t.Setenv("WARPBOX_BOX_OWNER_PASSWORD_EDIT_ENABLED", "false")
|
||||
|
||||
cfg, err := Load()
|
||||
if err != nil {
|
||||
@@ -63,6 +71,9 @@ func TestEnvironmentOverrides(t *testing.T) {
|
||||
if !cfg.OneTimeDownloadRetryOnFailure {
|
||||
t.Fatal("expected one-time retry-on-failure env override to be applied")
|
||||
}
|
||||
if cfg.BoxOwnerMaxRefreshCount != 5 || cfg.BoxOwnerPasswordEditEnabled {
|
||||
t.Fatal("expected box owner policy env overrides to be applied")
|
||||
}
|
||||
if cfg.Source(SettingAPIEnabled) != SourceEnv {
|
||||
t.Fatalf("expected API setting source to be env, got %s", cfg.Source(SettingAPIEnabled))
|
||||
}
|
||||
@@ -148,6 +159,12 @@ func TestSettingsOverrideValidation(t *testing.T) {
|
||||
if err := cfg.ApplyOverride(SettingGlobalMaxFileSizeBytes, "1"); err == nil {
|
||||
t.Fatal("expected hard limit override to fail")
|
||||
}
|
||||
if err := cfg.ApplyOverride(SettingBoxOwnerMaxRefreshCount, "2"); err != nil {
|
||||
t.Fatalf("expected box owner policy override to pass: %v", err)
|
||||
}
|
||||
if cfg.BoxOwnerMaxRefreshCount != 2 {
|
||||
t.Fatalf("expected box owner policy override to apply, got %d", cfg.BoxOwnerMaxRefreshCount)
|
||||
}
|
||||
}
|
||||
|
||||
func clearConfigEnv(t *testing.T) {
|
||||
@@ -181,6 +198,12 @@ func clearConfigEnv(t *testing.T) {
|
||||
"WARPBOX_BOX_POLL_INTERVAL_MS",
|
||||
"WARPBOX_THUMBNAIL_BATCH_SIZE",
|
||||
"WARPBOX_THUMBNAIL_INTERVAL_SECONDS",
|
||||
"WARPBOX_BOX_OWNER_EDIT_ENABLED",
|
||||
"WARPBOX_BOX_OWNER_REFRESH_ENABLED",
|
||||
"WARPBOX_BOX_OWNER_MAX_REFRESH_COUNT",
|
||||
"WARPBOX_BOX_OWNER_MAX_REFRESH_AMOUNT_SECONDS",
|
||||
"WARPBOX_BOX_OWNER_MAX_TOTAL_EXPIRY_SECONDS",
|
||||
"WARPBOX_BOX_OWNER_PASSWORD_EDIT_ENABLED",
|
||||
} {
|
||||
t.Setenv(name, "")
|
||||
}
|
||||
|
||||
@@ -20,6 +20,12 @@ var Definitions = []SettingDefinition{
|
||||
{Key: SettingBoxPollIntervalMS, EnvName: "WARPBOX_BOX_POLL_INTERVAL_MS", Label: "Box poll interval milliseconds", Type: SettingTypeInt, Editable: true, Minimum: 1000},
|
||||
{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: SettingBoxOwnerEditEnabled, EnvName: "WARPBOX_BOX_OWNER_EDIT_ENABLED", Label: "Box owner edit enabled", Type: SettingTypeBool, Editable: true},
|
||||
{Key: SettingBoxOwnerRefreshEnabled, EnvName: "WARPBOX_BOX_OWNER_REFRESH_ENABLED", Label: "Box owner refresh enabled", Type: SettingTypeBool, Editable: true},
|
||||
{Key: SettingBoxOwnerMaxRefreshCount, EnvName: "WARPBOX_BOX_OWNER_MAX_REFRESH_COUNT", Label: "Box owner max refresh count", Type: SettingTypeInt, Editable: true, Minimum: 0},
|
||||
{Key: SettingBoxOwnerMaxRefreshAmount, EnvName: "WARPBOX_BOX_OWNER_MAX_REFRESH_AMOUNT_SECONDS", Label: "Box owner max refresh amount seconds", Type: SettingTypeInt64, Editable: true, Minimum: 0},
|
||||
{Key: SettingBoxOwnerMaxTotalExpiry, EnvName: "WARPBOX_BOX_OWNER_MAX_TOTAL_EXPIRY_SECONDS", Label: "Box owner max total expiry seconds", Type: SettingTypeInt64, Editable: true, Minimum: 0},
|
||||
{Key: SettingBoxOwnerPasswordEdit, EnvName: "WARPBOX_BOX_OWNER_PASSWORD_EDIT_ENABLED", Label: "Box owner password edit enabled", Type: SettingTypeBool, Editable: true},
|
||||
}
|
||||
|
||||
func (cfg *Config) SettingRows() []SettingRow {
|
||||
@@ -38,6 +44,10 @@ func (cfg *Config) Source(key string) Source {
|
||||
return cfg.sourceFor(key)
|
||||
}
|
||||
|
||||
func (cfg *Config) SettingValue(key string) string {
|
||||
return cfg.values[key]
|
||||
}
|
||||
|
||||
func (cfg *Config) AdminLoginEnabled(hasAdminUser bool) bool {
|
||||
switch cfg.AdminEnabled {
|
||||
case AdminEnabledFalse:
|
||||
|
||||
@@ -11,24 +11,30 @@ import (
|
||||
|
||||
func Load() (*Config, error) {
|
||||
cfg := &Config{
|
||||
DataDir: "./data",
|
||||
AdminUsername: "admin",
|
||||
AdminEnabled: AdminEnabledAuto,
|
||||
AllowAdminSettingsOverride: true,
|
||||
GuestUploadsEnabled: true,
|
||||
APIEnabled: true,
|
||||
ZipDownloadsEnabled: true,
|
||||
OneTimeDownloadsEnabled: true,
|
||||
OneTimeDownloadExpirySeconds: 7 * 24 * 60 * 60,
|
||||
OneTimeDownloadRetryOnFailure: false,
|
||||
DefaultGuestExpirySeconds: 10,
|
||||
MaxGuestExpirySeconds: 48 * 60 * 60,
|
||||
SessionTTLSeconds: 24 * 60 * 60,
|
||||
BoxPollIntervalMS: 5000,
|
||||
ThumbnailBatchSize: 10,
|
||||
ThumbnailIntervalSeconds: 30,
|
||||
sources: make(map[string]Source),
|
||||
values: make(map[string]string),
|
||||
DataDir: "./data",
|
||||
AdminUsername: "admin",
|
||||
AdminEnabled: AdminEnabledAuto,
|
||||
AllowAdminSettingsOverride: true,
|
||||
GuestUploadsEnabled: true,
|
||||
APIEnabled: true,
|
||||
ZipDownloadsEnabled: true,
|
||||
OneTimeDownloadsEnabled: true,
|
||||
OneTimeDownloadExpirySeconds: 7 * 24 * 60 * 60,
|
||||
OneTimeDownloadRetryOnFailure: false,
|
||||
DefaultGuestExpirySeconds: 10,
|
||||
MaxGuestExpirySeconds: 48 * 60 * 60,
|
||||
SessionTTLSeconds: 24 * 60 * 60,
|
||||
BoxPollIntervalMS: 5000,
|
||||
ThumbnailBatchSize: 10,
|
||||
ThumbnailIntervalSeconds: 30,
|
||||
BoxOwnerEditEnabled: true,
|
||||
BoxOwnerRefreshEnabled: true,
|
||||
BoxOwnerMaxRefreshCount: 3,
|
||||
BoxOwnerMaxRefreshAmountSeconds: 24 * 60 * 60,
|
||||
BoxOwnerMaxTotalExpirySeconds: 7 * 24 * 60 * 60,
|
||||
BoxOwnerPasswordEditEnabled: true,
|
||||
sources: make(map[string]Source),
|
||||
values: make(map[string]string),
|
||||
}
|
||||
|
||||
// Config precedence: defaults -> env -> overrides.
|
||||
@@ -73,6 +79,9 @@ 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},
|
||||
{SettingBoxOwnerEditEnabled, "WARPBOX_BOX_OWNER_EDIT_ENABLED", &cfg.BoxOwnerEditEnabled},
|
||||
{SettingBoxOwnerRefreshEnabled, "WARPBOX_BOX_OWNER_REFRESH_ENABLED", &cfg.BoxOwnerRefreshEnabled},
|
||||
{SettingBoxOwnerPasswordEdit, "WARPBOX_BOX_OWNER_PASSWORD_EDIT_ENABLED", &cfg.BoxOwnerPasswordEditEnabled},
|
||||
}
|
||||
for _, item := range envBools {
|
||||
if err := cfg.applyBoolEnv(item.key, item.name, item.target); err != nil {
|
||||
@@ -90,6 +99,8 @@ func Load() (*Config, error) {
|
||||
{SettingMaxGuestExpirySecs, "WARPBOX_MAX_GUEST_EXPIRY_SECONDS", 0, &cfg.MaxGuestExpirySeconds},
|
||||
{SettingOneTimeDownloadExpirySecs, "WARPBOX_ONE_TIME_DOWNLOAD_EXPIRY_SECONDS", 0, &cfg.OneTimeDownloadExpirySeconds},
|
||||
{SettingSessionTTLSeconds, "WARPBOX_SESSION_TTL_SECONDS", 60, &cfg.SessionTTLSeconds},
|
||||
{SettingBoxOwnerMaxRefreshAmount, "WARPBOX_BOX_OWNER_MAX_REFRESH_AMOUNT_SECONDS", 0, &cfg.BoxOwnerMaxRefreshAmountSeconds},
|
||||
{SettingBoxOwnerMaxTotalExpiry, "WARPBOX_BOX_OWNER_MAX_TOTAL_EXPIRY_SECONDS", 0, &cfg.BoxOwnerMaxTotalExpirySeconds},
|
||||
}
|
||||
for _, item := range envInt64s {
|
||||
if err := cfg.applyInt64Env(item.key, item.name, item.min, item.target); err != nil {
|
||||
@@ -122,6 +133,7 @@ func Load() (*Config, error) {
|
||||
{SettingBoxPollIntervalMS, "WARPBOX_BOX_POLL_INTERVAL_MS", 1000, &cfg.BoxPollIntervalMS},
|
||||
{SettingThumbnailBatchSize, "WARPBOX_THUMBNAIL_BATCH_SIZE", 1, &cfg.ThumbnailBatchSize},
|
||||
{SettingThumbnailIntervalSeconds, "WARPBOX_THUMBNAIL_INTERVAL_SECONDS", 1, &cfg.ThumbnailIntervalSeconds},
|
||||
{SettingBoxOwnerMaxRefreshCount, "WARPBOX_BOX_OWNER_MAX_REFRESH_COUNT", 0, &cfg.BoxOwnerMaxRefreshCount},
|
||||
}
|
||||
for _, item := range envInts {
|
||||
if err := cfg.applyIntEnv(item.key, item.name, item.min, item.target); err != nil {
|
||||
@@ -171,6 +183,12 @@ func (cfg *Config) captureDefaults() {
|
||||
cfg.setValue(SettingBoxPollIntervalMS, strconv.Itoa(cfg.BoxPollIntervalMS), SourceDefault)
|
||||
cfg.setValue(SettingThumbnailBatchSize, strconv.Itoa(cfg.ThumbnailBatchSize), SourceDefault)
|
||||
cfg.setValue(SettingThumbnailIntervalSeconds, strconv.Itoa(cfg.ThumbnailIntervalSeconds), SourceDefault)
|
||||
cfg.setValue(SettingBoxOwnerEditEnabled, formatBool(cfg.BoxOwnerEditEnabled), SourceDefault)
|
||||
cfg.setValue(SettingBoxOwnerRefreshEnabled, formatBool(cfg.BoxOwnerRefreshEnabled), SourceDefault)
|
||||
cfg.setValue(SettingBoxOwnerMaxRefreshCount, strconv.Itoa(cfg.BoxOwnerMaxRefreshCount), SourceDefault)
|
||||
cfg.setValue(SettingBoxOwnerMaxRefreshAmount, strconv.FormatInt(cfg.BoxOwnerMaxRefreshAmountSeconds, 10), SourceDefault)
|
||||
cfg.setValue(SettingBoxOwnerMaxTotalExpiry, strconv.FormatInt(cfg.BoxOwnerMaxTotalExpirySeconds, 10), SourceDefault)
|
||||
cfg.setValue(SettingBoxOwnerPasswordEdit, formatBool(cfg.BoxOwnerPasswordEditEnabled), SourceDefault)
|
||||
}
|
||||
|
||||
func (cfg *Config) applyStringEnv(key string, name string, target *string) error {
|
||||
|
||||
@@ -36,6 +36,12 @@ const (
|
||||
SettingThumbnailBatchSize = "thumbnail_batch_size"
|
||||
SettingThumbnailIntervalSeconds = "thumbnail_interval_seconds"
|
||||
SettingDataDir = "data_dir"
|
||||
SettingBoxOwnerEditEnabled = "box_owner_edit_enabled"
|
||||
SettingBoxOwnerRefreshEnabled = "box_owner_refresh_enabled"
|
||||
SettingBoxOwnerMaxRefreshCount = "box_owner_max_refresh_count"
|
||||
SettingBoxOwnerMaxRefreshAmount = "box_owner_max_refresh_amount_seconds"
|
||||
SettingBoxOwnerMaxTotalExpiry = "box_owner_max_total_expiry_seconds"
|
||||
SettingBoxOwnerPasswordEdit = "box_owner_password_edit_enabled"
|
||||
)
|
||||
|
||||
type SettingType string
|
||||
@@ -84,16 +90,22 @@ type Config struct {
|
||||
RenewOnAccessEnabled bool
|
||||
RenewOnDownloadEnabled bool
|
||||
|
||||
DefaultGuestExpirySeconds int64
|
||||
MaxGuestExpirySeconds int64
|
||||
GlobalMaxFileSizeBytes int64
|
||||
GlobalMaxBoxSizeBytes int64
|
||||
DefaultUserMaxFileSizeBytes int64
|
||||
DefaultUserMaxBoxSizeBytes int64
|
||||
SessionTTLSeconds int64
|
||||
BoxPollIntervalMS int
|
||||
ThumbnailBatchSize int
|
||||
ThumbnailIntervalSeconds int
|
||||
DefaultGuestExpirySeconds int64
|
||||
MaxGuestExpirySeconds int64
|
||||
GlobalMaxFileSizeBytes int64
|
||||
GlobalMaxBoxSizeBytes int64
|
||||
DefaultUserMaxFileSizeBytes int64
|
||||
DefaultUserMaxBoxSizeBytes int64
|
||||
SessionTTLSeconds int64
|
||||
BoxPollIntervalMS int
|
||||
ThumbnailBatchSize int
|
||||
ThumbnailIntervalSeconds int
|
||||
BoxOwnerEditEnabled bool
|
||||
BoxOwnerRefreshEnabled bool
|
||||
BoxOwnerMaxRefreshCount int
|
||||
BoxOwnerMaxRefreshAmountSeconds int64
|
||||
BoxOwnerMaxTotalExpirySeconds int64
|
||||
BoxOwnerPasswordEditEnabled bool
|
||||
|
||||
sources map[string]Source
|
||||
values map[string]string
|
||||
|
||||
@@ -64,6 +64,12 @@ func (cfg *Config) assignBool(key string, value bool, source Source) {
|
||||
cfg.RenewOnAccessEnabled = value
|
||||
case SettingRenewOnDownloadEnabled:
|
||||
cfg.RenewOnDownloadEnabled = value
|
||||
case SettingBoxOwnerEditEnabled:
|
||||
cfg.BoxOwnerEditEnabled = value
|
||||
case SettingBoxOwnerRefreshEnabled:
|
||||
cfg.BoxOwnerRefreshEnabled = value
|
||||
case SettingBoxOwnerPasswordEdit:
|
||||
cfg.BoxOwnerPasswordEditEnabled = value
|
||||
}
|
||||
cfg.setValue(key, formatBool(value), source)
|
||||
}
|
||||
@@ -82,6 +88,10 @@ func (cfg *Config) assignInt64(key string, value int64, source Source) {
|
||||
cfg.DefaultUserMaxBoxSizeBytes = value
|
||||
case SettingSessionTTLSeconds:
|
||||
cfg.SessionTTLSeconds = value
|
||||
case SettingBoxOwnerMaxRefreshAmount:
|
||||
cfg.BoxOwnerMaxRefreshAmountSeconds = value
|
||||
case SettingBoxOwnerMaxTotalExpiry:
|
||||
cfg.BoxOwnerMaxTotalExpirySeconds = value
|
||||
}
|
||||
cfg.setValue(key, strconv.FormatInt(value, 10), source)
|
||||
}
|
||||
@@ -94,6 +104,8 @@ func (cfg *Config) assignInt(key string, value int, source Source) {
|
||||
cfg.ThumbnailBatchSize = value
|
||||
case SettingThumbnailIntervalSeconds:
|
||||
cfg.ThumbnailIntervalSeconds = value
|
||||
case SettingBoxOwnerMaxRefreshCount:
|
||||
cfg.BoxOwnerMaxRefreshCount = value
|
||||
}
|
||||
cfg.setValue(key, strconv.Itoa(value), source)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user