This commit is contained in:
Aine
2022-09-05 17:02:00 +03:00
parent fda0d62087
commit 12a2d4c6f9
7 changed files with 163 additions and 5 deletions

View File

@@ -15,6 +15,7 @@ const (
commandHelp = "help"
commandStop = "stop"
commandSend = "send"
commandDKIM = "dkim"
commandUsers = botOptionUsers
commandDelete = "delete"
commandMailboxes = "mailboxes"
@@ -132,6 +133,11 @@ func (b *Bot) initCommands() commandList {
description: "Get or set allowed users",
allowed: b.allowAdmin,
},
{
key: commandDKIM,
description: "Get DKIM signature",
allowed: b.allowAdmin,
},
{
key: commandMailboxes,
description: "Show the list of all mailboxes",
@@ -163,6 +169,8 @@ func (b *Bot) handleCommand(ctx context.Context, evt *event.Event, commandSlice
b.runStop(ctx)
case commandSend:
b.runSend(ctx, commandSlice)
case commandDKIM:
b.runDKIM(ctx)
case commandUsers:
b.runUsers(ctx, commandSlice)
case commandDelete:
@@ -272,7 +280,6 @@ func (b *Bot) runSend(ctx context.Context, commandSlice []string) {
subject := lines[1]
body := strings.Join(lines[2:], "\n")
b.log.Debug("to=%s subject=%s body=%s", to, subject, body)
err := b.Send2Email(ctx, to, subject, body)
if err != nil {
b.Error(ctx, evt.RoomID, "cannot send email: %v", err)

View File

@@ -6,6 +6,7 @@ import (
"sort"
"strings"
"gitlab.com/etke.cc/go/secgen"
"maunium.net/go/mautrix/id"
"gitlab.com/etke.cc/postmoogle/utils"
@@ -130,3 +131,32 @@ func (b *Bot) runUsers(ctx context.Context, commandSlice []string) {
b.allowedUsers = allowedUsers
b.SendNotice(ctx, evt.RoomID, "allowed users updated")
}
func (b *Bot) runDKIM(ctx context.Context) {
evt := eventFromContext(ctx)
cfg := b.getBotSettings()
signature := cfg.DKIMSignature()
if signature == "" {
var private string
var derr error
signature, private, derr = secgen.DKIM()
if derr != nil {
b.Error(ctx, evt.RoomID, "cannot generate DKIM signature: %v", derr)
return
}
cfg.Set(botOptionDKIMSignature, signature)
cfg.Set(botOptionDKIMPrivateKey, private)
err := b.setBotSettings(cfg)
if err != nil {
b.Error(ctx, evt.RoomID, "cannot save bot options: %v", err)
return
}
}
b.SendNotice(ctx, evt.RoomID, fmt.Sprintf(
"DKIM signature is: `%s`.\n"+
"You need to add it to your DNS records (if not already):\n"+
"Add new DNS record with type = `TXT`, key (subdomain/from): `postmoogle._domainkey` and value (to):\n ```\n%s\n```\n"+
"Without that record other email servers may reject your emails as spam, kupo.",
signature, signature))
}

View File

@@ -2,11 +2,15 @@ package bot
import (
"context"
"crypto"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"strings"
"time"
"github.com/emersion/go-msgauth/dkim"
"maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/format"
"maunium.net/go/mautrix/id"
@@ -234,9 +238,45 @@ func (b *Bot) Send2Email(ctx context.Context, to, subject, body string) error {
msg.WriteString(body)
msg.WriteString("\r\n")
msg = b.signDKIM(msg)
return b.mta.Send(from, to, msg.String())
}
func (b *Bot) signDKIM(body strings.Builder) strings.Builder {
privkey := b.getBotSettings().DKIMPrivateKey()
if privkey == "" {
b.log.Warn("DKIM private key not found, email will be sent unsigned")
return body
}
pemblock, _ := pem.Decode([]byte(privkey))
if pemblock == nil {
b.log.Error("cannot decode DKIM private key")
return body
}
parsedkey, err := x509.ParsePKCS8PrivateKey(pemblock.Bytes)
if err != nil {
b.log.Error("cannot parse PKCS8 private key: %v", err)
return body
}
signer := parsedkey.(crypto.Signer)
options := &dkim.SignOptions{
Domain: b.domain,
Selector: "postmoogle",
Signer: signer,
}
var msg strings.Builder
err = dkim.Sign(&msg, strings.NewReader(body.String()), options)
if err != nil {
b.log.Error("cannot sign email: %v", err)
return body
}
return msg
}
func (b *Bot) sendFiles(ctx context.Context, roomID id.RoomID, files []*utils.File, noThreads bool, parentID id.EventID) {
for _, file := range files {
req := file.Convert()

View File

@@ -11,7 +11,9 @@ const acBotSettingsKey = "cc.etke.postmoogle.config"
// bot options keys
const (
botOptionUsers = "users"
botOptionUsers = "users"
botOptionDKIMSignature = "dkim.pub"
botOptionDKIMPrivateKey = "dkim.pem"
)
type botSettings map[string]string
@@ -40,6 +42,16 @@ func (s botSettings) Users() []string {
return []string{value}
}
// DKIMSignature (DNS TXT record)
func (s botSettings) DKIMSignature() string {
return s.Get(botOptionDKIMSignature)
}
// DKIMPrivateKey keep it secret
func (s botSettings) DKIMPrivateKey() string {
return s.Get(botOptionDKIMPrivateKey)
}
func (b *Bot) initBotUsers() ([]string, error) {
config := b.getBotSettings()
cfgUsers := config.Users()