This repository has been archived by the owner on Mar 27, 2020. It is now read-only.
/
construct.go
102 lines (86 loc) · 2.87 KB
/
construct.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
package mail
import (
"bytes"
"fmt"
"io"
"strings"
"time"
"github.com/TNG/openpgp-validation-server/gpg"
)
// MessageEncrypter is a struct able to sign a message and encrypt it for the recipient key
type MessageEncrypter interface {
EncryptMessage(output io.Writer, recipientKey gpg.Key) (plaintext io.WriteCloser, err error)
ServerIdentity() string
}
// OutgoingMail describes the contents of the mail to be sent
type OutgoingMail struct {
Message string
RecipientEmail string
RecipientKey gpg.Key
Attachment []byte
GPG MessageEncrypter
}
// From returns the sender of the mail.
func (m OutgoingMail) From() string {
return m.GPG.ServerIdentity()
}
// Bytes returns the given message as an OpenPGP/MIME encrypted and signed message (RFC 2440 and 3156)
func (m OutgoingMail) Bytes() ([]byte, error) {
w := bytes.Buffer{}
now := time.Now()
identityParts := strings.FieldsFunc(m.GPG.ServerIdentity(), func(r rune) bool { return strings.ContainsRune("><@", r) })
serverDomain := identityParts[len(identityParts)-1]
empw := NewEncodingMultipartWriter(&w, "encrypted", "application/pgp-encrypted", map[string]string{
"Date": now.Format(time.RFC1123Z),
"From": m.From(),
"To": m.RecipientEmail,
"Message-ID": "<" + now.Format(time.RFC3339Nano) + "@" + serverDomain + ">",
"Subject": "OpenPGP Key Validation",
"X-Mailer": "github.com/TNG/openpgp-validation-server",
"Content-Description": "OpenPGP encrypted message",
})
if err := empw.WritePGPMIMEVersion(); err != nil {
return nil, err
}
partWriter, err := empw.WriteInlineFile("encrypted.asc", "application/octet-stream", "OpenPGP encrypted message")
if err != nil {
return nil, err
}
plaintext, err := m.GPG.EncryptMessage(partWriter, m.RecipientKey)
if err != nil {
return nil, err
}
encryptedMultipartWriter := NewEncodingMultipartWriter(plaintext, "mixed", "", nil)
if err = encryptedMultipartWriter.WritePlainText(m.Message); err != nil {
return nil, err
}
if err = m.handleAttachment(encryptedMultipartWriter); err != nil {
return nil, err
}
// Close all writers in the correct order:
if err = encryptedMultipartWriter.Close(); err != nil {
return nil, err
}
if err = plaintext.Close(); err != nil {
return nil, err
}
if err = empw.Close(); err != nil {
return nil, err
}
return w.Bytes(), nil
}
func (m OutgoingMail) handleAttachment(w *EncodingMultipartWriter) error {
if m.Attachment == nil {
return nil
}
fileName := "0x" + m.RecipientKey.PrimaryKey.KeyIdString() + ".asc"
attachmentWriter, err := w.WriteAttachedFile(fileName, "application/pgp-keys", "Your PGP Key")
if err != nil {
return fmt.Errorf("Could not create attachment: %v", err)
}
_, err = attachmentWriter.Write(m.Attachment)
if err != nil {
return fmt.Errorf("Could not write attachment: %v", err)
}
return nil
}