-
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathhelper.go
146 lines (136 loc) · 4.24 KB
/
helper.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// SPDX-FileCopyrightText: 2023 The go-mail Authors
//
// SPDX-License-Identifier: MIT
package openpgp
import (
"bytes"
"github.com/ProtonMail/gopenpgp/v2/armor"
"github.com/ProtonMail/gopenpgp/v2/constants"
"github.com/ProtonMail/gopenpgp/v2/helper"
"github.com/wneessen/go-mail"
)
const (
// armorComment is the comment string used for the OpenPGP Armor
armorComment = "https://go-mail.dev (OpenPGP based on: https://gopenpgp.org)"
// armorVeersion is the version string used for the OpenPGP Armor
armorVersion = "go-mail-middlware " + Version
)
// pgpInline takes the given mail.Msg and encrypts/signs the body parts
// and attachments and replaces them with an PGP encrypted data blob embedded
// into the mail body following the PGP/Inline scheme
func (m *Middleware) pgpInline(msg *mail.Msg) *mail.Msg {
pp := msg.GetParts()
for _, part := range pp {
c, err := part.GetContent()
if err != nil {
m.config.Logger.Errorf("failed to get part content: %s", err)
continue
}
switch part.GetContentType() {
case mail.TypeTextPlain:
s, err := m.processPlain(string(c))
if err != nil {
m.config.Logger.Errorf("failed to encrypt message part: %s", err)
continue
}
part.SetEncoding(mail.EncodingB64)
part.SetContent(s)
default:
m.config.Logger.Warnf("unsupported type %q. removing message part", string(part.GetContentType()))
part.Delete()
}
}
buf := bytes.Buffer{}
ef := msg.GetEmbeds()
msg.SetEmbeds(nil)
for _, f := range ef {
_, err := f.Writer(&buf)
if err != nil {
m.config.Logger.Errorf("failed to write attachment to memory: %s", err)
continue
}
b, err := m.processBinary(buf.Bytes())
if err != nil {
m.config.Logger.Errorf("failed to encrypt attachment: %s", err)
continue
}
if err := msg.EmbedReader(f.Name, bytes.NewReader([]byte(b))); err != nil {
m.config.Logger.Errorf("failed to embed reader: %s", err)
continue
}
buf.Reset()
}
af := msg.GetAttachments()
msg.SetAttachments(nil)
for _, f := range af {
_, err := f.Writer(&buf)
if err != nil {
m.config.Logger.Errorf("failed to write attachment to memory: %s", err)
continue
}
b, err := m.processBinary(buf.Bytes())
if err != nil {
m.config.Logger.Errorf("failed to encrypt attachment: %s", err)
continue
}
if err := msg.AttachReader(f.Name, bytes.NewReader([]byte(b))); err != nil {
m.config.Logger.Errorf("failed to attach reader: %s", err)
continue
}
buf.Reset()
}
return msg
}
// processBinary is a helper function that processes the given data based on the
// configured Action
func (m *Middleware) processBinary(d []byte) (string, error) {
var ct string
var err error
switch m.config.Action {
case ActionEncrypt:
ct, err = helper.EncryptBinaryMessageArmored(m.config.PublicKey, d)
case ActionEncryptAndSign:
// TODO: Waiting for reply to https://github.com/ProtonMail/gopenpgp/issues/213
ct, err = helper.EncryptSignMessageArmored(m.config.PublicKey, m.config.PrivKey,
[]byte(m.config.passphrase), string(d))
case ActionSign:
// TODO: Does this work with binary?
return helper.SignCleartextMessageArmored(m.config.PrivKey, []byte(m.config.passphrase), string(d))
default:
return "", ErrUnsupportedAction
}
if err != nil {
return ct, err
}
return m.reArmorMessage(ct)
}
// processPlain is a helper function that processes the given data based on the
// configured Action
func (m *Middleware) processPlain(d string) (string, error) {
var ct string
var err error
switch m.config.Action {
case ActionEncrypt:
ct, err = helper.EncryptMessageArmored(m.config.PublicKey, d)
case ActionEncryptAndSign:
ct, err = helper.EncryptSignMessageArmored(m.config.PublicKey, m.config.PrivKey,
[]byte(m.config.passphrase), d)
case ActionSign:
return helper.SignCleartextMessageArmored(m.config.PrivKey, []byte(m.config.passphrase), d)
default:
return "", ErrUnsupportedAction
}
if err != nil {
return ct, err
}
return m.reArmorMessage(ct)
}
// reArmorMessage unarmors the PGP message and re-armors it with the package specific
// comment and version strings
func (m *Middleware) reArmorMessage(d string) (string, error) {
ua, err := armor.Unarmor(d)
if err != nil {
return d, err
}
return armor.ArmorWithTypeAndCustomHeaders(ua, constants.PGPMessageHeader, armorVersion, armorComment)
}