From 6f8e85010303e5b46d485dae8b54b2ddee8a659e Mon Sep 17 00:00:00 2001 From: Aine Date: Fri, 7 Oct 2022 23:24:59 +0300 Subject: [PATCH 1/6] expose security and spam options --- bot/command.go | 40 +++++++++++++++++++++++++++++++++++++++ bot/settings_room.go | 45 ++++++++++++++++++++++++++++++++++---------- utils/utils.go | 28 +++++++++++++++++++++++++++ 3 files changed, 103 insertions(+), 10 deletions(-) diff --git a/bot/command.go b/bot/command.go index fc92b5b..df202d4 100644 --- a/bot/command.go +++ b/bot/command.go @@ -143,6 +143,46 @@ func (b *Bot) initCommands() commandList { sanitizer: utils.SanitizeBoolString, allowed: b.allowOwner, }, + {allowed: b.allowOwner}, // delimiter + { + key: roomOptionSecurityEmail, + description: "Enforce sender email address validation (`true` - enforce, `false` - disable)", + sanitizer: utils.SanitizeBoolString, + allowed: b.allowOwner, + }, + { + key: roomOptionSecuritySMTP, + description: "Enforce sender email SMTP check (`true` - enforce, `false` - disable)", + sanitizer: utils.SanitizeBoolString, + allowed: b.allowOwner, + }, + { + key: roomOptionSpamEmails, + description: fmt.Sprintf( + "Get or set `%s` of the room (comma-separated list)", + roomOptionSpamEmails, + ), + sanitizer: utils.SanitizeStringSlice, + allowed: b.allowOwner, + }, + { + key: roomOptionSpamHosts, + description: fmt.Sprintf( + "Get or set `%s` of the room (comma-separated list)", + roomOptionSpamHosts, + ), + sanitizer: utils.SanitizeStringSlice, + allowed: b.allowOwner, + }, + { + key: roomOptionSpamLocalparts, + description: fmt.Sprintf( + "Get or set `%s` of the room (comma-separated list)", + roomOptionSpamLocalparts, + ), + sanitizer: utils.SanitizeStringSlice, + allowed: b.allowOwner, + }, {allowed: b.allowAdmin}, // delimiter { key: botOptionUsers, diff --git a/bot/settings_room.go b/bot/settings_room.go index 7870aa7..57d57b9 100644 --- a/bot/settings_room.go +++ b/bot/settings_room.go @@ -13,16 +13,21 @@ const acRoomSettingsKey = "cc.etke.postmoogle.settings" // option keys const ( - roomOptionOwner = "owner" - roomOptionMailbox = "mailbox" - roomOptionNoSend = "nosend" - roomOptionNoSender = "nosender" - roomOptionNoRecipient = "norecipient" - roomOptionNoSubject = "nosubject" - roomOptionNoHTML = "nohtml" - roomOptionNoThreads = "nothreads" - roomOptionNoFiles = "nofiles" - roomOptionPassword = "password" + roomOptionOwner = "owner" + roomOptionMailbox = "mailbox" + roomOptionNoSend = "nosend" + roomOptionNoSender = "nosender" + roomOptionNoRecipient = "norecipient" + roomOptionNoSubject = "nosubject" + roomOptionNoHTML = "nohtml" + roomOptionNoThreads = "nothreads" + roomOptionNoFiles = "nofiles" + roomOptionPassword = "password" + roomOptionSecuritySMTP = "security:smtp" + roomOptionSecurityEmail = "security:email" + roomOptionSpamEmails = "spam:emails" + roomOptionSpamHosts = "spam:hosts" + roomOptionSpamLocalparts = "spam:localparts" ) type roomSettings map[string]string @@ -77,6 +82,26 @@ func (s roomSettings) NoFiles() bool { return utils.Bool(s.Get(roomOptionNoFiles)) } +func (s roomSettings) SecuritySMTP() bool { + return utils.Bool(s.Get(roomOptionSecuritySMTP)) +} + +func (s roomSettings) SecurityEmail() bool { + return utils.Bool(s.Get(roomOptionSecurityEmail)) +} + +func (s roomSettings) SpamEmails() []string { + return utils.StringSlice(s.Get(roomOptionSpamEmails)) +} + +func (s roomSettings) SpamHosts() []string { + return utils.StringSlice(s.Get(roomOptionSpamHosts)) +} + +func (s roomSettings) SpamLocalparts() []string { + return utils.StringSlice(s.Get(roomOptionSpamLocalparts)) +} + // ContentOptions converts room display settings to content options func (s roomSettings) ContentOptions() *utils.ContentOptions { return &utils.ContentOptions{ diff --git a/utils/utils.go b/utils/utils.go index 93271da..f49939a 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -33,3 +33,31 @@ func Bool(str string) bool { func SanitizeBoolString(str string) string { return strconv.FormatBool(Bool(str)) } + +// StringSlice converts comma-separated string to slice +func StringSlice(str string) []string { + if str == "" { + return nil + } + + str = strings.TrimSpace(str) + if strings.IndexByte(str, ',') == -1 { + return []string{str} + } + + return strings.Split(str, ",") +} + +// SanitizeBoolString converts string to slice and back to string +func SanitizeStringSlice(str string) string { + parts := StringSlice(str) + if len(parts) == 0 { + return str + } + + for i, part := range parts { + parts[i] = strings.TrimSpace(part) + } + + return strings.Join(parts, ",") +} From 99e509ea3a2d6b9c4df5b025438cfddb198a6e35 Mon Sep 17 00:00:00 2001 From: Aine Date: Sat, 8 Oct 2022 00:11:48 +0300 Subject: [PATCH 2/6] Email validations --- README.md | 8 ++++++++ bot/command.go | 4 ++-- bot/email.go | 11 +++++++++++ bot/settings_room.go | 6 +++--- go.mod | 3 ++- go.sum | 6 ++++-- smtp/msasession.go | 25 +++++++++++++++++++++++-- smtp/mta.go | 1 + utils/email.go | 9 +++++++++ 9 files changed, 63 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 903153c..e1839a8 100644 --- a/README.md +++ b/README.md @@ -254,6 +254,14 @@ If you want to change them - check available options in the help message (`!pm h --- +* **!pm security:mx** - Enforce sender email MX check (`true` - enforce, `false` - disable) +* **!pm security:smtp** - Enforce sender email SMTP check (`true` - enforce, `false` - disable) +* **!pm spam:emails** - Get or set `spam:emails` of the room (comma-separated list) +* **!pm spam:hosts** - Get or set `spam:hosts` of the room (comma-separated list) +* **!pm spam:localparts** - Get or set `spam:localparts` of the room (comma-separated list) + +--- + * **!pm dkim** - Get DKIM signature * **!pm catch-all** - Configure catch-all mailbox * **!pm users** - Get or set allowed users patterns diff --git a/bot/command.go b/bot/command.go index df202d4..4b54662 100644 --- a/bot/command.go +++ b/bot/command.go @@ -145,8 +145,8 @@ func (b *Bot) initCommands() commandList { }, {allowed: b.allowOwner}, // delimiter { - key: roomOptionSecurityEmail, - description: "Enforce sender email address validation (`true` - enforce, `false` - disable)", + key: roomOptionSecurityMX, + description: "Enforce sender email MX check (`true` - enforce, `false` - disable)", sanitizer: utils.SanitizeBoolString, allowed: b.allowOwner, }, diff --git a/bot/email.go b/bot/email.go index b946795..d69da1d 100644 --- a/bot/email.go +++ b/bot/email.go @@ -59,6 +59,17 @@ func (b *Bot) GetMapping(mailbox string) (id.RoomID, bool) { return roomID, ok } +// GetOptions returns room settings +func (b *Bot) GetOptions(roomID id.RoomID) utils.ValidationOptions { + cfg, err := b.getRoomSettings(roomID) + if err != nil { + b.log.Error("cannot retrieve room settings: %v", err) + return roomSettings{} + } + + return cfg +} + // Send email to matrix room func (b *Bot) Send2Matrix(ctx context.Context, email *utils.Email, incoming bool) error { roomID, ok := b.GetMapping(email.Mailbox(incoming)) diff --git a/bot/settings_room.go b/bot/settings_room.go index 57d57b9..69a8bdc 100644 --- a/bot/settings_room.go +++ b/bot/settings_room.go @@ -24,7 +24,7 @@ const ( roomOptionNoFiles = "nofiles" roomOptionPassword = "password" roomOptionSecuritySMTP = "security:smtp" - roomOptionSecurityEmail = "security:email" + roomOptionSecurityMX = "security:mx" roomOptionSpamEmails = "spam:emails" roomOptionSpamHosts = "spam:hosts" roomOptionSpamLocalparts = "spam:localparts" @@ -86,8 +86,8 @@ func (s roomSettings) SecuritySMTP() bool { return utils.Bool(s.Get(roomOptionSecuritySMTP)) } -func (s roomSettings) SecurityEmail() bool { - return utils.Bool(s.Get(roomOptionSecurityEmail)) +func (s roomSettings) SecurityMX() bool { + return utils.Bool(s.Get(roomOptionSecurityMX)) } func (s roomSettings) SpamEmails() []string { diff --git a/go.mod b/go.mod index c844f19..1c0a75a 100644 --- a/go.mod +++ b/go.mod @@ -19,8 +19,9 @@ require ( gitlab.com/etke.cc/go/mxidwc v1.0.0 gitlab.com/etke.cc/go/secgen v1.1.1 gitlab.com/etke.cc/go/trysmtp v1.0.0 + gitlab.com/etke.cc/go/validator v1.0.1 gitlab.com/etke.cc/linkpearl v0.0.0-20221002171411-bb783f7e50f0 - golang.org/x/net v0.0.0-20221002022538-bcab6841153b + golang.org/x/net v0.0.0-20221004154528-8021a29435af maunium.net/go/mautrix v0.12.1 ) diff --git a/go.sum b/go.sum index 60bf3c6..af7000d 100644 --- a/go.sum +++ b/go.sum @@ -97,6 +97,8 @@ gitlab.com/etke.cc/go/secgen v1.1.1 h1:RmKOki725HIhWJHzPtAc9X4YvBneczndchpMgoDkE gitlab.com/etke.cc/go/secgen v1.1.1/go.mod h1:3pJqRGeWApzx7qXjABqz2o2SMCNpKSZao/gXVdasqE8= gitlab.com/etke.cc/go/trysmtp v1.0.0 h1:f/7gSmzohKniVeLSLevI+ZsySYcPUGkT9cRlOTwjOr8= gitlab.com/etke.cc/go/trysmtp v1.0.0/go.mod h1:KqRuIB2IPElEEbAxXmFyKtm7S5YiuEb4lxwWthccqyE= +gitlab.com/etke.cc/go/validator v1.0.1 h1:xp1tAzgCu9A1pga8rFUo7hODaEcCR1nkkodw96+dYuA= +gitlab.com/etke.cc/go/validator v1.0.1/go.mod h1:3vdssRG4LwgdTr9IHz9MjGSEO+3/FO9hXPGMuSeweJ8= gitlab.com/etke.cc/linkpearl v0.0.0-20221002171411-bb783f7e50f0 h1:B5YV62XKsLb9sCu9jW4Pnc5HDNRzdR1FswtRBMw1sR0= gitlab.com/etke.cc/linkpearl v0.0.0-20221002171411-bb783f7e50f0/go.mod h1:hjn0SVswej+Jo3+MycLm+lTsAVFy047Df+adX6MoXoE= golang.org/x/crypto v0.0.0-20220518034528-6f7dac969898/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= @@ -105,8 +107,8 @@ golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/net v0.0.0-20210501142056-aec3718b3fa0/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20221002022538-bcab6841153b h1:6e93nYa3hNqAvLr0pD4PN1fFS+gKzp2zAXqrnTCstqU= -golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20221004154528-8021a29435af h1:wv66FM3rLZGPdxpYL+ApnDe2HzHcTFta3z5nsc13wI4= +golang.org/x/net v0.0.0-20221004154528-8021a29435af/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/smtp/msasession.go b/smtp/msasession.go index 93b293f..1c4df92 100644 --- a/smtp/msasession.go +++ b/smtp/msasession.go @@ -9,6 +9,7 @@ import ( "github.com/getsentry/sentry-go" "github.com/jhillyerd/enmime" "gitlab.com/etke.cc/go/logger" + "gitlab.com/etke.cc/go/validator" "gitlab.com/etke.cc/postmoogle/utils" ) @@ -43,6 +44,7 @@ func (s *msasession) Mail(from string, opts smtp.MailOptions) error { func (s *msasession) Rcpt(to string) error { sentry.GetHubFromContext(s.ctx).Scope().SetTag("to", to) + s.to = to if s.incoming { if utils.Hostname(to) != s.domain { @@ -50,14 +52,18 @@ func (s *msasession) Rcpt(to string) error { return smtp.ErrAuthRequired } - _, ok := s.bot.GetMapping(utils.Mailbox(to)) + roomID, ok := s.bot.GetMapping(utils.Mailbox(to)) if !ok { s.log.Debug("mapping for %s not found", to) return smtp.ErrAuthRequired } + + validations := s.bot.GetOptions(roomID) + if !s.validate(validations) { + return smtp.ErrAuthRequired + } } - s.to = to s.log.Debug("mail to %s", to) return nil } @@ -75,6 +81,21 @@ func (s *msasession) parseAttachments(parts []*enmime.Part) []*utils.File { return files } +func (s *msasession) validate(options utils.ValidationOptions) bool { + spam := validator.Spam{ + Emails: options.SpamEmails(), + Hosts: options.SpamHosts(), + Localparts: options.SpamLocalparts(), + } + enforce := validator.Enforce{ + MX: options.SecurityMX(), + SMTP: options.SecuritySMTP(), + } + v := validator.New(spam, enforce, s.to, s.log) + + return v.Email(s.from) +} + func (s *msasession) Data(r io.Reader) error { parser := enmime.NewParser() eml, err := parser.ReadEnvelope(r) diff --git a/smtp/mta.go b/smtp/mta.go index a8647cb..f095d91 100644 --- a/smtp/mta.go +++ b/smtp/mta.go @@ -16,6 +16,7 @@ import ( type Bot interface { AllowAuth(string, string) bool GetMapping(string) (id.RoomID, bool) + GetOptions(id.RoomID) utils.ValidationOptions Send2Matrix(ctx context.Context, email *utils.Email, incoming bool) error SetMTA(mta utils.MTA) } diff --git a/utils/email.go b/utils/email.go index b415929..6f7e279 100644 --- a/utils/email.go +++ b/utils/email.go @@ -19,6 +19,15 @@ type MTA interface { Send(from, to, data string) error } +// ValidationOptions for incoming mail +type ValidationOptions interface { + SecuritySMTP() bool + SecurityMX() bool + SpamEmails() []string + SpamHosts() []string + SpamLocalparts() []string +} + // Email object type Email struct { Date string From 0767e7d0c31f3c929ee70e80ff12ba07f60fcd84 Mon Sep 17 00:00:00 2001 From: Aine Date: Sat, 8 Oct 2022 11:29:10 +0300 Subject: [PATCH 3/6] security and spam options descriptions --- bot/command.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bot/command.go b/bot/command.go index 4b54662..ffbe068 100644 --- a/bot/command.go +++ b/bot/command.go @@ -146,20 +146,20 @@ func (b *Bot) initCommands() commandList { {allowed: b.allowOwner}, // delimiter { key: roomOptionSecurityMX, - description: "Enforce sender email MX check (`true` - enforce, `false` - disable)", + description: "only accept email from servers which seem prepared to receive it (those having valid MX records) (`true` - enable, `false` - disable)", sanitizer: utils.SanitizeBoolString, allowed: b.allowOwner, }, { key: roomOptionSecuritySMTP, - description: "Enforce sender email SMTP check (`true` - enforce, `false` - disable)", + description: "only accept email from servers which seem prepared to receive it (those listening on an SMTP port) (`true` - enable, `false` - disable)", sanitizer: utils.SanitizeBoolString, allowed: b.allowOwner, }, { key: roomOptionSpamEmails, description: fmt.Sprintf( - "Get or set `%s` of the room (comma-separated list)", + "Get or set `%s` of the room (comma-separated list), eg: `spammer@example.com,sspam@example.org`", roomOptionSpamEmails, ), sanitizer: utils.SanitizeStringSlice, @@ -168,7 +168,7 @@ func (b *Bot) initCommands() commandList { { key: roomOptionSpamHosts, description: fmt.Sprintf( - "Get or set `%s` of the room (comma-separated list)", + "Get or set `%s` of the room (comma-separated list), eg: `gmail.com,hotmail.com,outlook.com`", roomOptionSpamHosts, ), sanitizer: utils.SanitizeStringSlice, @@ -177,7 +177,7 @@ func (b *Bot) initCommands() commandList { { key: roomOptionSpamLocalparts, description: fmt.Sprintf( - "Get or set `%s` of the room (comma-separated list)", + "Get or set `%s` of the room (comma-separated list), eg: `notspam,noreply,no-rely`", roomOptionSpamLocalparts, ), sanitizer: utils.SanitizeStringSlice, From 1dd996e4303f606409797217cfb6dd465ccb618f Mon Sep 17 00:00:00 2001 From: Aine Date: Sat, 8 Oct 2022 11:58:14 +0300 Subject: [PATCH 4/6] rename security options --- bot/settings_room.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bot/settings_room.go b/bot/settings_room.go index 69a8bdc..1dfea96 100644 --- a/bot/settings_room.go +++ b/bot/settings_room.go @@ -23,11 +23,11 @@ const ( roomOptionNoThreads = "nothreads" roomOptionNoFiles = "nofiles" roomOptionPassword = "password" - roomOptionSecuritySMTP = "security:smtp" - roomOptionSecurityMX = "security:mx" - roomOptionSpamEmails = "spam:emails" - roomOptionSpamHosts = "spam:hosts" - roomOptionSpamLocalparts = "spam:localparts" + roomOptionSecuritySMTP = "spamcheck:smtp" + roomOptionSecurityMX = "spamcheck:mx" + roomOptionSpamEmails = "spamlist:emails" + roomOptionSpamHosts = "spamlist:hosts" + roomOptionSpamLocalparts = "spamlist:localparts" ) type roomSettings map[string]string From d575552237b7f73797f000557c5567d212f42f30 Mon Sep 17 00:00:00 2001 From: Aine Date: Sat, 8 Oct 2022 12:01:03 +0300 Subject: [PATCH 5/6] update readme --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e1839a8..192ab15 100644 --- a/README.md +++ b/README.md @@ -254,11 +254,11 @@ If you want to change them - check available options in the help message (`!pm h --- -* **!pm security:mx** - Enforce sender email MX check (`true` - enforce, `false` - disable) -* **!pm security:smtp** - Enforce sender email SMTP check (`true` - enforce, `false` - disable) -* **!pm spam:emails** - Get or set `spam:emails` of the room (comma-separated list) -* **!pm spam:hosts** - Get or set `spam:hosts` of the room (comma-separated list) -* **!pm spam:localparts** - Get or set `spam:localparts` of the room (comma-separated list) +* **!pm spamcheck:mx** - only accept email from servers which seem prepared to receive it (those having valid MX records) (`true` - enable, `false` - disable) +* **!pm spamcheck:smtp** - only accept email from servers which seem prepared to receive it (those listening on an SMTP port) (`true` - enable, `false` - disable) +* **!pm spamlist:emails** - Get or set `spamlist:emails` of the room (comma-separated list), eg: `spammer@example.com,sspam@example.org` +* **!pm spamlist:hosts** - Get or set `spamlist:hosts` of the room (comma-separated list), eg: `gmail.com,hotmail.com,outlook.com` +* **!pm spamlist:localparts** - Get or set `spamlist:localparts` of the room (comma-separated list), eg: `notspam,noreply,no-rely` --- From 6f4da5938773b41d912707fa9ef38d401b4805da Mon Sep 17 00:00:00 2001 From: Aine Date: Mon, 10 Oct 2022 09:41:22 +0300 Subject: [PATCH 6/6] feedback, typos, renaming --- README.md | 4 ++-- bot/bot.go | 4 +++- bot/command.go | 20 +++++++++--------- bot/email.go | 4 ++-- bot/settings_room.go | 50 ++++++++++++++++++++++---------------------- smtp/msasession.go | 14 ++++++------- smtp/mta.go | 2 +- utils/email.go | 14 ++++++------- 8 files changed, 57 insertions(+), 55 deletions(-) diff --git a/README.md b/README.md index 192ab15..40800a7 100644 --- a/README.md +++ b/README.md @@ -257,8 +257,8 @@ If you want to change them - check available options in the help message (`!pm h * **!pm spamcheck:mx** - only accept email from servers which seem prepared to receive it (those having valid MX records) (`true` - enable, `false` - disable) * **!pm spamcheck:smtp** - only accept email from servers which seem prepared to receive it (those listening on an SMTP port) (`true` - enable, `false` - disable) * **!pm spamlist:emails** - Get or set `spamlist:emails` of the room (comma-separated list), eg: `spammer@example.com,sspam@example.org` -* **!pm spamlist:hosts** - Get or set `spamlist:hosts` of the room (comma-separated list), eg: `gmail.com,hotmail.com,outlook.com` -* **!pm spamlist:localparts** - Get or set `spamlist:localparts` of the room (comma-separated list), eg: `notspam,noreply,no-rely` +* **!pm spamlist:hosts** - Get or set `spamlist:hosts` of the room (comma-separated list), eg: `spammer.com,scammer.com,morespam.com` +* **!pm spamlist:mailboxes** - Get or set `spamlist:mailboxes` of the room (comma-separated list), eg: `notspam,noreply,no-reply` --- diff --git a/bot/bot.go b/bot/bot.go index dbcb11c..fe8f7a8 100644 --- a/bot/bot.go +++ b/bot/bot.go @@ -73,7 +73,9 @@ func (b *Bot) Error(ctx context.Context, roomID id.RoomID, message string, args b.log.Error(message, args...) err := fmt.Errorf(message, args...) - sentry.GetHubFromContext(ctx).CaptureException(err) + if hub := sentry.GetHubFromContext(ctx); hub != nil { + sentry.GetHubFromContext(ctx).CaptureException(err) + } if roomID != "" { b.SendError(ctx, roomID, err.Error()) } diff --git a/bot/command.go b/bot/command.go index ffbe068..df135b3 100644 --- a/bot/command.go +++ b/bot/command.go @@ -145,40 +145,40 @@ func (b *Bot) initCommands() commandList { }, {allowed: b.allowOwner}, // delimiter { - key: roomOptionSecurityMX, + key: roomOptionSpamcheckMX, description: "only accept email from servers which seem prepared to receive it (those having valid MX records) (`true` - enable, `false` - disable)", sanitizer: utils.SanitizeBoolString, allowed: b.allowOwner, }, { - key: roomOptionSecuritySMTP, + key: roomOptionSpamcheckSMTP, description: "only accept email from servers which seem prepared to receive it (those listening on an SMTP port) (`true` - enable, `false` - disable)", sanitizer: utils.SanitizeBoolString, allowed: b.allowOwner, }, { - key: roomOptionSpamEmails, + key: roomOptionSpamlistEmails, description: fmt.Sprintf( "Get or set `%s` of the room (comma-separated list), eg: `spammer@example.com,sspam@example.org`", - roomOptionSpamEmails, + roomOptionSpamlistEmails, ), sanitizer: utils.SanitizeStringSlice, allowed: b.allowOwner, }, { - key: roomOptionSpamHosts, + key: roomOptionSpamlistHosts, description: fmt.Sprintf( - "Get or set `%s` of the room (comma-separated list), eg: `gmail.com,hotmail.com,outlook.com`", - roomOptionSpamHosts, + "Get or set `%s` of the room (comma-separated list), eg: `spammer.com,scammer.com,morespam.com`", + roomOptionSpamlistHosts, ), sanitizer: utils.SanitizeStringSlice, allowed: b.allowOwner, }, { - key: roomOptionSpamLocalparts, + key: roomOptionSpamlistLocalparts, description: fmt.Sprintf( - "Get or set `%s` of the room (comma-separated list), eg: `notspam,noreply,no-rely`", - roomOptionSpamLocalparts, + "Get or set `%s` of the room (comma-separated list), eg: `notspam,noreply,no-reply`", + roomOptionSpamlistLocalparts, ), sanitizer: utils.SanitizeStringSlice, allowed: b.allowOwner, diff --git a/bot/email.go b/bot/email.go index d69da1d..9f9c892 100644 --- a/bot/email.go +++ b/bot/email.go @@ -59,8 +59,8 @@ func (b *Bot) GetMapping(mailbox string) (id.RoomID, bool) { return roomID, ok } -// GetOptions returns room settings -func (b *Bot) GetOptions(roomID id.RoomID) utils.ValidationOptions { +// GetIFOptions returns incoming email filtering options (room settings) +func (b *Bot) GetIFOptions(roomID id.RoomID) utils.IncomingFilteringOptions { cfg, err := b.getRoomSettings(roomID) if err != nil { b.log.Error("cannot retrieve room settings: %v", err) diff --git a/bot/settings_room.go b/bot/settings_room.go index 1dfea96..3298d4f 100644 --- a/bot/settings_room.go +++ b/bot/settings_room.go @@ -13,21 +13,21 @@ const acRoomSettingsKey = "cc.etke.postmoogle.settings" // option keys const ( - roomOptionOwner = "owner" - roomOptionMailbox = "mailbox" - roomOptionNoSend = "nosend" - roomOptionNoSender = "nosender" - roomOptionNoRecipient = "norecipient" - roomOptionNoSubject = "nosubject" - roomOptionNoHTML = "nohtml" - roomOptionNoThreads = "nothreads" - roomOptionNoFiles = "nofiles" - roomOptionPassword = "password" - roomOptionSecuritySMTP = "spamcheck:smtp" - roomOptionSecurityMX = "spamcheck:mx" - roomOptionSpamEmails = "spamlist:emails" - roomOptionSpamHosts = "spamlist:hosts" - roomOptionSpamLocalparts = "spamlist:localparts" + roomOptionOwner = "owner" + roomOptionMailbox = "mailbox" + roomOptionNoSend = "nosend" + roomOptionNoSender = "nosender" + roomOptionNoRecipient = "norecipient" + roomOptionNoSubject = "nosubject" + roomOptionNoHTML = "nohtml" + roomOptionNoThreads = "nothreads" + roomOptionNoFiles = "nofiles" + roomOptionPassword = "password" + roomOptionSpamcheckSMTP = "spamcheck:smtp" + roomOptionSpamcheckMX = "spamcheck:mx" + roomOptionSpamlistEmails = "spamlist:emails" + roomOptionSpamlistHosts = "spamlist:hosts" + roomOptionSpamlistLocalparts = "spamlist:mailboxes" ) type roomSettings map[string]string @@ -82,24 +82,24 @@ func (s roomSettings) NoFiles() bool { return utils.Bool(s.Get(roomOptionNoFiles)) } -func (s roomSettings) SecuritySMTP() bool { - return utils.Bool(s.Get(roomOptionSecuritySMTP)) +func (s roomSettings) SpamcheckSMTP() bool { + return utils.Bool(s.Get(roomOptionSpamcheckSMTP)) } -func (s roomSettings) SecurityMX() bool { - return utils.Bool(s.Get(roomOptionSecurityMX)) +func (s roomSettings) SpamcheckMX() bool { + return utils.Bool(s.Get(roomOptionSpamcheckMX)) } -func (s roomSettings) SpamEmails() []string { - return utils.StringSlice(s.Get(roomOptionSpamEmails)) +func (s roomSettings) SpamlistEmails() []string { + return utils.StringSlice(s.Get(roomOptionSpamlistEmails)) } -func (s roomSettings) SpamHosts() []string { - return utils.StringSlice(s.Get(roomOptionSpamHosts)) +func (s roomSettings) SpamlistHosts() []string { + return utils.StringSlice(s.Get(roomOptionSpamlistHosts)) } -func (s roomSettings) SpamLocalparts() []string { - return utils.StringSlice(s.Get(roomOptionSpamLocalparts)) +func (s roomSettings) SpamlistLocalparts() []string { + return utils.StringSlice(s.Get(roomOptionSpamlistLocalparts)) } // ContentOptions converts room display settings to content options diff --git a/smtp/msasession.go b/smtp/msasession.go index 1c4df92..51d98be 100644 --- a/smtp/msasession.go +++ b/smtp/msasession.go @@ -58,7 +58,7 @@ func (s *msasession) Rcpt(to string) error { return smtp.ErrAuthRequired } - validations := s.bot.GetOptions(roomID) + validations := s.bot.GetIFOptions(roomID) if !s.validate(validations) { return smtp.ErrAuthRequired } @@ -81,15 +81,15 @@ func (s *msasession) parseAttachments(parts []*enmime.Part) []*utils.File { return files } -func (s *msasession) validate(options utils.ValidationOptions) bool { +func (s *msasession) validate(options utils.IncomingFilteringOptions) bool { spam := validator.Spam{ - Emails: options.SpamEmails(), - Hosts: options.SpamHosts(), - Localparts: options.SpamLocalparts(), + Emails: options.SpamlistEmails(), + Hosts: options.SpamlistHosts(), + Localparts: options.SpamlistLocalparts(), } enforce := validator.Enforce{ - MX: options.SecurityMX(), - SMTP: options.SecuritySMTP(), + MX: options.SpamcheckMX(), + SMTP: options.SpamcheckMX(), } v := validator.New(spam, enforce, s.to, s.log) diff --git a/smtp/mta.go b/smtp/mta.go index f095d91..c219b77 100644 --- a/smtp/mta.go +++ b/smtp/mta.go @@ -16,7 +16,7 @@ import ( type Bot interface { AllowAuth(string, string) bool GetMapping(string) (id.RoomID, bool) - GetOptions(id.RoomID) utils.ValidationOptions + GetIFOptions(id.RoomID) utils.IncomingFilteringOptions Send2Matrix(ctx context.Context, email *utils.Email, incoming bool) error SetMTA(mta utils.MTA) } diff --git a/utils/email.go b/utils/email.go index 6f7e279..12c9814 100644 --- a/utils/email.go +++ b/utils/email.go @@ -19,13 +19,13 @@ type MTA interface { Send(from, to, data string) error } -// ValidationOptions for incoming mail -type ValidationOptions interface { - SecuritySMTP() bool - SecurityMX() bool - SpamEmails() []string - SpamHosts() []string - SpamLocalparts() []string +// IncomingFilteringOptions for incoming mail +type IncomingFilteringOptions interface { + SpamcheckSMTP() bool + SpamcheckMX() bool + SpamlistEmails() []string + SpamlistHosts() []string + SpamlistLocalparts() []string } // Email object