move email composing to utils

This commit is contained in:
Aine
2022-09-05 20:38:58 +03:00
parent 2427d41ae3
commit 7d435f7ba8
2 changed files with 87 additions and 74 deletions

View File

@@ -2,15 +2,10 @@ package bot
import ( import (
"context" "context"
"crypto"
"crypto/x509"
"encoding/pem"
"errors" "errors"
"fmt" "fmt"
"strings" "strings"
"time"
"github.com/emersion/go-msgauth/dkim"
"maunium.net/go/mautrix/event" "maunium.net/go/mautrix/event"
"maunium.net/go/mautrix/format" "maunium.net/go/mautrix/format"
"maunium.net/go/mautrix/id" "maunium.net/go/mautrix/id"
@@ -206,75 +201,11 @@ func (b *Bot) Send2Email(ctx context.Context, to, subject, body string) error {
body = b.getBody(content) body = b.getBody(content)
} }
var msg strings.Builder ID := evt.ID.String()[1:] + "@" + b.domain
msg.WriteString("From: ") data := utils.
msg.WriteString(from) NewEmail(ID, inReplyTo, subject, from, to, body, "", nil).
msg.WriteString("\r\n") Compose(b.getBotSettings().DKIMPrivateKey())
return b.mta.Send(from, to, data)
msg.WriteString("To: ")
msg.WriteString(to)
msg.WriteString("\r\n")
msg.WriteString("Message-Id: ")
msg.WriteString(evt.ID.String()[1:] + "@" + b.domain)
msg.WriteString("\r\n")
msg.WriteString("Date: ")
msg.WriteString(time.Now().UTC().Format(time.RFC1123Z))
msg.WriteString("\r\n")
if inReplyTo != "" {
msg.WriteString("In-Reply-To: ")
msg.WriteString(inReplyTo)
msg.WriteString("\r\n")
}
msg.WriteString("Subject: ")
msg.WriteString(subject)
msg.WriteString("\r\n")
msg.WriteString("\r\n")
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) { func (b *Bot) sendFiles(ctx context.Context, roomID id.RoomID, files []*utils.File, noThreads bool, parentID id.EventID) {

View File

@@ -1,5 +1,15 @@
package utils package utils
import (
"crypto"
"crypto/x509"
"encoding/pem"
"strings"
"time"
"github.com/emersion/go-msgauth/dkim"
)
// MTA is mail transfer agent // MTA is mail transfer agent
type MTA interface { type MTA interface {
Send(from, to, data string) error Send(from, to, data string) error
@@ -7,6 +17,9 @@ type MTA interface {
// Email object // Email object
type Email struct { type Email struct {
data strings.Builder
Date string
MessageID string MessageID string
InReplyTo string InReplyTo string
From string From string
@@ -20,6 +33,7 @@ type Email struct {
// NewEmail constructs Email object // NewEmail constructs Email object
func NewEmail(messageID, inReplyTo, subject, from, to, text, html string, files []*File) *Email { func NewEmail(messageID, inReplyTo, subject, from, to, text, html string, files []*File) *Email {
email := &Email{ email := &Email{
Date: time.Now().UTC().Format(time.RFC1123Z),
MessageID: messageID, MessageID: messageID,
InReplyTo: inReplyTo, InReplyTo: inReplyTo,
From: from, From: from,
@@ -40,3 +54,71 @@ func NewEmail(messageID, inReplyTo, subject, from, to, text, html string, files
return email return email
} }
// Compose converts email object to string and (optionally) signs it
func (e *Email) Compose(privkey string) string {
domain := strings.SplitN(e.From, "@", 2)[0]
e.data.WriteString("From: ")
e.data.WriteString(e.From)
e.data.WriteString("\r\n")
e.data.WriteString("To: ")
e.data.WriteString(e.To)
e.data.WriteString("\r\n")
e.data.WriteString("Message-Id: ")
e.data.WriteString(e.MessageID)
e.data.WriteString("\r\n")
e.data.WriteString("Date: ")
e.data.WriteString(e.Date)
e.data.WriteString("\r\n")
if e.InReplyTo != "" {
e.data.WriteString("In-Reply-To: ")
e.data.WriteString(e.InReplyTo)
e.data.WriteString("\r\n")
}
e.data.WriteString("Subject: ")
e.data.WriteString(e.Subject)
e.data.WriteString("\r\n")
e.data.WriteString("\r\n")
e.data.WriteString(e.Text)
e.data.WriteString("\r\n")
e.sign(domain, privkey)
return e.data.String()
}
func (e *Email) sign(domain, privkey string) {
if privkey == "" {
return
}
pemblock, _ := pem.Decode([]byte(privkey))
if pemblock == nil {
return
}
parsedkey, err := x509.ParsePKCS8PrivateKey(pemblock.Bytes)
if err != nil {
return
}
signer := parsedkey.(crypto.Signer)
options := &dkim.SignOptions{
Domain: domain,
Selector: "postmoogle",
Signer: signer,
}
var msg strings.Builder
err = dkim.Sign(&msg, strings.NewReader(e.data.String()), options)
if err != nil {
return
}
e.data = msg
}