From 0bd2fc525e8754e0dedb5a382bc67c58e7ec99a9 Mon Sep 17 00:00:00 2001 From: Aine Date: Mon, 5 Feb 2024 21:49:30 +0200 Subject: [PATCH] fix access checks; fix duplicate metadata message; better email sanitization --- bot/access.go | 28 +++++++++++++++++++--------- bot/email.go | 32 +++++++++++++++++--------------- bot/sync.go | 3 +-- smtp/session.go | 2 +- 4 files changed, 38 insertions(+), 27 deletions(-) diff --git a/bot/access.go b/bot/access.go index 87d5fbf..bc32d76 100644 --- a/bot/access.go +++ b/bot/access.go @@ -22,14 +22,24 @@ func parseMXIDpatterns(patterns []string, defaultPattern string) ([]*regexp.Rege return mxidwc.ParsePatterns(patterns) } -func (b *Bot) allowUsers(actorID id.UserID) bool { - if len(b.allowedUsers) != 0 { - if !mxidwc.Match(actorID.String(), b.allowedUsers) { - return false - } +func (b *Bot) allowUsers(actorID id.UserID, targetRoomID id.RoomID) bool { + // first, check if it's an allowed user + if mxidwc.Match(actorID.String(), b.allowedUsers) { + return true } - return true + // second, check if it's an admin (admin may not fit the allowed users pattern) + if b.allowAdmin(actorID, targetRoomID) { + return true + } + + // then, check if it's the owner (same as above) + cfg, err := b.cfg.GetRoom(targetRoomID) + if err == nil && cfg.Owner() == actorID.String() { + return true + } + + return false } func (b *Bot) allowAnyone(_ id.UserID, _ id.RoomID) bool { @@ -37,7 +47,7 @@ func (b *Bot) allowAnyone(_ id.UserID, _ id.RoomID) bool { } func (b *Bot) allowOwner(actorID id.UserID, targetRoomID id.RoomID) bool { - if !b.allowUsers(actorID) { + if !b.allowUsers(actorID, targetRoomID) { return false } cfg, err := b.cfg.GetRoom(targetRoomID) @@ -59,7 +69,7 @@ func (b *Bot) allowAdmin(actorID id.UserID, _ id.RoomID) bool { } func (b *Bot) allowSend(actorID id.UserID, targetRoomID id.RoomID) bool { - if !b.allowUsers(actorID) { + if !b.allowUsers(actorID, targetRoomID) { return false } @@ -73,7 +83,7 @@ func (b *Bot) allowSend(actorID id.UserID, targetRoomID id.RoomID) bool { } func (b *Bot) allowReply(actorID id.UserID, targetRoomID id.RoomID) bool { - if !b.allowUsers(actorID) { + if !b.allowUsers(actorID, targetRoomID) { return false } diff --git a/bot/email.go b/bot/email.go index c69ad87..0b1061d 100644 --- a/bot/email.go +++ b/bot/email.go @@ -3,7 +3,9 @@ package bot import ( "context" "errors" + "fmt" "strings" + "time" "gitlab.com/etke.cc/linkpearl" "maunium.net/go/mautrix/event" @@ -71,7 +73,7 @@ func (b *Bot) Sendmail(eventID id.EventID, from, to, data string) (bool, error) return false, err } - log.Warn().Err(err).Msg("email delivery succeeded") + log.Info().Msg("email delivery succeeded") return false, nil } @@ -202,7 +204,7 @@ func (b *Bot) sendAutoreply(roomID id.RoomID, threadID id.EventID) { } evt := &event.Event{ - ID: threadID + "-autoreply", + ID: id.EventID(fmt.Sprintf("%s-autoreply-%s", threadID, time.Now().UTC().Format("20060102T150405Z"))), RoomID: roomID, Content: event.Content{ Parsed: &event.MessageEventContent{ @@ -256,17 +258,17 @@ func (b *Bot) sendAutoreply(roomID id.RoomID, threadID id.EventID) { queued, err = b.Sendmail(evt.ID, meta.From, to, data) if queued { b.log.Info().Err(err).Str("from", meta.From).Str("to", to).Msg("email has been queued") - b.saveSentMetadata(ctx, queued, meta.ThreadID, recipients, eml, cfg, "Autoreply has been sent (queued)") + b.saveSentMetadata(ctx, queued, meta.ThreadID, recipients, eml, cfg, "Autoreply has been sent to "+to+" (queued)") continue } if err != nil { - b.Error(ctx, "cannot send email: %v", err) + b.Error(ctx, "cannot send email to %q: %v", to, err) continue } - } - b.saveSentMetadata(ctx, queued, meta.ThreadID, recipients, eml, cfg, "Autoreply has been sent") + b.saveSentMetadata(ctx, queued, meta.ThreadID, recipients, eml, cfg, "Autoreply has been sent to "+to) + } } func (b *Bot) canReply(ctx context.Context) bool { @@ -345,12 +347,12 @@ func (b *Bot) SendEmailReply(ctx context.Context) { } if err != nil { - b.Error(ctx, "cannot send email: %v", err) + b.Error(ctx, "cannot send email to %q: %v", to, err) continue } - } - b.saveSentMetadata(ctx, queued, meta.ThreadID, recipients, eml, cfg) + b.saveSentMetadata(ctx, queued, meta.ThreadID, recipients, eml, cfg) + } } type parentEmail struct { @@ -420,7 +422,7 @@ func (e *parentEmail) fixtofrom(newSenderMailbox string, domains []string) strin func (e *parentEmail) calculateRecipients(from string, forwardedFrom []string) { recipients := map[string]struct{}{} - recipients[e.From] = struct{}{} + recipients[email.Address(e.From)] = struct{}{} for _, addr := range strings.Split(email.Address(e.To), ",") { recipients[addr] = struct{}{} @@ -436,7 +438,7 @@ func (e *parentEmail) calculateRecipients(from string, forwardedFrom []string) { rcpts := make([]string, 0, len(recipients)) for rcpt := range recipients { - rcpts = append(rcpts, rcpt) + rcpts = append(rcpts, email.Address(rcpt)) } e.Recipients = rcpts @@ -486,10 +488,10 @@ func (b *Bot) getParentEmail(evt *event.Event, newFromMailbox string) *parentEma return parent } - parent.From = linkpearl.EventField[string](&parentEvt.Content, eventFromKey) - parent.To = linkpearl.EventField[string](&parentEvt.Content, eventToKey) - parent.CC = linkpearl.EventField[string](&parentEvt.Content, eventCcKey) - parent.RcptTo = linkpearl.EventField[string](&parentEvt.Content, eventRcptToKey) + parent.From = email.Address(linkpearl.EventField[string](&parentEvt.Content, eventFromKey)) + parent.To = email.Address(linkpearl.EventField[string](&parentEvt.Content, eventToKey)) + parent.CC = email.Address(linkpearl.EventField[string](&parentEvt.Content, eventCcKey)) + parent.RcptTo = email.Address(linkpearl.EventField[string](&parentEvt.Content, eventRcptToKey)) parent.InReplyTo = linkpearl.EventField[string](&parentEvt.Content, eventMessageIDkey) parent.References = linkpearl.EventField[string](&parentEvt.Content, eventReferencesKey) senderEmail := parent.fixtofrom(newFromMailbox, b.domains) diff --git a/bot/sync.go b/bot/sync.go index 91cee1b..fb72a4b 100644 --- a/bot/sync.go +++ b/bot/sync.go @@ -3,7 +3,6 @@ package bot import ( "context" - "gitlab.com/etke.cc/go/mxidwc" "maunium.net/go/mautrix" "maunium.net/go/mautrix/event" ) @@ -33,7 +32,7 @@ func (b *Bot) initSync() { // joinPermit is called by linkpearl when processing "invite" events and deciding if rooms should be auto-joined or not func (b *Bot) joinPermit(evt *event.Event) bool { - if !mxidwc.Match(evt.Sender.String(), b.allowedUsers) { + if !b.allowUsers(evt.Sender, evt.RoomID) { b.log.Debug().Str("userID", evt.Sender.String()).Msg("Rejecting room invitation from unallowed user") return false } diff --git a/smtp/session.go b/smtp/session.go index 18ca0f0..c8a1d12 100644 --- a/smtp/session.go +++ b/smtp/session.go @@ -55,7 +55,7 @@ func (s *incomingSession) Mail(from string, opts smtp.MailOptions) error { s.ban(s.addr) return ErrBanned } - s.from = from + s.from = email.Address(from) s.log.Debug().Str("from", from).Any("options", opts).Msg("incoming mail") return nil }