Skip to content

Commit

Permalink
feat(config): sync smtp and email config to remote
Browse files Browse the repository at this point in the history
  • Loading branch information
sweatybridge committed Nov 12, 2024
1 parent 96136cf commit 921fdc6
Show file tree
Hide file tree
Showing 5 changed files with 358 additions and 54 deletions.
23 changes: 17 additions & 6 deletions internal/start/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -490,12 +490,6 @@ EOF

fmt.Sprintf("GOTRUE_EXTERNAL_ANONYMOUS_USERS_ENABLED=%v", utils.Config.Auth.EnableAnonymousSignIns),

fmt.Sprintf("GOTRUE_SMTP_HOST=%s", utils.Config.Auth.Email.Smtp.Host),
fmt.Sprintf("GOTRUE_SMTP_PORT=%d", utils.Config.Auth.Email.Smtp.Port),
fmt.Sprintf("GOTRUE_SMTP_USER=%s", utils.Config.Auth.Email.Smtp.User),
fmt.Sprintf("GOTRUE_SMTP_PASS=%s", utils.Config.Auth.Email.Smtp.Pass),
fmt.Sprintf("GOTRUE_SMTP_ADMIN_EMAIL=%s", utils.Config.Auth.Email.Smtp.AdminEmail),
fmt.Sprintf("GOTRUE_SMTP_SENDER_NAME=%s", utils.Config.Auth.Email.Smtp.SenderName),
fmt.Sprintf("GOTRUE_SMTP_MAX_FREQUENCY=%v", utils.Config.Auth.Email.MaxFrequency),

"GOTRUE_MAILER_URLPATHS_INVITE=" + utils.GetApiUrl("/auth/v1/verify"),
Expand Down Expand Up @@ -525,6 +519,23 @@ EOF
fmt.Sprintf("GOTRUE_MFA_MAX_ENROLLED_FACTORS=%v", utils.Config.Auth.MFA.MaxEnrolledFactors),
}

if utils.Config.Auth.Email.Smtp != nil {
env = append(env,
fmt.Sprintf("GOTRUE_SMTP_HOST=%s", utils.Config.Auth.Email.Smtp.Host),
fmt.Sprintf("GOTRUE_SMTP_PORT=%d", utils.Config.Auth.Email.Smtp.Port),
fmt.Sprintf("GOTRUE_SMTP_USER=%s", utils.Config.Auth.Email.Smtp.User),
fmt.Sprintf("GOTRUE_SMTP_PASS=%s", utils.Config.Auth.Email.Smtp.Pass),
fmt.Sprintf("GOTRUE_SMTP_ADMIN_EMAIL=%s", utils.Config.Auth.Email.Smtp.AdminEmail),
fmt.Sprintf("GOTRUE_SMTP_SENDER_NAME=%s", utils.Config.Auth.Email.Smtp.SenderName),
)
} else if utils.Config.Inbucket.Enabled {
env = append(env,
"GOTRUE_SMTP_HOST=inbucket",
"GOTRUE_SMTP_PORT=2500",
"[email protected]",
)
}

if utils.Config.Auth.Sessions.Timebox > 0 {
env = append(env, fmt.Sprintf("GOTRUE_SESSIONS_TIMEBOX=%v", utils.Config.Auth.Sessions.Timebox))
}
Expand Down
59 changes: 55 additions & 4 deletions pkg/config/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package config

