mirror of
https://github.com/MengMengCode/VoCat.git
synced 2026-08-13 03:13:43 +08:00
141 lines
4.6 KiB
Go
141 lines
4.6 KiB
Go
package developer
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"vocat/internal/exportproxy"
|
|
"vocat/internal/httpsmode"
|
|
"vocat/internal/store"
|
|
)
|
|
|
|
func Enabled(ctx context.Context, database *store.Store) bool {
|
|
setting, err := database.AppSetting(ctx, EnabledSettingKey)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
var document struct {
|
|
Enabled bool `json:"enabled"`
|
|
}
|
|
return json.Unmarshal(setting.Value, &document) == nil && document.Enabled
|
|
}
|
|
|
|
const (
|
|
EnabledSettingKey = "developer.enabled"
|
|
DeviceLimitSettingKey = "developer.device_limit"
|
|
SMSHourlyLimitKey = "developer.sms_hourly_limit"
|
|
DefaultDeviceLimit = 5
|
|
MaxDeviceLimit = 128
|
|
DefaultSMSHourlyLimit = 10
|
|
MaxSMSHourlyLimit = 1000
|
|
)
|
|
|
|
func DeviceLimit(ctx context.Context, database *store.Store, enabled bool) int {
|
|
if !enabled {
|
|
return DefaultDeviceLimit
|
|
}
|
|
setting, err := database.AppSetting(ctx, DeviceLimitSettingKey)
|
|
if err != nil {
|
|
return DefaultDeviceLimit
|
|
}
|
|
var document struct {
|
|
Limit int `json:"limit"`
|
|
}
|
|
if json.Unmarshal(setting.Value, &document) != nil || document.Limit < 1 || document.Limit > MaxDeviceLimit {
|
|
return DefaultDeviceLimit
|
|
}
|
|
return document.Limit
|
|
}
|
|
|
|
func SetDeviceLimit(ctx context.Context, database *store.Store, limit int) error {
|
|
if limit < 1 || limit > MaxDeviceLimit {
|
|
return fmt.Errorf("device limit must be between 1 and %d", MaxDeviceLimit)
|
|
}
|
|
value, err := json.Marshal(map[string]int{"limit": limit})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return database.UpsertAppSetting(ctx, store.AppSetting{Key: DeviceLimitSettingKey, Value: value})
|
|
}
|
|
|
|
// SMSHourlyLimit is enforced regardless of developer mode. Developer mode
|
|
// only controls whether administrators can see and modify this value.
|
|
func SMSHourlyLimit(ctx context.Context, database *store.Store) int {
|
|
setting, err := database.AppSetting(ctx, SMSHourlyLimitKey)
|
|
if err != nil {
|
|
return DefaultSMSHourlyLimit
|
|
}
|
|
var document struct {
|
|
Limit int `json:"limit"`
|
|
}
|
|
if json.Unmarshal(setting.Value, &document) != nil || document.Limit < 1 || document.Limit > MaxSMSHourlyLimit {
|
|
return DefaultSMSHourlyLimit
|
|
}
|
|
return document.Limit
|
|
}
|
|
|
|
func SetSMSHourlyLimit(ctx context.Context, database *store.Store, limit int) error {
|
|
if limit < 1 || limit > MaxSMSHourlyLimit {
|
|
return fmt.Errorf("SMS hourly limit must be between 1 and %d", MaxSMSHourlyLimit)
|
|
}
|
|
value, err := json.Marshal(map[string]int{"limit": limit})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return database.UpsertAppSetting(ctx, store.AppSetting{Key: SMSHourlyLimitKey, Value: value})
|
|
}
|
|
|
|
// ResetExperimental restores every mutable developer-only setting. It is
|
|
// called both by `vocat develop off` and at startup whenever developer mode is
|
|
// disabled, so stale database values cannot silently remain active.
|
|
func ResetExperimental(ctx context.Context, database *store.Store) error {
|
|
httpsValue, err := json.Marshal(map[string]bool{"enabled": false})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var resetErrors []error
|
|
if err := database.UpsertAppSetting(ctx, store.AppSetting{Key: httpsmode.SettingKey, Value: httpsValue}); err != nil {
|
|
resetErrors = append(resetErrors, fmt.Errorf("reset self-signed HTTPS: %w", err))
|
|
}
|
|
if err := SetDeviceLimit(ctx, database, DefaultDeviceLimit); err != nil {
|
|
resetErrors = append(resetErrors, fmt.Errorf("reset device limit: %w", err))
|
|
}
|
|
if err := SetSMSHourlyLimit(ctx, database, DefaultSMSHourlyLimit); err != nil {
|
|
resetErrors = append(resetErrors, fmt.Errorf("reset SMS hourly limit: %w", err))
|
|
}
|
|
if err := database.DeleteAppSetting(ctx, exportproxy.SettingKey); err != nil && !errors.Is(err, store.ErrNotFound) {
|
|
resetErrors = append(resetErrors, fmt.Errorf("delete export proxy configurations: %w", err))
|
|
}
|
|
devices, err := database.ListDevices(ctx)
|
|
if err != nil {
|
|
resetErrors = append(resetErrors, fmt.Errorf("list devices while disabling roaming data: %w", err))
|
|
} else {
|
|
for _, device := range devices {
|
|
if !device.NetworkEnabled {
|
|
continue
|
|
}
|
|
device.NetworkEnabled = false
|
|
if err := database.UpsertDevice(ctx, device); err != nil {
|
|
resetErrors = append(resetErrors, fmt.Errorf("disable roaming data for device %s: %w", device.ID, err))
|
|
}
|
|
}
|
|
}
|
|
policies, err := database.ListCardPolicies(ctx)
|
|
if err != nil {
|
|
resetErrors = append(resetErrors, fmt.Errorf("list card policies while disabling roaming data: %w", err))
|
|
} else {
|
|
for _, policy := range policies {
|
|
if !policy.NetworkEnabled {
|
|
continue
|
|
}
|
|
policy.NetworkEnabled = false
|
|
if err := database.UpsertCardPolicy(ctx, policy); err != nil {
|
|
resetErrors = append(resetErrors, fmt.Errorf("disable roaming policy for card %s: %w", policy.ICCID, err))
|
|
}
|
|
}
|
|
}
|
|
return errors.Join(resetErrors...)
|
|
}
|