From 7cf27ab509b796dbaa0a50e4b299a385b5d37ffb Mon Sep 17 00:00:00 2001 From: ShukeBta <272197458+ShukeBta@users.noreply.github.com> Date: Sat, 27 Jun 2026 10:20:46 +0800 Subject: [PATCH] split storage config secret helpers --- internal/service/storage_config.go | 79 ------------------- internal/service/storage_config_secrets.go | 88 ++++++++++++++++++++++ 2 files changed, 88 insertions(+), 79 deletions(-) create mode 100644 internal/service/storage_config_secrets.go diff --git a/internal/service/storage_config.go b/internal/service/storage_config.go index de5eeb5..a820feb 100644 --- a/internal/service/storage_config.go +++ b/internal/service/storage_config.go @@ -136,85 +136,6 @@ func (s *StorageConfigService) Save(ctx context.Context, in StorageInput) (*Stor return s.Get(ctx, in.Type) } -func shouldPreserveStorageSecretsOnSave(enabled *bool) bool { - return enabled == nil || *enabled -} - -func cloneStorageConfigMap(cfg map[string]any) map[string]any { - out := make(map[string]any, len(cfg)) - for k, v := range cfg { - out[k] = v - } - return out -} - -func (s *StorageConfigService) mergeExistingStorageSecrets(ctx context.Context, typ string, cfg map[string]any) (map[string]any, error) { - view, err := s.Get(ctx, typ) - if err != nil || view == nil { - return cfg, err - } - for _, key := range storagePreservedSecretKeys() { - existing := strings.TrimSpace(strr(view.Config[key])) - if existing == "" { - continue - } - incoming, hasIncoming := cfg[key] - if hasIncoming && !isBlankStorageSecret(incoming) { - continue - } - if storageSecretReplacedByAlternative(typ, key, cfg, view.Config) { - continue - } - cfg[key] = existing - } - return cfg, nil -} - -func storagePreservedSecretKeys() []string { - return []string{"password", "secret_key", "token", "cookie", "access_key"} -} - -func isBlankStorageSecret(value any) bool { - text := strings.TrimSpace(strr(value)) - return text == "" || text == "********" -} - -func storageSecretReplacedByAlternative(typ, key string, cfg, existing map[string]any) bool { - switch typ { - case cloud.TypeOpenList: - switch key { - case "token": - return strings.TrimSpace(strr(cfg["username"])) != "" && strings.TrimSpace(strr(cfg["password"])) != "" - case "password": - if strings.TrimSpace(strr(cfg["token"])) != "" { - return true - } - return storagePlainFieldChanged("username", cfg, existing) - } - case "webdav", cloud.TypeCloudDrive2: - if key == "password" { - if strings.TrimSpace(strr(cfg["token"])) != "" { - return true - } - return storagePlainFieldChanged("username", cfg, existing) - } - case "s3": - if key == "secret_key" { - return storagePlainFieldChanged("access_key", cfg, existing) - } - } - return false -} - -func storagePlainFieldChanged(key string, cfg, existing map[string]any) bool { - incoming := strings.TrimSpace(strr(cfg[key])) - if incoming == "" { - return false - } - current := strings.TrimSpace(strr(existing[key])) - return current != "" && incoming != current -} - // Logout clears saved cloud login credentials, disables the storage backend, // and removes virtual cloud libraries/media for that provider. It intentionally // keeps non-secret connection hints such as server / WebDAV URL / timeout so diff --git a/internal/service/storage_config_secrets.go b/internal/service/storage_config_secrets.go new file mode 100644 index 0000000..d327fa9 --- /dev/null +++ b/internal/service/storage_config_secrets.go @@ -0,0 +1,88 @@ +// Package service — storage configuration secret preservation helpers. +package service + +import ( + "context" + "strings" + + "github.com/ShukeBta/MediaStationGo/internal/service/cloud" +) + +func shouldPreserveStorageSecretsOnSave(enabled *bool) bool { + return enabled == nil || *enabled +} + +func cloneStorageConfigMap(cfg map[string]any) map[string]any { + out := make(map[string]any, len(cfg)) + for k, v := range cfg { + out[k] = v + } + return out +} + +func (s *StorageConfigService) mergeExistingStorageSecrets(ctx context.Context, typ string, cfg map[string]any) (map[string]any, error) { + view, err := s.Get(ctx, typ) + if err != nil || view == nil { + return cfg, err + } + for _, key := range storagePreservedSecretKeys() { + existing := strings.TrimSpace(strr(view.Config[key])) + if existing == "" { + continue + } + incoming, hasIncoming := cfg[key] + if hasIncoming && !isBlankStorageSecret(incoming) { + continue + } + if storageSecretReplacedByAlternative(typ, key, cfg, view.Config) { + continue + } + cfg[key] = existing + } + return cfg, nil +} + +func storagePreservedSecretKeys() []string { + return []string{"password", "secret_key", "token", "cookie", "access_key"} +} + +func isBlankStorageSecret(value any) bool { + text := strings.TrimSpace(strr(value)) + return text == "" || text == "********" +} + +func storageSecretReplacedByAlternative(typ, key string, cfg, existing map[string]any) bool { + switch typ { + case cloud.TypeOpenList: + switch key { + case "token": + return strings.TrimSpace(strr(cfg["username"])) != "" && strings.TrimSpace(strr(cfg["password"])) != "" + case "password": + if strings.TrimSpace(strr(cfg["token"])) != "" { + return true + } + return storagePlainFieldChanged("username", cfg, existing) + } + case "webdav", cloud.TypeCloudDrive2: + if key == "password" { + if strings.TrimSpace(strr(cfg["token"])) != "" { + return true + } + return storagePlainFieldChanged("username", cfg, existing) + } + case "s3": + if key == "secret_key" { + return storagePlainFieldChanged("access_key", cfg, existing) + } + } + return false +} + +func storagePlainFieldChanged(key string, cfg, existing map[string]any) bool { + incoming := strings.TrimSpace(strr(cfg[key])) + if incoming == "" { + return false + } + current := strings.TrimSpace(strr(existing[key])) + return current != "" && incoming != current +}