diff --git a/internal/start/start.go b/internal/start/start.go index 2483b6aed..9096f381d 100644 --- a/internal/start/start.go +++ b/internal/start/start.go @@ -583,44 +583,44 @@ EOF ) } - if utils.Config.Auth.Hook.MFAVerificationAttempt.Enabled { + if hook := utils.Config.Auth.Hook.MFAVerificationAttempt; hook != nil && hook.Enabled { env = append( env, "GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_ENABLED=true", - "GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_URI="+utils.Config.Auth.Hook.MFAVerificationAttempt.URI, - "GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_SECRETS="+utils.Config.Auth.Hook.MFAVerificationAttempt.Secrets, + "GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_URI="+hook.URI, + "GOTRUE_HOOK_MFA_VERIFICATION_ATTEMPT_SECRETS="+hook.Secrets, ) } - if utils.Config.Auth.Hook.PasswordVerificationAttempt.Enabled { + if hook := utils.Config.Auth.Hook.PasswordVerificationAttempt; hook != nil && hook.Enabled { env = append( env, "GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_ENABLED=true", - "GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_URI="+utils.Config.Auth.Hook.PasswordVerificationAttempt.URI, - "GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_SECRETS="+utils.Config.Auth.Hook.PasswordVerificationAttempt.Secrets, + "GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_URI="+hook.URI, + "GOTRUE_HOOK_PASSWORD_VERIFICATION_ATTEMPT_SECRETS="+hook.Secrets, ) } - if utils.Config.Auth.Hook.CustomAccessToken.Enabled { + if hook := utils.Config.Auth.Hook.CustomAccessToken; hook != nil && hook.Enabled { env = append( env, "GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_ENABLED=true", - "GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_URI="+utils.Config.Auth.Hook.CustomAccessToken.URI, - "GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_SECRETS="+utils.Config.Auth.Hook.CustomAccessToken.Secrets, + "GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_URI="+hook.URI, + "GOTRUE_HOOK_CUSTOM_ACCESS_TOKEN_SECRETS="+hook.Secrets, ) } - if utils.Config.Auth.Hook.SendSMS.Enabled { + if hook := utils.Config.Auth.Hook.SendSMS; hook != nil && hook.Enabled { env = append( env, "GOTRUE_HOOK_SEND_SMS_ENABLED=true", - "GOTRUE_HOOK_SEND_SMS_URI="+utils.Config.Auth.Hook.SendSMS.URI, - "GOTRUE_HOOK_SEND_SMS_SECRETS="+utils.Config.Auth.Hook.SendSMS.Secrets, + "GOTRUE_HOOK_SEND_SMS_URI="+hook.URI, + "GOTRUE_HOOK_SEND_SMS_SECRETS="+hook.Secrets, ) } - if utils.Config.Auth.Hook.SendEmail.Enabled { + if hook := utils.Config.Auth.Hook.SendEmail; hook != nil && hook.Enabled { env = append( env, "GOTRUE_HOOK_SEND_EMAIL_ENABLED=true", - "GOTRUE_HOOK_SEND_EMAIL_URI="+utils.Config.Auth.Hook.SendEmail.URI, - "GOTRUE_HOOK_SEND_EMAIL_SECRETS="+utils.Config.Auth.Hook.SendEmail.Secrets, + "GOTRUE_HOOK_SEND_EMAIL_URI="+hook.URI, + "GOTRUE_HOOK_SEND_EMAIL_SECRETS="+hook.Secrets, ) } diff --git a/pkg/config/auth.go b/pkg/config/auth.go index a73a23316..b2e6b0fa6 100644 --- a/pkg/config/auth.go +++ b/pkg/config/auth.go @@ -145,11 +145,11 @@ type ( } hook struct { - MFAVerificationAttempt hookConfig `toml:"mfa_verification_attempt"` - PasswordVerificationAttempt hookConfig `toml:"password_verification_attempt"` - CustomAccessToken hookConfig `toml:"custom_access_token"` - SendSMS hookConfig `toml:"send_sms"` - SendEmail hookConfig `toml:"send_email"` + MFAVerificationAttempt *hookConfig `toml:"mfa_verification_attempt"` + PasswordVerificationAttempt *hookConfig `toml:"password_verification_attempt"` + CustomAccessToken *hookConfig `toml:"custom_access_token"` + SendSMS *hookConfig `toml:"send_sms"` + SendEmail *hookConfig `toml:"send_email"` } factorTypeConfiguration struct { @@ -261,70 +261,88 @@ func (a *auth) FromRemoteAuthConfig(remoteConfig v1API.AuthConfigResponse) { } func (h hook) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { - if body.HookCustomAccessTokenEnabled = &h.CustomAccessToken.Enabled; *body.HookCustomAccessTokenEnabled { - body.HookCustomAccessTokenUri = &h.CustomAccessToken.URI - if len(h.CustomAccessToken.Secrets) > 0 { - body.HookCustomAccessTokenSecrets = &h.CustomAccessToken.Secrets + // When local config is not set, we assume platform defaults should not change + if hook := h.CustomAccessToken; hook != nil { + if body.HookCustomAccessTokenEnabled = &hook.Enabled; hook.Enabled { + body.HookCustomAccessTokenUri = &hook.URI + if len(hook.Secrets) > 0 { + body.HookCustomAccessTokenSecrets = &hook.Secrets + } } } - if body.HookSendEmailEnabled = &h.SendEmail.Enabled; *body.HookSendEmailEnabled { - body.HookSendEmailUri = &h.SendEmail.URI - if len(h.SendEmail.Secrets) > 0 { - body.HookSendEmailSecrets = &h.SendEmail.Secrets + if hook := h.SendEmail; hook != nil { + if body.HookSendEmailEnabled = &hook.Enabled; hook.Enabled { + body.HookSendEmailUri = &hook.URI + if len(hook.Secrets) > 0 { + body.HookSendEmailSecrets = &hook.Secrets + } } } - if body.HookSendSmsEnabled = &h.SendSMS.Enabled; *body.HookSendSmsEnabled { - body.HookSendSmsUri = &h.SendSMS.URI - if len(h.SendSMS.Secrets) > 0 { - body.HookSendSmsSecrets = &h.SendSMS.Secrets + if hook := h.SendSMS; hook != nil { + if body.HookSendSmsEnabled = &hook.Enabled; hook.Enabled { + body.HookSendSmsUri = &hook.URI + if len(hook.Secrets) > 0 { + body.HookSendSmsSecrets = &hook.Secrets + } } } // Enterprise and team only features - if body.HookMfaVerificationAttemptEnabled = &h.MFAVerificationAttempt.Enabled; *body.HookMfaVerificationAttemptEnabled { - body.HookMfaVerificationAttemptUri = &h.MFAVerificationAttempt.URI - if len(h.MFAVerificationAttempt.Secrets) > 0 { - body.HookMfaVerificationAttemptSecrets = &h.MFAVerificationAttempt.Secrets + if hook := h.MFAVerificationAttempt; hook != nil { + if body.HookMfaVerificationAttemptEnabled = &hook.Enabled; hook.Enabled { + body.HookMfaVerificationAttemptUri = &hook.URI + if len(hook.Secrets) > 0 { + body.HookMfaVerificationAttemptSecrets = &hook.Secrets + } } } - if body.HookPasswordVerificationAttemptEnabled = &h.PasswordVerificationAttempt.Enabled; *body.HookPasswordVerificationAttemptEnabled { - body.HookPasswordVerificationAttemptUri = &h.PasswordVerificationAttempt.URI - if len(h.PasswordVerificationAttempt.Secrets) > 0 { - body.HookPasswordVerificationAttemptSecrets = &h.PasswordVerificationAttempt.Secrets + if hook := h.PasswordVerificationAttempt; hook != nil { + if body.HookPasswordVerificationAttemptEnabled = &hook.Enabled; hook.Enabled { + body.HookPasswordVerificationAttemptUri = &hook.URI + if len(hook.Secrets) > 0 { + body.HookPasswordVerificationAttemptSecrets = &hook.Secrets + } } } } func (h *hook) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) { - // Ignore disabled hooks because their envs are not loaded - if h.CustomAccessToken.Enabled { - h.CustomAccessToken.URI = cast.Val(remoteConfig.HookCustomAccessTokenUri, "") - h.CustomAccessToken.Secrets = hashPrefix + cast.Val(remoteConfig.HookCustomAccessTokenSecrets, "") + // When local config is not set, we assume platform defaults should not change + if hook := h.CustomAccessToken; hook != nil { + // Ignore disabled hooks because their envs are not loaded + if hook.Enabled { + hook.URI = cast.Val(remoteConfig.HookCustomAccessTokenUri, "") + hook.Secrets = hashPrefix + cast.Val(remoteConfig.HookCustomAccessTokenSecrets, "") + } + hook.Enabled = cast.Val(remoteConfig.HookCustomAccessTokenEnabled, false) } - h.CustomAccessToken.Enabled = cast.Val(remoteConfig.HookCustomAccessTokenEnabled, false) - - if h.SendEmail.Enabled { - h.SendEmail.URI = cast.Val(remoteConfig.HookSendEmailUri, "") - h.SendEmail.Secrets = hashPrefix + cast.Val(remoteConfig.HookSendEmailSecrets, "") + if hook := h.SendEmail; hook != nil { + if hook.Enabled { + hook.URI = cast.Val(remoteConfig.HookSendEmailUri, "") + hook.Secrets = hashPrefix + cast.Val(remoteConfig.HookSendEmailSecrets, "") + } + hook.Enabled = cast.Val(remoteConfig.HookSendEmailEnabled, false) } - h.SendEmail.Enabled = cast.Val(remoteConfig.HookSendEmailEnabled, false) - - if h.SendSMS.Enabled { - h.SendSMS.URI = cast.Val(remoteConfig.HookSendSmsUri, "") - h.SendSMS.Secrets = hashPrefix + cast.Val(remoteConfig.HookSendSmsSecrets, "") + if hook := h.SendSMS; hook != nil { + if hook.Enabled { + hook.URI = cast.Val(remoteConfig.HookSendSmsUri, "") + hook.Secrets = hashPrefix + cast.Val(remoteConfig.HookSendSmsSecrets, "") + } + hook.Enabled = cast.Val(remoteConfig.HookSendSmsEnabled, false) } - h.SendSMS.Enabled = cast.Val(remoteConfig.HookSendSmsEnabled, false) - // Enterprise and team only features - if h.MFAVerificationAttempt.Enabled { - h.MFAVerificationAttempt.URI = cast.Val(remoteConfig.HookMfaVerificationAttemptUri, "") - h.MFAVerificationAttempt.Secrets = hashPrefix + cast.Val(remoteConfig.HookMfaVerificationAttemptSecrets, "") + if hook := h.MFAVerificationAttempt; hook != nil { + if hook.Enabled { + hook.URI = cast.Val(remoteConfig.HookMfaVerificationAttemptUri, "") + hook.Secrets = hashPrefix + cast.Val(remoteConfig.HookMfaVerificationAttemptSecrets, "") + } + hook.Enabled = cast.Val(remoteConfig.HookMfaVerificationAttemptEnabled, false) } - h.MFAVerificationAttempt.Enabled = cast.Val(remoteConfig.HookMfaVerificationAttemptEnabled, false) - - if h.PasswordVerificationAttempt.Enabled { - h.PasswordVerificationAttempt.URI = cast.Val(remoteConfig.HookPasswordVerificationAttemptUri, "") - h.PasswordVerificationAttempt.Secrets = hashPrefix + cast.Val(remoteConfig.HookPasswordVerificationAttemptSecrets, "") + if hook := h.PasswordVerificationAttempt; hook != nil { + if hook.Enabled { + hook.URI = cast.Val(remoteConfig.HookPasswordVerificationAttemptUri, "") + hook.Secrets = hashPrefix + cast.Val(remoteConfig.HookPasswordVerificationAttemptSecrets, "") + } + hook.Enabled = cast.Val(remoteConfig.HookPasswordVerificationAttemptEnabled, false) } - h.PasswordVerificationAttempt.Enabled = cast.Val(remoteConfig.HookPasswordVerificationAttemptEnabled, false) } func (m mfa) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) { @@ -942,19 +960,19 @@ func (a *auth) HashSecrets(key string) { case a.Sms.Vonage.Enabled: a.Sms.Vonage.ApiSecret = hash(a.Sms.Vonage.ApiSecret) } - if a.Hook.MFAVerificationAttempt.Enabled { + if a.Hook.MFAVerificationAttempt != nil && a.Hook.MFAVerificationAttempt.Enabled { a.Hook.MFAVerificationAttempt.Secrets = hash(a.Hook.MFAVerificationAttempt.Secrets) } - if a.Hook.PasswordVerificationAttempt.Enabled { + if a.Hook.PasswordVerificationAttempt != nil && a.Hook.PasswordVerificationAttempt.Enabled { a.Hook.PasswordVerificationAttempt.Secrets = hash(a.Hook.PasswordVerificationAttempt.Secrets) } - if a.Hook.CustomAccessToken.Enabled { + if a.Hook.CustomAccessToken != nil && a.Hook.CustomAccessToken.Enabled { a.Hook.CustomAccessToken.Secrets = hash(a.Hook.CustomAccessToken.Secrets) } - if a.Hook.SendSMS.Enabled { + if a.Hook.SendSMS != nil && a.Hook.SendSMS.Enabled { a.Hook.SendSMS.Secrets = hash(a.Hook.SendSMS.Secrets) } - if a.Hook.SendEmail.Enabled { + if a.Hook.SendEmail != nil && a.Hook.SendEmail.Enabled { a.Hook.SendEmail.Secrets = hash(a.Hook.SendEmail.Secrets) } for name, provider := range a.External { diff --git a/pkg/config/auth_test.go b/pkg/config/auth_test.go index 884737475..f85b87730 100644 --- a/pkg/config/auth_test.go +++ b/pkg/config/auth_test.go @@ -121,27 +121,27 @@ func TestHookDiff(t *testing.T) { t.Run("local and remote enabled", func(t *testing.T) { c := newWithDefaults() c.Hook = hook{ - CustomAccessToken: hookConfig{ + CustomAccessToken: &hookConfig{ Enabled: true, URI: "http://example.com", Secrets: "test-secret", }, - SendSMS: hookConfig{ + SendSMS: &hookConfig{ Enabled: true, URI: "http://example.com", Secrets: "test-secret", }, - SendEmail: hookConfig{ + SendEmail: &hookConfig{ Enabled: true, URI: "https://example.com", Secrets: "test-secret", }, - MFAVerificationAttempt: hookConfig{ + MFAVerificationAttempt: &hookConfig{ Enabled: true, URI: "https://example.com", Secrets: "test-secret", }, - PasswordVerificationAttempt: hookConfig{ + PasswordVerificationAttempt: &hookConfig{ Enabled: true, URI: "pg-functions://verifyPassword", }, @@ -171,22 +171,22 @@ func TestHookDiff(t *testing.T) { t.Run("local disabled remote enabled", func(t *testing.T) { c := newWithDefaults() c.Hook = hook{ - CustomAccessToken: hookConfig{ + CustomAccessToken: &hookConfig{ Enabled: false, }, - SendSMS: hookConfig{ + SendSMS: &hookConfig{ Enabled: false, URI: "https://example.com", Secrets: "test-secret", }, - SendEmail: hookConfig{ + SendEmail: &hookConfig{ Enabled: false, }, - MFAVerificationAttempt: hookConfig{ + MFAVerificationAttempt: &hookConfig{ Enabled: false, URI: "pg-functions://postgres/public/verifyMFA", }, - PasswordVerificationAttempt: hookConfig{ + PasswordVerificationAttempt: &hookConfig{ Enabled: false, URI: "http://example.com", Secrets: "test-secret", @@ -216,25 +216,25 @@ func TestHookDiff(t *testing.T) { t.Run("local enabled remote disabled", func(t *testing.T) { c := newWithDefaults() c.Hook = hook{ - CustomAccessToken: hookConfig{ + CustomAccessToken: &hookConfig{ Enabled: true, URI: "http://example.com", Secrets: "test-secret", }, - SendSMS: hookConfig{ + SendSMS: &hookConfig{ Enabled: true, URI: "https://example.com", Secrets: "test-secret", }, - SendEmail: hookConfig{ + SendEmail: &hookConfig{ Enabled: true, URI: "pg-functions://postgres/public/sendEmail", }, - MFAVerificationAttempt: hookConfig{ + MFAVerificationAttempt: &hookConfig{ Enabled: true, URI: "pg-functions://postgres/public/verifyMFA", }, - PasswordVerificationAttempt: hookConfig{ + PasswordVerificationAttempt: &hookConfig{ Enabled: true, URI: "pg-functions://postgres/public/verifyPassword", }, @@ -260,6 +260,13 @@ func TestHookDiff(t *testing.T) { t.Run("local and remote disabled", func(t *testing.T) { c := newWithDefaults() + c.Hook = hook{ + CustomAccessToken: &hookConfig{Enabled: false}, + SendSMS: &hookConfig{Enabled: false}, + SendEmail: &hookConfig{Enabled: false}, + MFAVerificationAttempt: &hookConfig{Enabled: false}, + PasswordVerificationAttempt: &hookConfig{Enabled: false}, + } // Run test diff, err := c.DiffWithRemote("", v1API.AuthConfigResponse{ HookCustomAccessTokenEnabled: cast.Ptr(false), diff --git a/pkg/config/config.go b/pkg/config/config.go index 83eefa445..0e3f00a84 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -950,19 +950,32 @@ func (e external) validate() (err error) { } func (h *hook) validate() error { - if err := h.MFAVerificationAttempt.validate("mfa_verification_attempt"); err != nil { - return err + if hook := h.MFAVerificationAttempt; hook != nil { + if err := hook.validate("mfa_verification_attempt"); err != nil { + return err + } } - if err := h.PasswordVerificationAttempt.validate("password_verification_attempt"); err != nil { - return err + if hook := h.PasswordVerificationAttempt; hook != nil { + if err := hook.validate("password_verification_attempt"); err != nil { + return err + } } - if err := h.CustomAccessToken.validate("custom_access_token"); err != nil { - return err + if hook := h.CustomAccessToken; hook != nil { + if err := hook.validate("custom_access_token"); err != nil { + return err + } } - if err := h.SendSMS.validate("send_sms"); err != nil { - return err + if hook := h.SendSMS; hook != nil { + if err := hook.validate("send_sms"); err != nil { + return err + } } - return h.SendEmail.validate("send_email") + if hook := h.SendEmail; hook != nil { + if err := h.SendEmail.validate("send_email"); err != nil { + return err + } + } + return nil } var hookSecretPattern = regexp.MustCompile(`^v1,whsec_[A-Za-z0-9+/=]{32,88}$`)