feat: 持久化客户端 IP 请求头设置
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
1 parent
8b8b6b3132
commit
f72958d530
5 files changed
+242
-34
No files matched your search
@@ -43,6 +43,14 @@ func (s *SettingService) InitializeDefaultSettings(ctx context.Context) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
forwardedClientIPHeaders := []string{}
|
||||
if s != nil && s.cfg != nil {
|
||||
forwardedClientIPHeaders = s.cfg.ForwardedClientIPSettings().Headers
|
||||
}
|
||||
forwardedClientIPHeadersJSON, err := json.Marshal(forwardedClientIPHeaders)
|
||||
if err != nil {
|
||||
return fmt.Errorf("marshal default forwarded client IP headers: %w", err)
|
||||
}
|
||||
|
||||
// 初始化默认设置
|
||||
defaults := map[string]string{
|
||||
@@ -55,6 +63,7 @@ func (s *SettingService) InitializeDefaultSettings(ctx context.Context) error {
|
||||
SettingKeyLoginAgreementUpdatedAt: defaultLoginAgreementDate,
|
||||
SettingKeyLoginAgreementDocuments: loginAgreementDocumentsJSON,
|
||||
SettingKeyAPIKeyACLTrustForwardedIP: "true",
|
||||
SettingKeyForwardedClientIPHeaders: string(forwardedClientIPHeadersJSON),
|
||||
settingKeyForwardedClientIPModeV2: "true",
|
||||
SettingKeySiteName: "Sub2API",
|
||||
SettingKeySiteLogo: "",
|
||||
@@ -238,6 +247,21 @@ func (s *SettingService) InitializeDefaultSettings(ctx context.Context) error {
|
||||
return s.settingRepo.SetMultiple(ctx, defaults)
|
||||
}
|
||||
|
||||
func parseForwardedClientIPHeadersSetting(value string) ([]string, error) {
|
||||
var headers []string
|
||||
if err := json.Unmarshal([]byte(value), &headers); err != nil {
|
||||
return nil, fmt.Errorf("parse forwarded_client_ip_headers: %w", err)
|
||||
}
|
||||
if headers == nil {
|
||||
return nil, fmt.Errorf("parse forwarded_client_ip_headers: value must be a JSON array")
|
||||
}
|
||||
normalized, err := config.NormalizeForwardedClientIPHeaders(headers)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse forwarded_client_ip_headers: %w", err)
|
||||
}
|
||||
return normalized, nil
|
||||
}
|
||||
|
||||
// parseSettings 解析设置到结构体
|
||||
func (s *SettingService) parseSettings(settings map[string]string) *SystemSettings {
|
||||
emailVerifyEnabled := settings[SettingKeyEmailVerifyEnabled] == "true"
|
||||
@@ -247,10 +271,24 @@ func (s *SettingService) parseSettings(settings map[string]string) *SystemSettin
|
||||
loginAgreementUpdatedAt = defaultLoginAgreementDate
|
||||
}
|
||||
apiKeyACLTrustForwardedIP := false
|
||||
forwardedClientIPHeaders := []string{}
|
||||
if s != nil && s.cfg != nil {
|
||||
runtimeSettings := s.cfg.ForwardedClientIPSettings()
|
||||
apiKeyACLTrustForwardedIP = runtimeSettings.TrustForwardedIP
|
||||
forwardedClientIPHeaders = runtimeSettings.Headers
|
||||
}
|
||||
if value, ok := settings[SettingKeyAPIKeyACLTrustForwardedIP]; ok {
|
||||
apiKeyACLTrustForwardedIP = value == "true"
|
||||
} else if s != nil && s.cfg != nil {
|
||||
apiKeyACLTrustForwardedIP = s.cfg.ForwardedClientIPTrustEnabled()
|
||||
}
|
||||
if value, ok := settings[SettingKeyForwardedClientIPHeaders]; ok {
|
||||
parsed, err := parseForwardedClientIPHeadersSetting(value)
|
||||
if err != nil {
|
||||
slog.Error("invalid persisted forwarded client IP headers; forwarded trust disabled", "error", err)
|
||||
apiKeyACLTrustForwardedIP = false
|
||||
forwardedClientIPHeaders = []string{}
|
||||
} else {
|
||||
forwardedClientIPHeaders = parsed
|
||||
}
|
||||
}
|
||||
result := &SystemSettings{
|
||||
RegistrationEnabled: settings[SettingKeyRegistrationEnabled] == "true",
|
||||
@@ -278,6 +316,7 @@ func (s *SettingService) parseSettings(settings map[string]string) *SystemSettin
|
||||
TurnstileSiteKey: settings[SettingKeyTurnstileSiteKey],
|
||||
TurnstileSecretKeyConfigured: settings[SettingKeyTurnstileSecretKey] != "",
|
||||
APIKeyACLTrustForwardedIP: apiKeyACLTrustForwardedIP,
|
||||
ForwardedClientIPHeaders: forwardedClientIPHeaders,
|
||||
SiteName: s.getStringOrDefault(settings, SettingKeySiteName, "Sub2API"),
|
||||
SiteLogo: settings[SettingKeySiteLogo],
|
||||
SiteSubtitle: s.getStringOrDefault(settings, SettingKeySiteSubtitle, "Subscription to API Conversion Platform"),
|
||||
|
||||
@@ -2,6 +2,8 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync/atomic"
|
||||
|
||||
@@ -215,42 +217,66 @@ func (s *SettingService) SetProxyRepository(repo ProxyRepository) {
|
||||
s.proxyRepo = repo
|
||||
}
|
||||
|
||||
func (s *SettingService) LoadAPIKeyACLTrustForwardedIPSetting(ctx context.Context) error {
|
||||
func (s *SettingService) LoadForwardedClientIPSettings(ctx context.Context) error {
|
||||
if s == nil || s.cfg == nil || s.settingRepo == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
values, err := s.settingRepo.GetMultiple(ctx, []string{
|
||||
SettingKeyAPIKeyACLTrustForwardedIP,
|
||||
SettingKeyForwardedClientIPHeaders,
|
||||
settingKeyForwardedClientIPModeV2,
|
||||
})
|
||||
if err != nil {
|
||||
s.cfg.SetTrustForwardedIPForAPIKeyACL(false)
|
||||
s.cfg.SetForwardedClientIPSettings(false, nil)
|
||||
return fmt.Errorf("get forwarded client ip settings: %w", err)
|
||||
}
|
||||
|
||||
enabled := s.cfg.Security.TrustForwardedIPForAPIKeyACL
|
||||
headers := s.cfg.ForwardedClientIPSettings().Headers
|
||||
storedValue, hasStoredValue := values[SettingKeyAPIKeyACLTrustForwardedIP]
|
||||
if hasStoredValue {
|
||||
enabled = storedValue == "true"
|
||||
}
|
||||
|
||||
if values[settingKeyForwardedClientIPModeV2] != "true" {
|
||||
updates := map[string]string{settingKeyForwardedClientIPModeV2: "true"}
|
||||
// Before this migration, new installations persisted false by default.
|
||||
// Restore compatibility only when no trusted-proxy policy was configured.
|
||||
if hasStoredValue && !enabled && !s.cfg.Server.TrustedProxiesConfigured {
|
||||
enabled = true
|
||||
updates[SettingKeyAPIKeyACLTrustForwardedIP] = "true"
|
||||
}
|
||||
if err := s.settingRepo.SetMultiple(ctx, updates); err != nil {
|
||||
s.cfg.SetTrustForwardedIPForAPIKeyACL(enabled)
|
||||
return fmt.Errorf("migrate forwarded client ip setting: %w", err)
|
||||
var headersErr error
|
||||
if storedHeaders, ok := values[SettingKeyForwardedClientIPHeaders]; ok {
|
||||
headers, headersErr = parseForwardedClientIPHeadersSetting(storedHeaders)
|
||||
if headersErr != nil {
|
||||
enabled = false
|
||||
headers = []string{}
|
||||
headersErr = fmt.Errorf("load forwarded client ip headers: %w", headersErr)
|
||||
}
|
||||
}
|
||||
|
||||
s.cfg.SetTrustForwardedIPForAPIKeyACL(enabled)
|
||||
return nil
|
||||
updates := make(map[string]string)
|
||||
if _, hasStoredHeaders := values[SettingKeyForwardedClientIPHeaders]; !hasStoredHeaders {
|
||||
headersJSON, marshalErr := json.Marshal(headers)
|
||||
if marshalErr != nil {
|
||||
headers = []string{}
|
||||
headersErr = errors.Join(headersErr, fmt.Errorf("marshal forwarded client ip headers: %w", marshalErr))
|
||||
headersJSON = []byte("[]")
|
||||
}
|
||||
updates[SettingKeyForwardedClientIPHeaders] = string(headersJSON)
|
||||
}
|
||||
if values[settingKeyForwardedClientIPModeV2] != "true" {
|
||||
updates[settingKeyForwardedClientIPModeV2] = "true"
|
||||
// Before this migration, new installations persisted false by default.
|
||||
// Restore compatibility only when no trusted-proxy policy was configured.
|
||||
if headersErr == nil && hasStoredValue && !enabled && !s.cfg.Server.TrustedProxiesConfigured {
|
||||
enabled = true
|
||||
updates[SettingKeyAPIKeyACLTrustForwardedIP] = "true"
|
||||
}
|
||||
}
|
||||
if len(updates) > 0 {
|
||||
if err := s.settingRepo.SetMultiple(ctx, updates); err != nil {
|
||||
s.cfg.SetForwardedClientIPSettings(enabled, headers)
|
||||
return errors.Join(headersErr, fmt.Errorf("migrate forwarded client ip setting: %w", err))
|
||||
}
|
||||
}
|
||||
|
||||
s.cfg.SetForwardedClientIPSettings(enabled, headers)
|
||||
return headersErr
|
||||
}
|
||||
|
||||
// GetAllSettings 获取所有系统设置
|
||||
|
||||
@@ -17,7 +17,8 @@ import (
|
||||
)
|
||||
|
||||
type settingUpdateRepoStub struct {
|
||||
updates map[string]string
|
||||
updates map[string]string
|
||||
setMultipleErr error
|
||||
}
|
||||
|
||||
func (s *settingUpdateRepoStub) Get(ctx context.Context, key string) (*Setting, error) {
|
||||
@@ -41,7 +42,7 @@ func (s *settingUpdateRepoStub) SetMultiple(ctx context.Context, settings map[st
|
||||
for k, v := range settings {
|
||||
s.updates[k] = v
|
||||
}
|
||||
return nil
|
||||
return s.setMultipleErr
|
||||
}
|
||||
|
||||
func (s *settingUpdateRepoStub) GetAll(ctx context.Context) (map[string]string, error) {
|
||||
@@ -99,8 +100,12 @@ func (s *forwardedIPMigrationRepoStub) Get(context.Context, string) (*Setting, e
|
||||
panic("unexpected Get call")
|
||||
}
|
||||
|
||||
func (s *forwardedIPMigrationRepoStub) GetValue(context.Context, string) (string, error) {
|
||||
panic("unexpected GetValue call")
|
||||
func (s *forwardedIPMigrationRepoStub) GetValue(_ context.Context, key string) (string, error) {
|
||||
value, ok := s.values[key]
|
||||
if !ok {
|
||||
return "", ErrSettingNotFound
|
||||
}
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func (s *forwardedIPMigrationRepoStub) Set(context.Context, string, string) error {
|
||||
@@ -548,6 +553,16 @@ func TestSettingService_UpdateSettings_AntigravityUserAgentVersion(t *testing.T)
|
||||
require.Equal(t, "1.23.2", repo.updates[SettingKeyAntigravityUserAgentVersion])
|
||||
}
|
||||
|
||||
func TestSettingService_InitializeDefaultSettingsPersistsConfiguredForwardedClientIPHeaders(t *testing.T) {
|
||||
repo := &forwardedIPMigrationRepoStub{values: map[string]string{}}
|
||||
cfg := &config.Config{}
|
||||
cfg.SetForwardedClientIPSettings(true, []string{"X-Cdn-Ip", "True-Client-Ip"})
|
||||
svc := NewSettingService(repo, cfg)
|
||||
|
||||
require.NoError(t, svc.InitializeDefaultSettings(context.Background()))
|
||||
require.JSONEq(t, `["X-Cdn-Ip","True-Client-Ip"]`, repo.values[SettingKeyForwardedClientIPHeaders])
|
||||
}
|
||||
|
||||
func TestSettingService_UpdateSettings_APIKeyACLTrustForwardedIPRefreshesConfig(t *testing.T) {
|
||||
repo := &settingUpdateRepoStub{}
|
||||
cfg := &config.Config{}
|
||||
@@ -555,11 +570,51 @@ func TestSettingService_UpdateSettings_APIKeyACLTrustForwardedIPRefreshesConfig(
|
||||
|
||||
err := svc.UpdateSettings(context.Background(), &SystemSettings{
|
||||
APIKeyACLTrustForwardedIP: true,
|
||||
ForwardedClientIPHeaders: []string{" x-cdn-ip ", "X-CDN-IP", "true-client-ip"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, "true", repo.updates[SettingKeyAPIKeyACLTrustForwardedIP])
|
||||
require.True(t, cfg.Security.TrustForwardedIPForAPIKeyACL)
|
||||
require.True(t, cfg.TrustForwardedIPForAPIKeyACL())
|
||||
require.JSONEq(t, `["X-Cdn-Ip","True-Client-Ip"]`, repo.updates[SettingKeyForwardedClientIPHeaders])
|
||||
runtimeSettings := cfg.ForwardedClientIPSettings()
|
||||
require.True(t, runtimeSettings.TrustForwardedIP)
|
||||
require.Equal(t, []string{"X-Cdn-Ip", "True-Client-Ip"}, runtimeSettings.Headers)
|
||||
|
||||
runtimeSettings.Headers[0] = "X-Mutated"
|
||||
require.Equal(t, []string{"X-Cdn-Ip", "True-Client-Ip"}, cfg.ForwardedClientIPSettings().Headers)
|
||||
}
|
||||
|
||||
func TestSettingService_UpdateSettings_RejectsInvalidForwardedClientIPHeadersWithoutRefreshing(t *testing.T) {
|
||||
repo := &settingUpdateRepoStub{}
|
||||
cfg := &config.Config{}
|
||||
cfg.SetForwardedClientIPSettings(true, []string{"X-Existing-IP"})
|
||||
svc := NewSettingService(repo, cfg)
|
||||
|
||||
err := svc.UpdateSettings(context.Background(), &SystemSettings{
|
||||
ForwardedClientIPHeaders: []string{"X Invalid"},
|
||||
})
|
||||
|
||||
require.Error(t, err)
|
||||
require.Nil(t, repo.updates)
|
||||
runtimeSettings := cfg.ForwardedClientIPSettings()
|
||||
require.True(t, runtimeSettings.TrustForwardedIP)
|
||||
require.Equal(t, []string{"X-Existing-IP"}, runtimeSettings.Headers)
|
||||
}
|
||||
|
||||
func TestSettingService_UpdateSettings_WriteFailureDoesNotRefreshForwardedIPRuntime(t *testing.T) {
|
||||
repo := &settingUpdateRepoStub{setMultipleErr: errors.New("database unavailable")}
|
||||
cfg := &config.Config{}
|
||||
cfg.SetForwardedClientIPSettings(false, []string{"X-Existing-IP"})
|
||||
svc := NewSettingService(repo, cfg)
|
||||
|
||||
err := svc.UpdateSettings(context.Background(), &SystemSettings{
|
||||
APIKeyACLTrustForwardedIP: true,
|
||||
ForwardedClientIPHeaders: []string{"X-New-IP"},
|
||||
})
|
||||
|
||||
require.ErrorContains(t, err, "database unavailable")
|
||||
runtimeSettings := cfg.ForwardedClientIPSettings()
|
||||
require.False(t, runtimeSettings.TrustForwardedIP)
|
||||
require.Equal(t, []string{"X-Existing-IP"}, runtimeSettings.Headers)
|
||||
}
|
||||
|
||||
func TestSettingService_ParseSettings_APIKeyACLTrustForwardedIPFallsBackToConfigWhenMissing(t *testing.T) {
|
||||
@@ -582,7 +637,34 @@ func TestSettingService_ParseSettings_APIKeyACLTrustForwardedIPUsesStoredValue(t
|
||||
require.False(t, got.APIKeyACLTrustForwardedIP)
|
||||
}
|
||||
|
||||
func TestSettingService_LoadAPIKeyACLTrustForwardedIPSettingMigration(t *testing.T) {
|
||||
func TestSettingService_ParseSettings_ForwardedClientIPHeaders(t *testing.T) {
|
||||
cfg := &config.Config{}
|
||||
cfg.SetForwardedClientIPSettings(true, []string{"X-Config-IP"})
|
||||
svc := NewSettingService(&settingUpdateRepoStub{}, cfg)
|
||||
|
||||
t.Run("stored value is normalized", func(t *testing.T) {
|
||||
got := svc.parseSettings(map[string]string{
|
||||
SettingKeyForwardedClientIPHeaders: `[" x-cdn-ip ","X-CDN-IP","true-client-ip"]`,
|
||||
})
|
||||
require.Equal(t, []string{"X-Cdn-Ip", "True-Client-Ip"}, got.ForwardedClientIPHeaders)
|
||||
})
|
||||
|
||||
t.Run("missing value falls back to config", func(t *testing.T) {
|
||||
got := svc.parseSettings(map[string]string{})
|
||||
require.Equal(t, []string{"X-Config-IP"}, got.ForwardedClientIPHeaders)
|
||||
})
|
||||
|
||||
t.Run("malformed value disables forwarded trust", func(t *testing.T) {
|
||||
got := svc.parseSettings(map[string]string{
|
||||
SettingKeyAPIKeyACLTrustForwardedIP: "true",
|
||||
SettingKeyForwardedClientIPHeaders: `{"not":"an array"}`,
|
||||
})
|
||||
require.False(t, got.APIKeyACLTrustForwardedIP)
|
||||
require.Empty(t, got.ForwardedClientIPHeaders)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSettingService_LoadForwardedClientIPSettingsMigration(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
values map[string]string
|
||||
@@ -630,19 +712,67 @@ func TestSettingService_LoadAPIKeyACLTrustForwardedIPSettingMigration(t *testing
|
||||
cfg.Security.TrustForwardedIPForAPIKeyACL = test.configDefault
|
||||
svc := NewSettingService(repo, cfg)
|
||||
|
||||
require.NoError(t, svc.LoadAPIKeyACLTrustForwardedIPSetting(context.Background()))
|
||||
require.NoError(t, svc.LoadForwardedClientIPSettings(context.Background()))
|
||||
require.Equal(t, test.wantEnabled, cfg.TrustForwardedIPForAPIKeyACL())
|
||||
require.Equal(t, test.wantForwardedIPUpdate, repo.updates[SettingKeyAPIKeyACLTrustForwardedIP])
|
||||
require.JSONEq(t, `[]`, repo.updates[SettingKeyForwardedClientIPHeaders])
|
||||
if test.wantMigrationMarkerSet {
|
||||
require.Equal(t, "true", repo.updates[settingKeyForwardedClientIPModeV2])
|
||||
} else {
|
||||
require.Nil(t, repo.updates)
|
||||
require.NotContains(t, repo.updates, settingKeyForwardedClientIPModeV2)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestSettingService_LoadAPIKeyACLTrustForwardedIPSettingReadFailureFailsClosed(t *testing.T) {
|
||||
func TestSettingService_LoadForwardedClientIPSettingsLoadsHeaders(t *testing.T) {
|
||||
repo := &forwardedIPMigrationRepoStub{values: map[string]string{
|
||||
SettingKeyAPIKeyACLTrustForwardedIP: "true",
|
||||
SettingKeyForwardedClientIPHeaders: `[" x-cdn-ip ","true-client-ip"]`,
|
||||
settingKeyForwardedClientIPModeV2: "true",
|
||||
}}
|
||||
cfg := &config.Config{}
|
||||
svc := NewSettingService(repo, cfg)
|
||||
|
||||
require.NoError(t, svc.LoadForwardedClientIPSettings(context.Background()))
|
||||
runtimeSettings := cfg.ForwardedClientIPSettings()
|
||||
require.True(t, runtimeSettings.TrustForwardedIP)
|
||||
require.Equal(t, []string{"X-Cdn-Ip", "True-Client-Ip"}, runtimeSettings.Headers)
|
||||
require.Nil(t, repo.updates)
|
||||
}
|
||||
|
||||
func TestSettingService_LoadForwardedClientIPSettingsMalformedHeadersDisablesCustomTrust(t *testing.T) {
|
||||
repo := &forwardedIPMigrationRepoStub{values: map[string]string{
|
||||
SettingKeyAPIKeyACLTrustForwardedIP: "true",
|
||||
SettingKeyForwardedClientIPHeaders: `["X Invalid"]`,
|
||||
}}
|
||||
cfg := &config.Config{}
|
||||
svc := NewSettingService(repo, cfg)
|
||||
|
||||
err := svc.LoadForwardedClientIPSettings(context.Background())
|
||||
|
||||
require.ErrorContains(t, err, "load forwarded client ip headers")
|
||||
runtimeSettings := cfg.ForwardedClientIPSettings()
|
||||
require.False(t, runtimeSettings.TrustForwardedIP)
|
||||
require.Empty(t, runtimeSettings.Headers)
|
||||
require.Equal(t, "true", repo.updates[settingKeyForwardedClientIPModeV2])
|
||||
require.NotContains(t, repo.updates, SettingKeyAPIKeyACLTrustForwardedIP)
|
||||
}
|
||||
|
||||
func TestSettingService_LoadForwardedClientIPSettingsBackfillsConfigHeaders(t *testing.T) {
|
||||
repo := &forwardedIPMigrationRepoStub{values: map[string]string{
|
||||
settingKeyForwardedClientIPModeV2: "true",
|
||||
}}
|
||||
cfg := &config.Config{}
|
||||
cfg.SetForwardedClientIPSettings(false, []string{"X-Config-IP"})
|
||||
svc := NewSettingService(repo, cfg)
|
||||
|
||||
require.NoError(t, svc.LoadForwardedClientIPSettings(context.Background()))
|
||||
require.JSONEq(t, `["X-Config-IP"]`, repo.updates[SettingKeyForwardedClientIPHeaders])
|
||||
require.Equal(t, []string{"X-Config-IP"}, cfg.ForwardedClientIPSettings().Headers)
|
||||
}
|
||||
|
||||
func TestSettingService_LoadForwardedClientIPSettingsReadFailureFailsClosed(t *testing.T) {
|
||||
repo := &forwardedIPMigrationRepoStub{
|
||||
getMultipleErr: errors.New("database unavailable"),
|
||||
}
|
||||
@@ -650,13 +780,15 @@ func TestSettingService_LoadAPIKeyACLTrustForwardedIPSettingReadFailureFailsClos
|
||||
cfg.SetTrustForwardedIPForAPIKeyACL(true)
|
||||
svc := NewSettingService(repo, cfg)
|
||||
|
||||
err := svc.LoadAPIKeyACLTrustForwardedIPSetting(context.Background())
|
||||
err := svc.LoadForwardedClientIPSettings(context.Background())
|
||||
|
||||
require.ErrorContains(t, err, "get forwarded client ip settings")
|
||||
require.False(t, cfg.TrustForwardedIPForAPIKeyACL())
|
||||
runtimeSettings := cfg.ForwardedClientIPSettings()
|
||||
require.False(t, runtimeSettings.TrustForwardedIP)
|
||||
require.Empty(t, runtimeSettings.Headers)
|
||||
}
|
||||
|
||||
func TestSettingService_LoadAPIKeyACLTrustForwardedIPSettingWriteFailureUsesComputedMode(t *testing.T) {
|
||||
func TestSettingService_LoadForwardedClientIPSettingsWriteFailureUsesComputedMode(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
trustedProxiesSet bool
|
||||
@@ -675,7 +807,7 @@ func TestSettingService_LoadAPIKeyACLTrustForwardedIPSettingWriteFailureUsesComp
|
||||
cfg := &config.Config{Server: config.ServerConfig{TrustedProxiesConfigured: test.trustedProxiesSet}}
|
||||
svc := NewSettingService(repo, cfg)
|
||||
|
||||
err := svc.LoadAPIKeyACLTrustForwardedIPSetting(context.Background())
|
||||
err := svc.LoadForwardedClientIPSettings(context.Background())
|
||||
|
||||
require.ErrorContains(t, err, "migrate forwarded client ip setting")
|
||||
require.Equal(t, test.wantEnabled, cfg.TrustForwardedIPForAPIKeyACL())
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Wei-Shaw/sub2api/internal/config"
|
||||
"github.com/Wei-Shaw/sub2api/internal/pkg/antigravity"
|
||||
infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors"
|
||||
)
|
||||
@@ -62,6 +63,11 @@ func (s *SettingService) buildSystemSettingsUpdates(ctx context.Context, setting
|
||||
normalizedWhitelist = []string{}
|
||||
}
|
||||
settings.RegistrationEmailSuffixWhitelist = normalizedWhitelist
|
||||
normalizedForwardedClientIPHeaders, err := config.NormalizeForwardedClientIPHeaders(settings.ForwardedClientIPHeaders)
|
||||
if err != nil {
|
||||
return nil, infraerrors.BadRequest("INVALID_FORWARDED_CLIENT_IP_HEADERS", err.Error())
|
||||
}
|
||||
settings.ForwardedClientIPHeaders = normalizedForwardedClientIPHeaders
|
||||
alipaySource, err := normalizeVisibleMethodSettingSource("alipay", settings.PaymentVisibleMethodAlipaySource, settings.PaymentVisibleMethodAlipayEnabled)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -156,6 +162,11 @@ func (s *SettingService) buildSystemSettingsUpdates(ctx context.Context, setting
|
||||
updates[SettingKeyTurnstileSecretKey] = settings.TurnstileSecretKey
|
||||
}
|
||||
updates[SettingKeyAPIKeyACLTrustForwardedIP] = strconv.FormatBool(settings.APIKeyACLTrustForwardedIP)
|
||||
forwardedClientIPHeadersJSON, err := json.Marshal(settings.ForwardedClientIPHeaders)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("marshal forwarded client IP headers: %w", err)
|
||||
}
|
||||
updates[SettingKeyForwardedClientIPHeaders] = string(forwardedClientIPHeadersJSON)
|
||||
|
||||
// LinuxDo Connect OAuth 登录
|
||||
updates[SettingKeyLinuxDoConnectEnabled] = strconv.FormatBool(settings.LinuxDoConnectEnabled)
|
||||
@@ -579,7 +590,7 @@ func (s *SettingService) refreshCachedSettings(settings *SystemSettings) {
|
||||
})
|
||||
}
|
||||
if s.cfg != nil {
|
||||
s.cfg.SetTrustForwardedIPForAPIKeyACL(settings.APIKeyACLTrustForwardedIP)
|
||||
s.cfg.SetForwardedClientIPSettings(settings.APIKeyACLTrustForwardedIP, settings.ForwardedClientIPHeaders)
|
||||
}
|
||||
// codex_cli_only 加固策略缓存:设置更新后强制下次重载(涉及 4 个键 + JSON 解析,直接置过期)。
|
||||
s.codexRestrictionPolicySF.Forget("codex_restriction_policy")
|
||||
|
||||
@@ -613,8 +613,8 @@ func ProvideSettingService(settingRepo SettingRepository, groupRepo GroupReposit
|
||||
svc := NewSettingService(settingRepo, cfg)
|
||||
svc.SetDefaultSubscriptionGroupReader(groupRepo)
|
||||
svc.SetProxyRepository(proxyRepo)
|
||||
if err := svc.LoadAPIKeyACLTrustForwardedIPSetting(context.Background()); err != nil {
|
||||
logger.LegacyPrintf("service.setting", "Warning: load api key acl forwarded ip setting failed: %v", err)
|
||||
if err := svc.LoadForwardedClientIPSettings(context.Background()); err != nil {
|
||||
logger.LegacyPrintf("service.setting", "Warning: load forwarded client IP settings failed: %v", err)
|
||||
}
|
||||
if err := svc.MigrateOpenAIAllowClaudeCodeCodexPluginSetting(context.Background()); err != nil {
|
||||
logger.LegacyPrintf("service.setting", "Warning: migrate openai allow Claude Code Codex plugin setting failed: %v", err)
|
||||
|
||||
Reference in new issue
Block a user