mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-07 13:28:39 +08:00
fix: keep passkey switch coupled to WebAuthn config and fix CI issues
- parseSettings now reports passkey_enabled=false whenever the WebAuthn deployment config is absent: a stale "true" row left behind after the config is removed previously made the admin update gate reject every settings save while the UI toggle was disabled, leaving no recovery path from the admin panel. Added a regression test. - update the admin settings API contract goldens with the new passkey_enabled/passkey_configured/passkey_rp_id/passkey_rp_origins fields. - errcheck: check rows.Close in passkey repository (repo convention). - staticcheck QF1001: apply De Morgan's law in WebAuthn origin scheme validation.
This commit is contained in:
@@ -2634,7 +2634,7 @@ func (c *Config) Validate() error {
|
||||
u.Host = strings.ToLower(u.Host)
|
||||
host := strings.ToLower(u.Hostname())
|
||||
localDevelopment := host == "localhost" || host == "127.0.0.1" || host == "::1"
|
||||
if u.Scheme != "https" && !(u.Scheme == "http" && localDevelopment) {
|
||||
if u.Scheme != "https" && (u.Scheme != "http" || !localDevelopment) {
|
||||
return fmt.Errorf("webauthn.rp_origins entry %q must use HTTPS (HTTP is allowed only for localhost)", origin)
|
||||
}
|
||||
if host != c.WebAuthn.RPID && !strings.HasSuffix(host, "."+c.WebAuthn.RPID) {
|
||||
|
||||
@@ -92,7 +92,7 @@ func (r *passkeyRepository) ListByUserID(
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list passkey credentials: %w", err)
|
||||
}
|
||||
defer rows.Close()
|
||||
defer func() { _ = rows.Close() }()
|
||||
|
||||
records := make([]service.PasskeyCredentialRecord, 0)
|
||||
for rows.Next() {
|
||||
|
||||
@@ -711,6 +711,10 @@ func TestAPIContracts(t *testing.T) {
|
||||
"frontend_url": "",
|
||||
"totp_enabled": false,
|
||||
"totp_encryption_key_configured": false,
|
||||
"passkey_enabled": false,
|
||||
"passkey_configured": false,
|
||||
"passkey_rp_id": "",
|
||||
"passkey_rp_origins": [],
|
||||
"session_binding_enabled": false,
|
||||
"step_up_enabled": false,
|
||||
"audit_log_retention_days": 180,
|
||||
@@ -1028,6 +1032,10 @@ func TestAPIContracts(t *testing.T) {
|
||||
"invitation_code_enabled": false,
|
||||
"totp_enabled": false,
|
||||
"totp_encryption_key_configured": false,
|
||||
"passkey_enabled": false,
|
||||
"passkey_configured": false,
|
||||
"passkey_rp_id": "",
|
||||
"passkey_rp_origins": [],
|
||||
"session_binding_enabled": false,
|
||||
"step_up_enabled": false,
|
||||
"audit_log_retention_days": 180,
|
||||
|
||||
@@ -182,7 +182,7 @@ func (s *SettingService) PasskeyEnabled(ctx context.Context) (bool, error) {
|
||||
}
|
||||
value, err := s.settingRepo.GetValue(ctx, SettingKeyPasskeyEnabled)
|
||||
if errors.Is(err, ErrSettingNotFound) {
|
||||
return true, nil // preserve enabled deployments when upgrading from config-only releases
|
||||
return true, nil // configured deployments default to enabled until the admin persists the switch
|
||||
}
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("read passkey setting: %w", err)
|
||||
@@ -206,10 +206,16 @@ func (s *SettingService) passkeyConfigured() bool {
|
||||
return s != nil && s.cfg != nil && s.cfg.WebAuthn.Enabled
|
||||
}
|
||||
|
||||
// passkeySettingEnabled must stay ANDed with passkeyConfigured: a stale
|
||||
// "true" row after the WebAuthn config is removed would otherwise make the
|
||||
// admin update gate reject every settings save while the UI toggle is locked.
|
||||
func (s *SettingService) passkeySettingEnabled(settings map[string]string) bool {
|
||||
if !s.passkeyConfigured() {
|
||||
return false
|
||||
}
|
||||
value, ok := settings[SettingKeyPasskeyEnabled]
|
||||
if !ok {
|
||||
return s.passkeyConfigured()
|
||||
return true
|
||||
}
|
||||
return value == "true"
|
||||
}
|
||||
|
||||
@@ -879,3 +879,17 @@ func TestSettingService_PasskeySwitchPersistsAndDefaultsToConfigured(t *testing.
|
||||
require.NoError(t, err)
|
||||
require.False(t, publicSettings.PasskeyEnabled)
|
||||
}
|
||||
|
||||
// 移除 WebAuthn 配置后,残留的 passkey_enabled="true" 不得再让 GetAllSettings
|
||||
// 报告开关开启:admin 更新门控以此为准,一旦误报为 true 会拒绝所有设置保存,
|
||||
// 而此时前端开关处于禁用态,管理员无法在 UI 里自救。
|
||||
func TestSettingService_StalePasskeyTrueWithoutConfigReportsDisabled(t *testing.T) {
|
||||
repo := &settingGetAllRepoStub{values: map[string]string{
|
||||
SettingKeyPasskeyEnabled: "true",
|
||||
}}
|
||||
service := NewSettingService(repo, &config.Config{})
|
||||
|
||||
settings, err := service.GetAllSettings(context.Background())
|
||||
require.NoError(t, err)
|
||||
require.False(t, settings.PasskeyEnabled)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user