dkim
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
40
bot/email.go
40
bot/email.go
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user