dkim.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. package parsemail
  2. import (
  3. "bytes"
  4. "crypto"
  5. "crypto/x509"
  6. "encoding/pem"
  7. "fmt"
  8. "github.com/emersion/go-msgauth/dkim"
  9. log "github.com/sirupsen/logrus"
  10. "golang.org/x/crypto/ed25519"
  11. "io"
  12. "os"
  13. "pmail/config"
  14. "pmail/utils/consts"
  15. "strings"
  16. )
  17. type Dkim struct {
  18. privateKey crypto.Signer
  19. }
  20. var instance *Dkim
  21. func Init() {
  22. privateKey, err := loadPrivateKey(config.Instance.DkimPrivateKeyPath)
  23. if err != nil {
  24. panic("DKIM load fail! Please set dkim! dkim私钥加载失败!请先设置dkim秘钥")
  25. }
  26. instance = &Dkim{
  27. privateKey: privateKey,
  28. }
  29. }
  30. func loadPrivateKey(path string) (crypto.Signer, error) {
  31. b, err := os.ReadFile(path)
  32. if err != nil {
  33. return nil, err
  34. }
  35. block, _ := pem.Decode(b)
  36. if block == nil {
  37. return nil, fmt.Errorf("no PEM data found")
  38. }
  39. switch strings.ToUpper(block.Type) {
  40. case "PRIVATE KEY":
  41. k, err := x509.ParsePKCS8PrivateKey(block.Bytes)
  42. if err != nil {
  43. return nil, err
  44. }
  45. return k.(crypto.Signer), nil
  46. case "RSA PRIVATE KEY":
  47. return x509.ParsePKCS1PrivateKey(block.Bytes)
  48. case "EDDSA PRIVATE KEY":
  49. if len(block.Bytes) != ed25519.PrivateKeySize {
  50. return nil, fmt.Errorf("invalid Ed25519 private key size")
  51. }
  52. return ed25519.PrivateKey(block.Bytes), nil
  53. default:
  54. return nil, fmt.Errorf("unknown private key type: '%v'", block.Type)
  55. }
  56. }
  57. func (p *Dkim) Sign(msgData string) []byte {
  58. var b bytes.Buffer
  59. r := strings.NewReader(msgData)
  60. options := &dkim.SignOptions{
  61. Domain: config.Instance.Domain,
  62. Selector: "default",
  63. Signer: p.privateKey,
  64. }
  65. if err := dkim.Sign(&b, r, options); err != nil {
  66. log.Errorf("%+v", err)
  67. return []byte(msgData)
  68. }
  69. return b.Bytes()
  70. }
  71. func Check(mail io.Reader) bool {
  72. verifications, err := dkim.Verify(mail)
  73. if err != nil {
  74. log.Println(err)
  75. }
  76. for _, v := range verifications {
  77. if v.Domain == consts.TEST_DOMAIN {
  78. return true
  79. }
  80. if v.Err == nil {
  81. log.Println("Valid signature for:", v.Domain)
  82. } else {
  83. log.Println("Invalid signature for:", v.Domain, v.Err)
  84. return false
  85. }
  86. }
  87. return true
  88. }