import (
"maps"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -73,7 +74,7 @@ type (
EnableConfirmations bool `toml:"enable_confirmations"`
SecurePasswordChange bool `toml:"secure_password_change"`
Template map[string]emailTemplate `toml:"template"`
Smtp smtp `toml:"smtp"`
Smtp *smtp `toml:"smtp"`
MaxFrequency time.Duration `toml:"max_frequency"`
OtpLength uint `toml:"otp_length"`
OtpExpiry uint `toml:"otp_expiry"`
Expand Down Expand Up @@ -194,7 +195,7 @@ func (a *auth) ToUpdateAuthConfigBody() v1API.UpdateAuthConfigBody {
a.Hook.toAuthConfigBody(&body)
a.MFA.toAuthConfigBody(&body)
a.Sessions.toAuthConfigBody(&body)
// TODO: email
a.Email.toAuthConfigBody(&body)
a.Sms.toAuthConfigBody(&body)
a.External.toAuthConfigBody(&body)
return body
Expand All @@ -213,6 +214,7 @@ func (a *auth) fromRemoteAuthConfig(remoteConfig v1API.AuthConfigResponse) auth
result.Hook.fromAuthConfig(remoteConfig)
result.MFA.fromAuthConfig(remoteConfig)
result.Sessions.fromAuthConfig(remoteConfig)
result.Email.fromAuthConfig(remoteConfig)
result.Sms.fromAuthConfig(remoteConfig)
result.External = maps.Clone(result.External)
result.External.fromAuthConfig(remoteConfig)
Expand Down Expand Up @@ -309,6 +311,53 @@ func (s *sessions) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
s.InactivityTimeout = time.Duration(cast.Val(remoteConfig.SessionsInactivityTimeout, 0)) * time.Second
}

func (e email) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) {
body.ExternalEmailEnabled = &e.EnableSignup
body.MailerSecureEmailChangeEnabled = &e.DoubleConfirmChanges
body.MailerAutoconfirm = cast.Ptr(!e.EnableConfirmations)
body.MailerOtpLength = cast.UintToIntPtr(&e.OtpLength)
body.MailerOtpExp = cast.UintToIntPtr(&e.OtpExpiry)
body.SecurityUpdatePasswordRequireReauthentication = &e.SecurePasswordChange
body.SmtpMaxFrequency = cast.Ptr(int(e.MaxFrequency.Seconds()))
if e.Smtp != nil {
body.SmtpHost = &e.Smtp.Host
body.SmtpPort = cast.Ptr(strconv.Itoa(int(e.Smtp.Port)))
body.SmtpUser = &e.Smtp.User
body.SmtpPass = &e.Smtp.Pass
body.SmtpAdminEmail = &e.Smtp.AdminEmail
body.SmtpSenderName = &e.Smtp.SenderName
} else {
// Setting a single empty string disables SMTP
body.SmtpHost = cast.Ptr("")
}
}

func (e *email) fromAuthConfig(remoteConfig v1API.AuthConfigResponse) {
e.EnableSignup = cast.Val(remoteConfig.ExternalEmailEnabled, false)
e.DoubleConfirmChanges = cast.Val(remoteConfig.MailerSecureEmailChangeEnabled, false)
e.EnableConfirmations = !cast.Val(remoteConfig.MailerAutoconfirm, false)
e.OtpLength = cast.IntToUint(cast.Val(remoteConfig.MailerOtpLength, 0))
e.OtpExpiry = cast.IntToUint(remoteConfig.MailerOtpExp)
e.SecurePasswordChange = cast.Val(remoteConfig.SecurityUpdatePasswordRequireReauthentication, false)
e.MaxFrequency = time.Duration(cast.Val(remoteConfig.SmtpMaxFrequency, 0)) * time.Second
// Api resets all values when SMTP is disabled
if remoteConfig.SmtpHost != nil {
e.Smtp = &smtp{
Host: *remoteConfig.SmtpHost,
User: cast.Val(remoteConfig.SmtpUser, ""),
Pass: hashPrefix + cast.Val(remoteConfig.SmtpPass, ""),
AdminEmail: cast.Val(remoteConfig.SmtpAdminEmail, ""),
SenderName: cast.Val(remoteConfig.SmtpSenderName, ""),
}
portStr := cast.Val(remoteConfig.SmtpPort, "")
if port, err := strconv.ParseUint(portStr, 10, 16); err == nil {
e.Smtp.Port = uint16(port)
}
} else {
e.Smtp = nil
}
}

func (s sms) toAuthConfigBody(body *v1API.UpdateAuthConfigBody) {
body.ExternalPhoneEnabled = &s.EnableSignup
body.SmsMaxFrequency = cast.Ptr(int(s.MaxFrequency.Seconds()))
Expand Down Expand Up @@ -667,8 +716,10 @@ func (a *auth) hashSecrets(key string) auth {
return hashPrefix + sha256Hmac(key, v)
}
result := *a
if len(result.Email.Smtp.Pass) > 0 {
result.Email.Smtp.Pass = hash(result.Email.Smtp.Pass)
if result.Email.Smtp != nil && len(result.Email.Smtp.Pass) > 0 {
copy := *result.Email.Smtp
copy.Pass = hash(result.Email.Smtp.Pass)
result.Email.Smtp = &copy
}
// Only hash secrets for locally enabled providers because other envs won't be loaded
switch {
Expand Down
Loading

0 comments on commit 921fdc6

Please sign in to comment.