From 15d5afe90f3e065cbf60744eef3ad16c6c70dfca Mon Sep 17 00:00:00 2001 From: Aine Date: Tue, 8 Nov 2022 18:16:38 +0200 Subject: [PATCH] initial, rought, not-user-friendly support for multi-domain setup --- README.md | 2 +- bot/access.go | 9 ++++++++- bot/bot.go | 16 ++++++++-------- bot/command.go | 8 ++++---- bot/command_admin.go | 4 ++-- bot/command_owner.go | 6 +++--- bot/email.go | 6 +++--- cmd/cmd.go | 4 ++-- config/config.go | 12 +++++++++++- config/defaults.go | 2 +- config/types.go | 4 ++-- smtp/msa.go | 10 +++++----- smtp/msasession.go | 18 +++++++++++++----- smtp/server.go | 14 +++++++------- 14 files changed, 70 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index ea2098a..2beefd1 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ env vars * **POSTMOOGLE_HOMESERVER** - homeserver url, eg: `https://matrix.example.com` * **POSTMOOGLE_LOGIN** - user login/localpart, eg: `moogle` * **POSTMOOGLE_PASSWORD** - user password -* **POSTMOOGLE_DOMAIN** - SMTP domain to listen for new emails +* **POSTMOOGLE_DOMAINS** - space separated list of SMTP domains to listen for new emails. The first domain acts as actual domain, all other as aliases
other optional config parameters diff --git a/bot/access.go b/bot/access.go index c76a02a..489140a 100644 --- a/bot/access.go +++ b/bot/access.go @@ -73,7 +73,14 @@ func (b *Bot) allowSend(actorID id.UserID, targetRoomID id.RoomID) bool { // AllowAuth check if SMTP login (email) and password are valid func (b *Bot) AllowAuth(email, password string) bool { - if !strings.HasSuffix(email, "@"+b.domain) { + var suffix bool + for _, domain := range b.domains { + if strings.HasSuffix(email, "@"+domain) { + suffix = true + break + } + } + if !suffix { return false } diff --git a/bot/bot.go b/bot/bot.go index fe8f7a8..3ddbbb6 100644 --- a/bot/bot.go +++ b/bot/bot.go @@ -19,7 +19,7 @@ import ( // Bot represents matrix bot type Bot struct { prefix string - domain string + domains []string allowedUsers []*regexp.Regexp allowedAdmins []*regexp.Regexp commands commandList @@ -36,16 +36,16 @@ func New( lp *linkpearl.Linkpearl, log *logger.Logger, prefix string, - domain string, + domains []string, admins []string, ) (*Bot, error) { b := &Bot{ - prefix: prefix, - domain: domain, - rooms: sync.Map{}, - log: log, - lp: lp, - mu: map[id.RoomID]*sync.Mutex{}, + prefix: prefix, + domains: domains, + rooms: sync.Map{}, + log: log, + lp: lp, + mu: map[id.RoomID]*sync.Mutex{}, } users, err := b.initBotUsers() if err != nil { diff --git a/bot/command.go b/bot/command.go index 82888e2..a973635 100644 --- a/bot/command.go +++ b/bot/command.go @@ -262,7 +262,7 @@ func (b *Bot) sendIntroduction(ctx context.Context, roomID id.RoomID) { msg.WriteString(" SOME_INBOX` command.\n") msg.WriteString("You will then be able to send emails to `SOME_INBOX@") - msg.WriteString(b.domain) + msg.WriteString(b.domains[0]) msg.WriteString("` and have them appear in this room.") b.SendNotice(ctx, roomID, msg.String()) @@ -301,7 +301,7 @@ func (b *Bot) sendHelp(ctx context.Context) { msg.WriteString(value) if cmd.key == roomOptionMailbox { msg.WriteString("@") - msg.WriteString(b.domain) + msg.WriteString(b.domains[0]) } msg.WriteString("`)") } @@ -358,8 +358,8 @@ func (b *Bot) runSend(ctx context.Context) { } } - from := mailbox + "@" + b.domain - ID := fmt.Sprintf("<%s@%s>", evt.ID, b.domain) + from := mailbox + "@" + b.domains[0] + ID := fmt.Sprintf("<%s@%s>", evt.ID, b.domains[0]) for _, to := range tos { data := utils. NewEmail(ID, "", subject, from, to, body, "", nil). diff --git a/bot/command_admin.go b/bot/command_admin.go index 89dbd0e..ee7615e 100644 --- a/bot/command_admin.go +++ b/bot/command_admin.go @@ -55,7 +55,7 @@ func (b *Bot) sendMailboxes(ctx context.Context) { msg.WriteString("* `") msg.WriteString(mailbox) msg.WriteString("@") - msg.WriteString(b.domain) + msg.WriteString(b.domains[0]) msg.WriteString("` by ") msg.WriteString(cfg.Owner()) msg.WriteString("\n") @@ -202,5 +202,5 @@ func (b *Bot) runCatchAll(ctx context.Context, commandSlice []string) { return } - b.SendNotice(ctx, evt.RoomID, fmt.Sprintf("Catch-all is set to: `%s@%s`.", mailbox, b.domain)) + b.SendNotice(ctx, evt.RoomID, fmt.Sprintf("Catch-all is set to: `%s@%s`.", mailbox, b.domains[0])) } diff --git a/bot/command_owner.go b/bot/command_owner.go index 78dd4fb..3c56002 100644 --- a/bot/command_owner.go +++ b/bot/command_owner.go @@ -58,7 +58,7 @@ func (b *Bot) getOption(ctx context.Context, name string) { } if name == roomOptionMailbox { - value = value + "@" + b.domain + value = value + "@" + b.domains[0] } msg := fmt.Sprintf("`%s` of this room is `%s`\n"+ @@ -85,7 +85,7 @@ func (b *Bot) setOption(ctx context.Context, name, value string) { if name == roomOptionMailbox { existingID, ok := b.getMapping(value) if ok && existingID != "" && existingID != evt.RoomID { - b.SendNotice(ctx, evt.RoomID, fmt.Sprintf("Mailbox `%s@%s` already taken, kupo", value, b.domain)) + b.SendNotice(ctx, evt.RoomID, fmt.Sprintf("Mailbox `%s@%s` already taken, kupo", value, b.domains[0])) return } } @@ -114,7 +114,7 @@ func (b *Bot) setOption(ctx context.Context, name, value string) { b.rooms.Delete(old) } b.rooms.Store(value, evt.RoomID) - value = fmt.Sprintf("%s@%s", value, b.domain) + value = fmt.Sprintf("%s@%s", value, b.domains[0]) } err = b.setRoomSettings(evt.RoomID, cfg) diff --git a/bot/email.go b/bot/email.go index 4acbfc8..5ed76c7 100644 --- a/bot/email.go +++ b/bot/email.go @@ -112,7 +112,7 @@ func (b *Bot) Send2Matrix(ctx context.Context, email *utils.Email, incoming bool } if !incoming { - email.MessageID = fmt.Sprintf("<%s@%s>", eventID, b.domain) + email.MessageID = fmt.Sprintf("<%s@%s>", eventID, b.domains[0]) return b.mta.Send(email.From, email.To, email.Compose(b.getBotSettings().DKIMPrivateKey())) } return nil @@ -167,7 +167,7 @@ func (b *Bot) Send2Email(ctx context.Context, to, subject, body string) error { if mailbox == "" { return fmt.Errorf("mailbox not configured, kupo") } - from := mailbox + "@" + b.domain + from := mailbox + "@" + b.domains[0] pTo, pInReplyTo, pSubject := b.getParentEmail(evt) inReplyTo = pInReplyTo if pTo != "" && to == "" { @@ -189,7 +189,7 @@ func (b *Bot) Send2Email(ctx context.Context, to, subject, body string) error { } } - ID := evt.ID.String()[1:] + "@" + b.domain + ID := evt.ID.String()[1:] + "@" + b.domains[0] data := utils. NewEmail(ID, inReplyTo, subject, from, to, body, "", nil). Compose(b.getBotSettings().DKIMPrivateKey()) diff --git a/cmd/cmd.go b/cmd/cmd.go index 166c49f..140a43b 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -87,7 +87,7 @@ func initBot(cfg *config.Config) { log.Fatal("cannot initialize matrix bot: %v", err) } - mxb, err = bot.New(lp, mxlog, cfg.Prefix, cfg.Domain, cfg.Admins) + mxb, err = bot.New(lp, mxlog, cfg.Prefix, cfg.Domains, cfg.Admins) if err != nil { // nolint // Fatal = panic, not os.Exit() log.Fatal("cannot start matrix bot: %v", err) @@ -97,7 +97,7 @@ func initBot(cfg *config.Config) { func initSMTP(cfg *config.Config) { smtpserv = smtp.NewServer(&smtp.Config{ - Domain: cfg.Domain, + Domains: cfg.Domains, Port: cfg.Port, TLSCert: cfg.TLS.Cert, TLSKey: cfg.TLS.Key, diff --git a/config/config.go b/config/config.go index 8130c57..c410ff5 100644 --- a/config/config.go +++ b/config/config.go @@ -15,7 +15,7 @@ func New() *Config { Login: env.String("login", defaultConfig.Login), Password: env.String("password", defaultConfig.Password), Prefix: env.String("prefix", defaultConfig.Prefix), - Domain: env.String("domain", defaultConfig.Domain), + Domains: migrateDomains("domain", "domains"), Port: env.String("port", defaultConfig.Port), NoEncryption: env.Bool("noencryption"), DataSecret: env.String("data.secret", defaultConfig.DataSecret), @@ -40,3 +40,13 @@ func New() *Config { return cfg } + +func migrateDomains(oldKey, newKey string) []string { + domains := []string{} + old := env.String(oldKey, "") + if old != "" { + domains = append(domains, old) + } + + return append(domains, env.Slice(newKey)...) +} diff --git a/config/defaults.go b/config/defaults.go index c9cff1e..41db4c6 100644 --- a/config/defaults.go +++ b/config/defaults.go @@ -2,7 +2,7 @@ package config var defaultConfig = &Config{ LogLevel: "INFO", - Domain: "localhost", + Domains: []string{"localhost"}, Port: "25", Prefix: "!pm", MaxSize: 1024, diff --git a/config/types.go b/config/types.go index f85cd34..f355275 100644 --- a/config/types.go +++ b/config/types.go @@ -8,8 +8,8 @@ type Config struct { Login string // Password for login/password auth only Password string - // Domain for SMTP - Domain string + // Domains for SMTP + Domains []string // Port for SMTP Port string // RoomID of the admin room diff --git a/smtp/msa.go b/smtp/msa.go index 71d50b2..4641425 100644 --- a/smtp/msa.go +++ b/smtp/msa.go @@ -13,10 +13,10 @@ import ( // msa is mail submission agent, implements smtp.Backend type msa struct { - log *logger.Logger - domain string - bot Bot - mta utils.MTA + log *logger.Logger + domains []string + bot Bot + mta utils.MTA } func (m *msa) newSession(from string, incoming bool) *msasession { @@ -27,7 +27,7 @@ func (m *msa) newSession(from string, incoming bool) *msasession { incoming: incoming, log: m.log, bot: m.bot, - domain: m.domain, + domains: m.domains, } } diff --git a/smtp/msasession.go b/smtp/msasession.go index c4cfca9..4c3c694 100644 --- a/smtp/msasession.go +++ b/smtp/msasession.go @@ -19,10 +19,10 @@ import ( // - receiving emails from remote servers, in which case: `incoming = true` // - sending emails from local users, in which case: `incoming = false` type msasession struct { - log *logger.Logger - bot Bot - mta utils.MTA - domain string + log *logger.Logger + bot Bot + mta utils.MTA + domains []string ctx context.Context incoming bool @@ -46,8 +46,16 @@ func (s *msasession) Rcpt(to string) error { sentry.GetHubFromContext(s.ctx).Scope().SetTag("to", to) s.to = to + //nolint:nestif // TODO if s.incoming { - if utils.Hostname(to) != s.domain { + var domainok bool + for _, domain := range s.domains { + if utils.Hostname(to) == domain { + domainok = true + break + } + } + if !domainok { s.log.Debug("wrong domain of %s", to) return smtp.ErrAuthRequired } diff --git a/smtp/server.go b/smtp/server.go index dfab3db..b386b0d 100644 --- a/smtp/server.go +++ b/smtp/server.go @@ -11,8 +11,8 @@ import ( ) type Config struct { - Domain string - Port string + Domains []string + Port string TLSCert string TLSKey string @@ -39,15 +39,15 @@ func NewServer(cfg *Config) *Server { log := logger.New("smtp/msa.", cfg.LogLevel) sender := NewMTA(cfg.LogLevel) receiver := &msa{ - log: log, - mta: sender, - bot: cfg.Bot, - domain: cfg.Domain, + log: log, + mta: sender, + bot: cfg.Bot, + domains: cfg.Domains, } receiver.bot.SetMTA(sender) s := smtp.NewServer(receiver) - s.Domain = cfg.Domain + s.Domain = cfg.Domains[0] s.ReadTimeout = 10 * time.Second s.WriteTimeout = 10 * time.Second s.MaxMessageBytes = cfg.MaxSize * 1024 * 1024