diff --git a/backend/config/config.go b/backend/config/config.go index 8017cfba..62f6d7a4 100644 --- a/backend/config/config.go +++ b/backend/config/config.go @@ -11,6 +11,7 @@ import ( "github.com/knadh/koanf/providers/file" "github.com/teamhanko/hanko/backend/ee/saml/config" "golang.org/x/exp/slices" + zeroLogger "github.com/rs/zerolog/log" "log" "strings" "time" @@ -20,6 +21,7 @@ import ( type Config struct { Server Server `yaml:"server" json:"server,omitempty" koanf:"server"` Webauthn WebauthnSettings `yaml:"webauthn" json:"webauthn,omitempty" koanf:"webauthn"` + Smtp SMTP `yaml:"smtp" json:"smtp,omitempty" koanf:"smtp"` Passcode Passcode `yaml:"passcode" json:"passcode" koanf:"passcode"` Password Password `yaml:"password" json:"password,omitempty" koanf:"password"` Database Database `yaml:"database" json:"database" koanf:"database"` @@ -83,6 +85,8 @@ func Load(cfgFile *string) (*Config, error) { return nil, fmt.Errorf("failed to post process config: %w", err) } + c.arrangeSmtpSettings() + if err = c.Validate(); err != nil { return nil, fmt.Errorf("failed to validate config: %s", err) } @@ -109,15 +113,18 @@ func DefaultConfig() *Config { UserVerification: "preferred", Timeout: 60000, }, + Smtp: SMTP{ + Port: "465", + }, Passcode: Passcode{ - Smtp: SMTP{ - Port: "465", - }, TTL: 300, Email: Email{ FromAddress: "passcode@hanko.io", FromName: "Hanko", }, + Smtp: SMTP{ + Port: "465", + }, }, Password: Password{ MinPasswordLength: 8, @@ -175,6 +182,10 @@ func (c *Config) Validate() error { if err != nil { return fmt.Errorf("failed to validate webauthn settings: %w", err) } + err = c.Smtp.Validate() + if err != nil { + return fmt.Errorf("failed to validate smtp settings: %w", err) + } err = c.Passcode.Validate() if err != nil { return fmt.Errorf("failed to validate passcode settings: %w", err) @@ -360,8 +371,9 @@ func (e *Email) Validate() error { type Passcode struct { Email Email `yaml:"email" json:"email,omitempty" koanf:"email"` - Smtp SMTP `yaml:"smtp" json:"smtp" koanf:"smtp"` TTL int `yaml:"ttl" json:"ttl,omitempty" koanf:"ttl" jsonschema:"default=300"` + //Deprecated: Use root level Smtp instead + Smtp SMTP `yaml:"smtp" json:"smtp,omitempty" koanf:"smtp,omitempty" required:"false" envconfig:"smtp,omitempty"` } func (p *Passcode) Validate() error { @@ -369,10 +381,6 @@ func (p *Passcode) Validate() error { if err != nil { return fmt.Errorf("failed to validate email settings: %w", err) } - err = p.Smtp.Validate() - if err != nil { - return fmt.Errorf("failed to validate smtp settings: %w", err) - } return nil } @@ -651,6 +659,17 @@ func (c *Config) PostProcess() error { } +func (c *Config) arrangeSmtpSettings() { + if c.Passcode.Smtp.Validate() == nil { + if c.Smtp.Validate() == nil { + zeroLogger.Warn().Msg("Both root smtp and passcode.smtp are set. Using smtp settings from root configuration") + return + } + + c.Smtp = c.Passcode.Smtp + } +} + type LoggerConfig struct { LogHealthAndMetrics bool `yaml:"log_health_and_metrics,omitempty" json:"log_health_and_metrics" koanf:"log_health_and_metrics" jsonschema:"default=true"` } diff --git a/backend/config/config.yaml b/backend/config/config.yaml index 4484cca0..9098b7d9 100644 --- a/backend/config/config.yaml +++ b/backend/config/config.yaml @@ -4,13 +4,13 @@ database: host: localhost port: 5432 dialect: postgres -passcode: - email: - from_address: no-reply@hanko.io - smtp: +smtp: host: smtp.example.com user: example password: example +passcode: + email: + from_address: no-reply@hanko.io secrets: keys: - abcedfghijklmnopqrstuvwxyz diff --git a/backend/config/config_test.go b/backend/config/config_test.go index c32f1ea2..ff7a0344 100644 --- a/backend/config/config_test.go +++ b/backend/config/config_test.go @@ -21,6 +21,11 @@ func TestDefaultConfigAccountParameters(t *testing.T) { assert.Equal(t, cfg.Account.AllowSignup, true) } +func TestDefaultConfigSmtpParameters(t *testing.T) { + cfg := DefaultConfig() + assert.Equal(t, cfg.Smtp.Port, "465") +} + func TestParseValidConfig(t *testing.T) { configPath := "./config.yaml" cfg, err := Load(&configPath) @@ -32,6 +37,28 @@ func TestParseValidConfig(t *testing.T) { } } +func TestPasscodeSmtpSettingsCopiedToRootLevelSmtp(t *testing.T) { + configPath := "./passcode-smtp-config.yaml" + cfg, err := Load(&configPath) + if err != nil { + t.Error(err) + } + if err := cfg.Validate(); err != nil { + t.Error(err) + } + + assert.Equal(t, cfg.Smtp.Port, cfg.Passcode.Smtp.Port) + assert.Equal(t, cfg.Smtp.Host, cfg.Passcode.Smtp.Host) + assert.Equal(t, cfg.Smtp.Password, cfg.Passcode.Smtp.Password) + assert.Equal(t, cfg.Smtp.User, cfg.Passcode.Smtp.User) +} + +func TestRootSmtpPasscodeSmtpConflict(t *testing.T) { + configPath := "./root-passcode-smtp-config.yaml" + _, err := Load(&configPath) + assert.NoError(t, err) +} + func TestMinimalConfigValidates(t *testing.T) { configPath := "./minimal-config.yaml" cfg, err := Load(&configPath) @@ -76,7 +103,7 @@ func TestRateLimiterConfig(t *testing.T) { } func TestEnvironmentVariables(t *testing.T) { - err := os.Setenv("PASSCODE_SMTP_HOST", "valueFromEnvVars") + err := os.Setenv("SMTP_HOST", "valueFromEnvVars") require.NoError(t, err) err = os.Setenv("WEBAUTHN_RELYING_PARTY_ORIGINS", "https://hanko.io,https://auth.hanko.io") @@ -86,6 +113,6 @@ func TestEnvironmentVariables(t *testing.T) { cfg, err := Load(&configPath) require.NoError(t, err) - assert.Equal(t, "valueFromEnvVars", cfg.Passcode.Smtp.Host) + assert.Equal(t, "valueFromEnvVars", cfg.Smtp.Host) assert.True(t, reflect.DeepEqual([]string{"https://hanko.io", "https://auth.hanko.io"}, cfg.Webauthn.RelyingParty.Origins)) } diff --git a/backend/config/minimal-config.yaml b/backend/config/minimal-config.yaml index 12fd30b8..02ace097 100644 --- a/backend/config/minimal-config.yaml +++ b/backend/config/minimal-config.yaml @@ -1,5 +1,4 @@ -passcode: - smtp: +smtp: host: smtp.example.com user: example password: example diff --git a/backend/config/passcode-smtp-config.yaml b/backend/config/passcode-smtp-config.yaml new file mode 100644 index 00000000..4484cca0 --- /dev/null +++ b/backend/config/passcode-smtp-config.yaml @@ -0,0 +1,18 @@ +database: + user: hanko + password: hanko + host: localhost + port: 5432 + dialect: postgres +passcode: + email: + from_address: no-reply@hanko.io + smtp: + host: smtp.example.com + user: example + password: example +secrets: + keys: + - abcedfghijklmnopqrstuvwxyz +service: + name: Hanko Authentication Service diff --git a/backend/config/root-passcode-smtp-config.yaml b/backend/config/root-passcode-smtp-config.yaml new file mode 100644 index 00000000..b566560a --- /dev/null +++ b/backend/config/root-passcode-smtp-config.yaml @@ -0,0 +1,22 @@ +database: + user: hanko + password: hanko + host: localhost + port: 5432 + dialect: postgres +smtp: + host: smtp1.example.com + user: example1 + password: example1 +passcode: + email: + from_address: no-reply@hanko.io + smtp: + host: smtp2.example.com + user: example2 + password: example2 +secrets: + keys: + - abcedfghijklmnopqrstuvwxyz +service: + name: Hanko Authentication Service diff --git a/backend/handler/passcode_test.go b/backend/handler/passcode_test.go index 523b9640..5c1a3bcc 100644 --- a/backend/handler/passcode_test.go +++ b/backend/handler/passcode_test.go @@ -38,8 +38,8 @@ func (s *passcodeSuite) TestPasscodeHandler_Init() { cfg := func() *config.Config { cfg := &test.DefaultConfig - cfg.Passcode.Smtp.Host = "localhost" - cfg.Passcode.Smtp.Port = s.EmailServer.SmtpPort + cfg.Smtp.Host = s.EmailServer.SmtpHost + cfg.Smtp.Port = s.EmailServer.SmtpPort return cfg } diff --git a/backend/handler/public_router.go b/backend/handler/public_router.go index 69146653..e922d944 100644 --- a/backend/handler/public_router.go +++ b/backend/handler/public_router.go @@ -70,7 +70,7 @@ func NewPublicRouter(cfg *config.Config, persister persistence.Persister, promet sessionMiddleware := hankoMiddleware.Session(cfg, sessionManager) - mailer, err := mail.NewMailer(cfg.Passcode.Smtp) + mailer, err := mail.NewMailer(cfg.Smtp) if err != nil { panic(fmt.Errorf("failed to create mailer: %w", err)) } diff --git a/backend/handler/webauthn_test.go b/backend/handler/webauthn_test.go index f0a7757e..7790c486 100644 --- a/backend/handler/webauthn_test.go +++ b/backend/handler/webauthn_test.go @@ -343,10 +343,10 @@ var defaultConfig = config.Config{ Secrets: config.Secrets{ Keys: []string{"abcdefghijklmnop"}, }, - Passcode: config.Passcode{Smtp: config.SMTP{ + Smtp: config.SMTP{ Host: "localhost", Port: "2500", - }}, + }, } type sessionManager struct { diff --git a/backend/test/config.go b/backend/test/config.go index 3eac60e9..6f0567ec 100644 --- a/backend/test/config.go +++ b/backend/test/config.go @@ -16,11 +16,11 @@ var DefaultConfig = config.Config{ Secrets: config.Secrets{ Keys: []string{"abcdefghijklmnop"}, }, + Smtp: config.SMTP{ + Host: "localhost", + Port: "2500", + }, Passcode: config.Passcode{ - Smtp: config.SMTP{ - Host: "localhost", - Port: "2500", - }, Email: config.Email{ FromAddress: "test@hanko.io", FromName: "Hanko Test", diff --git a/backend/test/mailslurper.go b/backend/test/mailslurper.go index 86616861..f4626d82 100644 --- a/backend/test/mailslurper.go +++ b/backend/test/mailslurper.go @@ -18,6 +18,7 @@ type TestMailslurper struct { pool *dockertest.Pool resource *dockertest.Resource httpUrl string + SmtpHost string SmtpPort string } @@ -74,6 +75,7 @@ func StartMailslurper() (*TestMailslurper, error) { pool: pool, resource: resource, httpUrl: dsn, + SmtpHost: "localhost", SmtpPort: smtpPort, }, nil } diff --git a/deploy/docker-compose/config-disable-signup.yaml b/deploy/docker-compose/config-disable-signup.yaml index dfb47fee..c413e707 100644 --- a/deploy/docker-compose/config-disable-signup.yaml +++ b/deploy/docker-compose/config-disable-signup.yaml @@ -4,12 +4,12 @@ database: host: postgresd port: 5432 dialect: postgres +smtp: + host: "mailslurper" + port: "2500" passcode: email: from_address: no-reply@hanko.io - smtp: - host: "mailslurper" - port: "2500" secrets: keys: - abcedfghijklmnopqrstuvwxyz diff --git a/deploy/docker-compose/config-rate-limiting.yaml b/deploy/docker-compose/config-rate-limiting.yaml index 8c2cbf1e..865543e4 100644 --- a/deploy/docker-compose/config-rate-limiting.yaml +++ b/deploy/docker-compose/config-rate-limiting.yaml @@ -4,12 +4,12 @@ database: host: postgresd port: 5432 dialect: postgres +smtp: + host: "mailslurper" + port: "2500" passcode: email: from_address: no-reply@hanko.io - smtp: - host: "mailslurper" - port: "2500" secrets: keys: - abcedfghijklmnopqrstuvwxyz diff --git a/deploy/docker-compose/config.yaml b/deploy/docker-compose/config.yaml index 8d09edf7..2890914b 100644 --- a/deploy/docker-compose/config.yaml +++ b/deploy/docker-compose/config.yaml @@ -4,12 +4,12 @@ database: host: postgresd port: 5432 dialect: postgres +smtp: + host: "mailslurper" + port: "2500" passcode: email: from_address: no-reply@hanko.io - smtp: - host: "mailslurper" - port: "2500" secrets: keys: - abcedfghijklmnopqrstuvwxyz diff --git a/deploy/k8s/overlays/thirdparty-x-domain/config.yaml b/deploy/k8s/overlays/thirdparty-x-domain/config.yaml index 877f4b46..1d305776 100644 --- a/deploy/k8s/overlays/thirdparty-x-domain/config.yaml +++ b/deploy/k8s/overlays/thirdparty-x-domain/config.yaml @@ -4,12 +4,12 @@ database: host: postgres port: 5432 dialect: postgres +smtp: + host: "mailhog" + port: "2500" passcode: email: from_address: no-reply@hanko.io - smtp: - host: "mailhog" - port: "2500" secrets: keys: - abcedfghijklmnopqrstuvwxyz @@ -40,4 +40,4 @@ third_party: github: enabled: true apple: - enabled: true \ No newline at end of file + enabled: true diff --git a/e2e/.nvmrc b/e2e/.nvmrc index dac255d2..1c680742 100644 --- a/e2e/.nvmrc +++ b/e2e/.nvmrc @@ -1 +1 @@ -v16.15.1 +v18.6.0