Smail/server/dto/parsemail/dkim.go
Jinnrry e194d6ecfd
feature/v2.8.3 (#269)
1.优化垃圾邮件处理
2.升级所有依赖,go版本升级到1.24
2025-04-20 09:59:56 +08:00

110 lines
2.2 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package parsemail
import (
"bytes"
"crypto"
"crypto/x509"
"encoding/pem"
"fmt"
"github.com/Jinnrry/pmail/config"
"github.com/Jinnrry/pmail/utils/consts"
"github.com/Jinnrry/pmail/utils/context"
"github.com/emersion/go-msgauth/dkim"
log "github.com/sirupsen/logrus"
"golang.org/x/crypto/ed25519"
"io"
"os"
"strings"
)
type Dkim struct {
privateKey crypto.Signer
}
var instance *Dkim
func Init() {
privateKey, err := loadPrivateKey(config.Instance.DkimPrivateKeyPath)
if err != nil {
panic(config.Instance.DkimPrivateKeyPath +
" DKIM load fail! Please set dkim! dkim私钥加载失败!请先设置dkim秘钥" +
err.Error())
}
instance = &Dkim{
privateKey: privateKey,
}
}
func loadPrivateKey(path string) (crypto.Signer, error) {
b, err := os.ReadFile(path)
if err != nil {
return nil, err
}
block, _ := pem.Decode(b)
if block == nil {
return nil, fmt.Errorf("no PEM data found")
}
switch strings.ToUpper(block.Type) {
case "PRIVATE KEY":
k, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
return k.(crypto.Signer), nil
case "RSA PRIVATE KEY":
return x509.ParsePKCS1PrivateKey(block.Bytes)
case "EDDSA PRIVATE KEY":
if len(block.Bytes) != ed25519.PrivateKeySize {
return nil, fmt.Errorf("invalid Ed25519 private key size")
}
return ed25519.PrivateKey(block.Bytes), nil
default:
return nil, fmt.Errorf("unknown private key type: '%v'", block.Type)
}
}
func (p *Dkim) Sign(msgData string) []byte {
var b bytes.Buffer
r := strings.NewReader(msgData)
options := &dkim.SignOptions{
Domain: config.Instance.Domain,
Selector: "default",
Signer: p.privateKey,
}
if err := dkim.Sign(&b, r, options); err != nil {
log.Errorf("%+v", err)
return []byte(msgData)
}
return b.Bytes()
}
func Check(ctx *context.Context, mail io.Reader) bool {
verifications, err := dkim.Verify(mail)
if err != nil {
log.WithContext(ctx).Warnf("DKIM Error:%v", err)
}
if len(verifications) == 0 {
return false
}
for _, v := range verifications {
if v.Domain == consts.TEST_DOMAIN {
return true
}
if v.Err == nil {
log.Println("Valid signature for:", v.Domain)
} else {
log.Println("Invalid signature for:", v.Domain, v.Err)
return false
}
}
return true
}