Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12d2fee2d4 | ||
|
|
ddf2460dbd | ||
|
|
3f1fd00fb6 | ||
|
|
ac9c27aa32 | ||
|
|
1e9558c1fc | ||
|
|
174930fc90 | ||
|
|
0559978fa2 | ||
|
|
f54b87c1f7 | ||
|
|
2ac6c64d13 |
3
Makefile
3
Makefile
@@ -1,6 +1,7 @@
|
||||
### CI vars
|
||||
CI_LOGIN_COMMAND = @echo "Not a CI, skip login"
|
||||
CI_REGISTRY_IMAGE ?= registry.gitlab.com/etke.cc/postmoogle
|
||||
REGISTRY_IMAGE ?= registry.etke.cc/etke.cc/postmoogle
|
||||
CI_COMMIT_TAG ?= latest
|
||||
# for main branch it must be set explicitly
|
||||
ifeq ($(CI_COMMIT_TAG), main)
|
||||
@@ -51,4 +52,4 @@ login:
|
||||
# docker build
|
||||
docker:
|
||||
docker buildx create --use
|
||||
docker buildx build --platform linux/arm64/v8,linux/amd64 --push -t ${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG} .
|
||||
docker buildx build --platform linux/arm64/v8,linux/amd64 --push -t ${CI_REGISTRY_IMAGE}:${CI_COMMIT_TAG} -t ${REGISTRY_IMAGE}:${CI_COMMIT_TAG} .
|
||||
|
||||
@@ -119,12 +119,14 @@ func (b *Bot) IsTrusted(addr net.Addr) bool {
|
||||
}
|
||||
}
|
||||
|
||||
b.log.Debug("address %s is NOT trusted", ip)
|
||||
return false
|
||||
}
|
||||
|
||||
// Ban an address
|
||||
func (b *Bot) Ban(addr net.Addr) {
|
||||
if !b.cfg.BanlistEnalbed() {
|
||||
return
|
||||
}
|
||||
if b.IsTrusted(addr) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"maunium.net/go/mautrix/event"
|
||||
"maunium.net/go/mautrix/format"
|
||||
"maunium.net/go/mautrix/id"
|
||||
|
||||
@@ -284,6 +285,10 @@ func (b *Bot) handle(ctx context.Context) {
|
||||
b.Error(ctx, evt.RoomID, "cannot read message")
|
||||
return
|
||||
}
|
||||
// ignore any type apart from text (e.g. reactions, redactions, notices, etc)
|
||||
if content.MsgType != event.MsgText {
|
||||
return
|
||||
}
|
||||
message := strings.TrimSpace(content.Body)
|
||||
commandSlice := b.parseCommand(message, true)
|
||||
if commandSlice == nil {
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gitlab.com/etke.cc/go/logger"
|
||||
"gitlab.com/etke.cc/linkpearl"
|
||||
"maunium.net/go/mautrix/id"
|
||||
@@ -32,15 +30,24 @@ func New(lp *linkpearl.Linkpearl, log *logger.Logger) *Manager {
|
||||
return m
|
||||
}
|
||||
|
||||
// BanlistEnalbed or not
|
||||
func (m *Manager) BanlistEnalbed() bool {
|
||||
return m.ble
|
||||
}
|
||||
|
||||
// GetBot config
|
||||
func (m *Manager) GetBot() Bot {
|
||||
config, err := m.lp.GetAccountData(acBotKey)
|
||||
var err error
|
||||
var config Bot
|
||||
config, err = m.lp.GetAccountData(acBotKey)
|
||||
if err != nil {
|
||||
m.log.Error("cannot get bot settings: %v", utils.UnwrapError(err))
|
||||
}
|
||||
if config == nil {
|
||||
config = make(Bot, 0)
|
||||
return config
|
||||
}
|
||||
m.ble = config.BanlistEnabled()
|
||||
|
||||
return config
|
||||
}
|
||||
@@ -80,6 +87,7 @@ func (m *Manager) GetBanlist() List {
|
||||
}
|
||||
if config == nil {
|
||||
config = make(List, 0)
|
||||
return config
|
||||
}
|
||||
m.bl = config
|
||||
return config
|
||||
@@ -88,7 +96,7 @@ func (m *Manager) GetBanlist() List {
|
||||
// SetBanlist config
|
||||
func (m *Manager) SetBanlist(cfg List) error {
|
||||
if !m.ble {
|
||||
return fmt.Errorf("banlist is disabled, kupo")
|
||||
return nil
|
||||
}
|
||||
|
||||
m.mu.Lock("banlist")
|
||||
@@ -109,6 +117,7 @@ func (m *Manager) GetGreylist() List {
|
||||
}
|
||||
if config == nil {
|
||||
config = make(List, 0)
|
||||
return config
|
||||
}
|
||||
|
||||
return config
|
||||
|
||||
12
bot/data.go
12
bot/data.go
@@ -38,9 +38,11 @@ func (b *Bot) migrate() error {
|
||||
}
|
||||
|
||||
func (b *Bot) syncRooms() error {
|
||||
adminRooms := []id.RoomID{}
|
||||
|
||||
adminRoom := b.cfg.GetBot().AdminRoom()
|
||||
if adminRoom != "" {
|
||||
b.adminRooms = append(b.adminRooms, adminRoom)
|
||||
adminRooms = append(adminRooms, adminRoom)
|
||||
}
|
||||
|
||||
resp, err := b.lp.GetClient().JoinedRooms()
|
||||
@@ -60,9 +62,10 @@ func (b *Bot) syncRooms() error {
|
||||
}
|
||||
|
||||
if cfg.Owner() != "" && b.allowAdmin(id.UserID(cfg.Owner()), "") {
|
||||
b.adminRooms = append(b.adminRooms, roomID)
|
||||
adminRooms = append(adminRooms, roomID)
|
||||
}
|
||||
}
|
||||
b.adminRooms = adminRooms
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -101,3 +104,8 @@ func (b *Bot) initBotUsers() ([]string, error) {
|
||||
cfg.Set(config.BotUsers, "@*:"+homeserver)
|
||||
return cfg.Users(), b.cfg.SetBot(cfg)
|
||||
}
|
||||
|
||||
// SyncRooms and mailboxes
|
||||
func (b *Bot) SyncRooms() {
|
||||
b.syncRooms() //nolint:errcheck // nothing can be done here
|
||||
}
|
||||
|
||||
36
bot/email.go
36
bot/email.go
@@ -44,7 +44,7 @@ func (b *Bot) Sendmail(eventID id.EventID, from, to, data string) (bool, error)
|
||||
err := b.sendmail(from, to, data)
|
||||
if err != nil {
|
||||
if strings.HasPrefix(err.Error(), "4") {
|
||||
b.log.Debug("email %s (from=%s to=%s) was added to the queue: %v", eventID, from, to, err)
|
||||
b.log.Info("email %s (from=%s to=%s) was added to the queue: %v", eventID, from, to, err)
|
||||
return true, b.q.Add(eventID.String(), from, to, data)
|
||||
}
|
||||
return false, err
|
||||
@@ -128,7 +128,6 @@ func (b *Bot) IncomingEmail(ctx context.Context, email *email.Email) error {
|
||||
|
||||
b.setThreadID(roomID, email.MessageID, threadID)
|
||||
b.setLastEventID(roomID, threadID, eventID)
|
||||
threadID = eventID
|
||||
|
||||
if !cfg.NoFiles() {
|
||||
b.sendFiles(ctx, roomID, email.Files, cfg.NoThreads(), threadID)
|
||||
@@ -179,7 +178,7 @@ func (b *Bot) SendEmailReply(ctx context.Context) {
|
||||
|
||||
meta.MessageID = email.MessageID(evt.ID, meta.FromDomain)
|
||||
meta.References = meta.References + " " + meta.MessageID
|
||||
b.log.Debug("send email reply: %+v", meta)
|
||||
b.log.Info("sending email reply: %+v", meta)
|
||||
eml := email.New(meta.MessageID, meta.InReplyTo, meta.References, meta.Subject, meta.From, meta.To, meta.RcptTo, meta.CC, body, htmlBody, nil)
|
||||
data := eml.Compose(b.cfg.GetBot().DKIMPrivateKey())
|
||||
if data == "" {
|
||||
@@ -189,7 +188,7 @@ func (b *Bot) SendEmailReply(ctx context.Context) {
|
||||
|
||||
var queued bool
|
||||
var hasErr bool
|
||||
recipients := meta.Recipients()
|
||||
recipients := meta.Recipients
|
||||
for _, to := range recipients {
|
||||
queued, err = b.Sendmail(evt.ID, meta.From, to, data)
|
||||
if queued {
|
||||
@@ -222,6 +221,7 @@ type parentEmail struct {
|
||||
InReplyTo string
|
||||
References string
|
||||
Subject string
|
||||
Recipients []string
|
||||
}
|
||||
|
||||
// fixtofrom attempts to "fix" or rather reverse the To, From and CC headers
|
||||
@@ -229,7 +229,7 @@ type parentEmail struct {
|
||||
// that will be sent from postmoogle.
|
||||
// To do so, we need to reverse From and To headers, but Cc should be adjusted as well,
|
||||
// thus that hacky workaround below:
|
||||
func (e *parentEmail) fixtofrom(newSenderMailbox string, domains []string) {
|
||||
func (e *parentEmail) fixtofrom(newSenderMailbox string, domains []string) string {
|
||||
newSenders := make(map[string]string, len(domains))
|
||||
for _, domain := range domains {
|
||||
sender := newSenderMailbox + "@" + domain
|
||||
@@ -271,11 +271,28 @@ func (e *parentEmail) fixtofrom(newSenderMailbox string, domains []string) {
|
||||
e.CC = strings.ReplaceAll(e.CC, newSender, originalFrom)
|
||||
}
|
||||
}
|
||||
|
||||
return previousSender
|
||||
}
|
||||
|
||||
// Recipients returns list of recipients (to, cc)
|
||||
func (e parentEmail) Recipients() []string {
|
||||
return append(email.AddressList(e.CC), e.To)
|
||||
func (e *parentEmail) calculateRecipients(from string) {
|
||||
recipients := map[string]struct{}{}
|
||||
recipients[e.From] = struct{}{}
|
||||
|
||||
for _, addr := range strings.Split(email.Address(e.To), ",") {
|
||||
recipients[addr] = struct{}{}
|
||||
}
|
||||
for _, addr := range email.AddressList(e.CC) {
|
||||
recipients[addr] = struct{}{}
|
||||
}
|
||||
delete(recipients, from)
|
||||
|
||||
rcpts := make([]string, 0, len(recipients))
|
||||
for rcpt := range recipients {
|
||||
rcpts = append(rcpts, rcpt)
|
||||
}
|
||||
|
||||
e.Recipients = rcpts
|
||||
}
|
||||
|
||||
func (b *Bot) getParentEvent(evt *event.Event) (id.EventID, *event.Event) {
|
||||
@@ -331,7 +348,8 @@ func (b *Bot) getParentEmail(evt *event.Event, newFromMailbox string) *parentEma
|
||||
parent.RcptTo = utils.EventField[string](&parentEvt.Content, eventRcptToKey)
|
||||
parent.InReplyTo = utils.EventField[string](&parentEvt.Content, eventMessageIDkey)
|
||||
parent.References = utils.EventField[string](&parentEvt.Content, eventReferencesKey)
|
||||
parent.fixtofrom(newFromMailbox, b.domains)
|
||||
senderEmail := parent.fixtofrom(newFromMailbox, b.domains)
|
||||
parent.calculateRecipients(senderEmail)
|
||||
parent.MessageID = email.MessageID(parentEvt.ID, parent.FromDomain)
|
||||
if parent.InReplyTo == "" {
|
||||
parent.InReplyTo = parent.MessageID
|
||||
|
||||
@@ -67,7 +67,7 @@ func (q *Queue) Process() {
|
||||
return
|
||||
}
|
||||
if dequeue := q.try(itemkey, maxRetries); dequeue {
|
||||
q.log.Debug("email %q has been delivered", id)
|
||||
q.log.Info("email %q has been delivered", id)
|
||||
err = q.Remove(id)
|
||||
if err != nil {
|
||||
q.log.Error("cannot dequeue email %q: %v", id, err)
|
||||
|
||||
@@ -60,7 +60,7 @@ func (q *Queue) Remove(id string) error {
|
||||
|
||||
q.mu.Lock(itemkey)
|
||||
defer q.mu.Unlock(itemkey)
|
||||
return q.lp.SetAccountData(itemkey, nil)
|
||||
return q.lp.SetAccountData(itemkey, map[string]string{})
|
||||
}
|
||||
|
||||
// try to send email
|
||||
@@ -85,11 +85,11 @@ func (q *Queue) try(itemkey string, maxRetries int) bool {
|
||||
|
||||
err = q.sendmail(item["from"], item["to"], item["data"])
|
||||
if err == nil {
|
||||
q.log.Debug("email %q from queue was delivered")
|
||||
q.log.Info("email %q from queue was delivered")
|
||||
return true
|
||||
}
|
||||
|
||||
q.log.Debug("attempted to deliver email id=%q, retry=%q, but it's not ready yet: %v", item["id"], item["attempts"], err)
|
||||
q.log.Info("attempted to deliver email id=%q, retry=%q, but it's not ready yet: %v", item["id"], item["attempts"], err)
|
||||
attempts++
|
||||
item["attempts"] = strconv.Itoa(attempts)
|
||||
err = q.lp.SetAccountData(itemkey, item)
|
||||
|
||||
@@ -153,6 +153,11 @@ func initCron() {
|
||||
if err != nil {
|
||||
log.Error("cannot start queue processing cronjob: %v", err)
|
||||
}
|
||||
|
||||
err = cron.AddJob("*/5 * * * *", mxb.SyncRooms)
|
||||
if err != nil {
|
||||
log.Error("cannot start sync rooms cronjob: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func initShutdown(quit chan struct{}) {
|
||||
|
||||
@@ -41,7 +41,7 @@ func New(messageID, inReplyTo, references, subject, from, to, rcptto, cc, text,
|
||||
From: Address(from),
|
||||
To: Address(to),
|
||||
CC: AddressList(cc),
|
||||
RcptTo: rcptto,
|
||||
RcptTo: Address(rcptto),
|
||||
Subject: subject,
|
||||
Text: text,
|
||||
HTML: html,
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"net/mail"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"maunium.net/go/mautrix/id"
|
||||
@@ -26,6 +27,10 @@ func MessageID(eventID id.EventID, domain string) string {
|
||||
func Address(email string) string {
|
||||
addr, _ := mail.ParseAddress(email) //nolint:errcheck // if it fails here, nothing will help
|
||||
if addr == nil {
|
||||
list := AddressList(email)
|
||||
if len(list) > 0 {
|
||||
return strings.Join(list, ",")
|
||||
}
|
||||
return email
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ func (l *Listener) Accept() (net.Conn, error) {
|
||||
continue
|
||||
}
|
||||
|
||||
l.log.Debug("accepted connection from %q", conn.RemoteAddr())
|
||||
l.log.Info("accepted connection from %q", conn.RemoteAddr())
|
||||
return conn, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,8 +80,8 @@ func NewManager(cfg *Config) *Manager {
|
||||
if len(cfg.Domains) == 1 {
|
||||
s.Domain = cfg.Domains[0]
|
||||
}
|
||||
if log.GetLevel() == "DEBUG" || log.GetLevel() == "TRACE" {
|
||||
s.Debug = loggerWriter{func(s string) { log.Debug(s) }}
|
||||
if log.GetLevel() == "INFO" || log.GetLevel() == "DEBUG" || log.GetLevel() == "TRACE" {
|
||||
s.Debug = loggerWriter{func(s string) { log.Info(s) }}
|
||||
}
|
||||
|
||||
m := &Manager{
|
||||
|
||||
Reference in New Issue
Block a user