diff --git a/config/config.go b/config/config.go index 2cd53fd..0f2f907 100644 --- a/config/config.go +++ b/config/config.go @@ -1,9 +1,12 @@ package config import ( + "crypto/tls" + "github.com/spf13/afero" "github.com/spf13/viper" + "errors" "fmt" "runtime" "strings" @@ -58,6 +61,30 @@ type SMTPConfig struct { URL string User string Pass string + TLS TLSConfig +} + +type TLSConfig struct { + InsecureSkipVerify bool + MinVersion string +} + +func (t TLSConfig) GetMinVersion() (uint16, error) { + switch t.MinVersion { + case "": + // Not set, so let the tls package decide + return 0, nil + case "1.0": + return tls.VersionTLS10, nil + case "1.1": + return tls.VersionTLS11, nil + case "1.2": + return tls.VersionTLS12, nil + case "1.3": + return tls.VersionTLS13, nil + default: + return 0, errors.New("Invalid TLS version") + } } // Initial blank config @@ -115,6 +142,8 @@ func newViperConfig(fs afero.Fs) *viper.Viper { v.SetDefault("smtp.url", "") v.SetDefault("smtp.user", "") v.SetDefault("smtp.pass", "") + v.SetDefault("smtp.tls.InsecureSkipVerify", false) + v.SetDefault("smtp.tls.MinVersion", "1.2") v.SetDefault("dryRun", false) // Defaults (Dirs) diff --git a/config/config_test.go b/config/config_test.go new file mode 100644 index 0000000..cee4efb --- /dev/null +++ b/config/config_test.go @@ -0,0 +1,57 @@ +package config + +import ( + "crypto/tls" + "path/filepath" + "testing" + + "github.com/spf13/afero" +) + +func TestDefaultConfig(t *testing.T) { + cfg := NewConfig(afero.NewMemMapFs()) + + // Write and load fake configuration + cPath, _ := filepath.Abs("./config.toml") + afero.WriteFile(cfg.AppFs, cPath, []byte(""), 0644) + if err := LoadConfigTo(cfg); err != nil { + panic(err) + } + + version, err := cfg.ConfigFile.SMTP.TLS.GetMinVersion() + if err != nil { + t.Error(err) + } + if version != tls.VersionTLS12 { + t.Errorf("Invalid version: expected %d got %d", tls.VersionTLS12, version) + } + if cfg.ConfigFile.SMTP.TLS.InsecureSkipVerify { + t.Error("InsecureSkipVerify should be false") + } +} + +func TestTLSConfig(t *testing.T) { + cfg := NewConfig(afero.NewMemMapFs()) + + // Write and load fake configuration + cPath, _ := filepath.Abs("./config.toml") + afero.WriteFile(cfg.AppFs, cPath, []byte(` +[smtp.tls] +InsecureSkipVerify = true +MinVersion = "1.0" + `), 0644) + if err := LoadConfigTo(cfg); err != nil { + panic(err) + } + + version, err := cfg.ConfigFile.SMTP.TLS.GetMinVersion() + if err != nil { + t.Error(err) + } + if version != tls.VersionTLS10 { + t.Errorf("Invalid version: expected %d got %d", tls.VersionTLS12, version) + } + if !cfg.ConfigFile.SMTP.TLS.InsecureSkipVerify { + t.Error("InsecureSkipVerify should be true") + } +} diff --git a/mail/sender.go b/mail/sender.go index 5b2ee93..0f19139 100644 --- a/mail/sender.go +++ b/mail/sender.go @@ -1,6 +1,8 @@ package mail import ( + "crypto/tls" + "github.com/cenkalti/backoff/v4" "github.com/go-gomail/gomail" "github.com/rykov/paperboy/config" @@ -236,6 +238,15 @@ func smtpDialer(cfg *config.SMTPConfig) (*gomail.Dialer, error) { // Initialize the dialer d := gomail.NewDialer(surl.Hostname(), port, user, pass) d.SSL = (surl.Scheme == "smtps") + // insecure TLSConfig + tlsMinVersion, err := cfg.TLS.GetMinVersion() + if err != nil { + return nil, err + } + d.TLSConfig = &tls.Config{ + InsecureSkipVerify: cfg.TLS.InsecureSkipVerify, + MinVersion: tlsMinVersion, + } return d, nil }