Implement first version of signature collector
This commit is contained in:
parent
2d45c99a89
commit
dccb3ba50b
4 changed files with 283 additions and 22 deletions
10
glide.lock
generated
10
glide.lock
generated
|
|
@ -1,5 +1,5 @@
|
||||||
hash: 834f29378b80e2f7486b79420679fb1d854c16f2989574090ba80d322a7b71c5
|
hash: 4251e23b87e24d3580705ee49d6354cbd956d2ecc254bd9cb2037d5fd6f34d48
|
||||||
updated: 2018-09-02T14:56:08.452174+02:00
|
updated: 2018-09-04T20:05:07.075614+02:00
|
||||||
imports:
|
imports:
|
||||||
- name: github.com/Sirupsen/logrus
|
- name: github.com/Sirupsen/logrus
|
||||||
version: 78fa2915c1fa231f62e0438da493688c21ca678e
|
version: 78fa2915c1fa231f62e0438da493688c21ca678e
|
||||||
|
|
@ -31,7 +31,7 @@ imports:
|
||||||
- rsa
|
- rsa
|
||||||
- ssh/terminal
|
- ssh/terminal
|
||||||
- name: golang.org/x/sys
|
- name: golang.org/x/sys
|
||||||
version: fa5fdf94c78965f1aa8423f0cc50b8b8d728b05a
|
version: 2b024373dcd9800f0cae693839fac6ede8d64a8c
|
||||||
subpackages:
|
subpackages:
|
||||||
- unix
|
- unix
|
||||||
- windows
|
- windows
|
||||||
|
|
@ -43,7 +43,7 @@ imports:
|
||||||
- encoding/internal
|
- encoding/internal
|
||||||
- encoding/internal/identifier
|
- encoding/internal/identifier
|
||||||
- transform
|
- transform
|
||||||
- name: mimeparser
|
- name: proton/pmmime
|
||||||
version: f4de8a5a52ecd93189c785c7d87259ac637e1d7c
|
version: f64ddc9969090ae55c92712def8289587816dc11
|
||||||
repo: git@gitlab.protontech.ch:ProtonMail/go-pm-mime.git
|
repo: git@gitlab.protontech.ch:ProtonMail/go-pm-mime.git
|
||||||
testImports: []
|
testImports: []
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,6 @@ import:
|
||||||
- package: golang.org/x/crypto
|
- package: golang.org/x/crypto
|
||||||
version: v1.0.0
|
version: v1.0.0
|
||||||
repo: https://github.com/ProtonMail/crypto.git
|
repo: https://github.com/ProtonMail/crypto.git
|
||||||
- package: mimeparser
|
- package: proton/pmmime
|
||||||
repo: git@gitlab.protontech.ch:ProtonMail/go-pm-mime.git
|
repo: git@gitlab.protontech.ch:ProtonMail/go-pm-mime.git
|
||||||
|
version: feat/mimevisitor
|
||||||
|
|
|
||||||
141
mime.go
141
mime.go
|
|
@ -6,10 +6,117 @@ import (
|
||||||
"net/textproto"
|
"net/textproto"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"bytes"
|
"bytes"
|
||||||
"mimeparser"
|
"proton/pmmime"
|
||||||
|
"io"
|
||||||
|
log "github.com/Sirupsen/logrus"
|
||||||
|
"mime"
|
||||||
|
"mime/multipart"
|
||||||
)
|
)
|
||||||
|
|
||||||
func parseMIME(mimeBody string) (body *mimeparser.BodyCollector, atts, attHeaders []string, err error) {
|
|
||||||
|
|
||||||
|
func DecodePart(partReader io.Reader, header textproto.MIMEHeader) (decodedPart io.Reader) {
|
||||||
|
decodedPart = pmmime.DecodeContentEncoding(partReader, header.Get("Content-Transfer-Encoding"))
|
||||||
|
if decodedPart == nil {
|
||||||
|
log.Warnf("Unsupported Content-Transfer-Encoding '%v'", header.Get("Content-Transfer-Encoding"))
|
||||||
|
decodedPart = partReader
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======================== Attachments Collector ==============
|
||||||
|
// Collect contents of all attachment parts and return
|
||||||
|
// them as a string
|
||||||
|
|
||||||
|
type SignatureCollector struct {
|
||||||
|
target pmmime.VisitAcceptor
|
||||||
|
signature string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSignatureCollector(targetAccepter pmmime.VisitAcceptor) *SignatureCollector {
|
||||||
|
return &SignatureCollector{
|
||||||
|
target: targetAccepter,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMultipartParts(r io.Reader, params map[string]string) (parts []io.Reader, headers []textproto.MIMEHeader, err error) {
|
||||||
|
mr := multipart.NewReader(r, params["boundary"])
|
||||||
|
parts = []io.Reader{}
|
||||||
|
headers = []textproto.MIMEHeader{}
|
||||||
|
var p *multipart.Part
|
||||||
|
for {
|
||||||
|
p, err = mr.NextPart()
|
||||||
|
if err == io.EOF {
|
||||||
|
err = nil
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
b, _ := ioutil.ReadAll(p)
|
||||||
|
buffer := bytes.NewBuffer(b)
|
||||||
|
|
||||||
|
parts = append(parts, buffer)
|
||||||
|
headers = append(headers, p.Header)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *SignatureCollector) Accept(part io.Reader, header textproto.MIMEHeader, hasPlainSibling bool, isFirst, isLast bool) (err error) {
|
||||||
|
parentMediaType, params, _ := mime.ParseMediaType(header.Get("Content-Type"))
|
||||||
|
if parentMediaType == "multipart/signed" {
|
||||||
|
var multiparts []io.Reader
|
||||||
|
var multipartHeaders []textproto.MIMEHeader
|
||||||
|
if multiparts, multipartHeaders, err = getMultipartParts(part, params); err != nil {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
hasPlainChild := false
|
||||||
|
for _, header := range multipartHeaders {
|
||||||
|
mediaType, _, _ := mime.ParseMediaType(header.Get("Content-Type"))
|
||||||
|
if mediaType == "text/plain" {
|
||||||
|
hasPlainChild = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(multiparts) != 2 {
|
||||||
|
// Invalid multipart/signed format just pass along
|
||||||
|
for i, p := range multiparts {
|
||||||
|
if err = sc.target.Accept(p, multipartHeaders[i], hasPlainChild, true, true); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// actual multipart/signed format
|
||||||
|
err = sc.target.Accept(multiparts[0], multipartHeaders[0], hasPlainChild, true, true)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
partData, _ := ioutil.ReadAll(multiparts[1])
|
||||||
|
decodedPart := pmmime.DecodeContentEncoding(bytes.NewReader(partData), header.Get("Content-Transfer-Encoding"))
|
||||||
|
buffer, err := ioutil.ReadAll(decodedPart)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
buffer, err = pmmime.DecodeCharset(buffer, params)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
sc.signature = string(buffer)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
sc.target.Accept(part, header, hasPlainSibling, isFirst, isLast)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func (ac SignatureCollector) GetSignature() string {
|
||||||
|
return ac.signature
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func ParseMIME(mimeBody string) (body *pmmime.BodyCollector, atts, attHeaders []string, err error) {
|
||||||
|
|
||||||
mm, err := mail.ReadMessage(strings.NewReader(mimeBody))
|
mm, err := mail.ReadMessage(strings.NewReader(mimeBody))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -19,10 +126,12 @@ func parseMIME(mimeBody string) (body *mimeparser.BodyCollector, atts, attHeader
|
||||||
h := textproto.MIMEHeader(mm.Header)
|
h := textproto.MIMEHeader(mm.Header)
|
||||||
mmBodyData, err := ioutil.ReadAll(mm.Body)
|
mmBodyData, err := ioutil.ReadAll(mm.Body)
|
||||||
|
|
||||||
printAccepter := mimeparser.NewMIMEPrinter()
|
printAccepter := pmmime.NewMIMEPrinter()
|
||||||
bodyCollector := mimeparser.NewBodyCollector(printAccepter)
|
bodyCollector := pmmime.NewBodyCollector(printAccepter)
|
||||||
attachmentsCollector := mimeparser.NewAttachmentsCollector(bodyCollector)
|
attachmentsCollector := pmmime.NewAttachmentsCollector(bodyCollector)
|
||||||
err = mimeparser.VisitAll(bytes.NewReader(mmBodyData), h, attachmentsCollector)
|
mimeVisitor := pmmime.NewMimeVisitor(attachmentsCollector)
|
||||||
|
signatureCollector := NewSignatureCollector(mimeVisitor)
|
||||||
|
err = pmmime.VisitAll(bytes.NewReader(mmBodyData), h, signatureCollector)
|
||||||
|
|
||||||
body = bodyCollector
|
body = bodyCollector
|
||||||
atts = attachmentsCollector.GetAttachments()
|
atts = attachmentsCollector.GetAttachments()
|
||||||
|
|
@ -31,7 +140,7 @@ func parseMIME(mimeBody string) (body *mimeparser.BodyCollector, atts, attHeader
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
// define call back interface
|
// define call back interface
|
||||||
type MIMECallbacks interface {
|
type MIMECallbacks interface {
|
||||||
|
|
@ -42,16 +151,16 @@ type MIMECallbacks interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *OpenPGP) decryptMIMEMessage(encryptedText string, verifierKey string, privateKeys []byte,
|
func (o *OpenPGP) decryptMIMEMessage(encryptedText string, verifierKey string, privateKeys []byte,
|
||||||
passphrase string, callbacks MIMECallbacks, verifyTime int64) (verifier int, err error) {
|
passphrase string, callbacks MIMECallbacks, verifyTime int64) (verifier int, err error) {
|
||||||
decsignverify, error := o.DecryptMessageVerifyPrivbinkeys(encryptedText, verifierKey, privateKeys, passphrase, verifyTime)
|
decsignverify, err := o.DecryptMessageVerifyPrivbinkeys(encryptedText, verifierKey, privateKeys, passphrase, verifyTime)
|
||||||
if (error != nil) {
|
if (err != nil) {
|
||||||
return 0, error
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
body, attachments, attachmentHeaders, error := parseMIME(decsignverify.Plaintext
|
body, attachments, attachmentHeaders, err := parseMIME(decsignverify.Plaintext)
|
||||||
if (error != nil) {
|
if (err != nil) {
|
||||||
return 0, error
|
return 0, err
|
||||||
})
|
}
|
||||||
bodyContent, bodyMimeType := body.GetBody()
|
bodyContent, bodyMimeType := body.GetBody()
|
||||||
callbacks.onBody(bodyContent, bodyMimeType)
|
callbacks.onBody(bodyContent, bodyMimeType)
|
||||||
for i := 0; i < len(attachments); i++ {
|
for i := 0; i < len(attachments); i++ {
|
||||||
|
|
@ -62,4 +171,4 @@ func (o *OpenPGP) decryptMIMEMessage(encryptedText string, verifierKey string, p
|
||||||
// Todo verify the signature included in the attachment
|
// Todo verify the signature included in the attachment
|
||||||
|
|
||||||
return verifier, nil
|
return verifier, nil
|
||||||
}
|
}*/
|
||||||
151
mime_test.go
Normal file
151
mime_test.go
Normal file
|
|
@ -0,0 +1,151 @@
|
||||||
|
package pmcrypto
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestParse(t *testing.T) {
|
||||||
|
testMessage :=
|
||||||
|
`Content-Type: multipart/signed; protocol="application/pgp-signature"; micalg=pgp-sha256; boundary="---------------------4a9ea9f4dad3f36079bdb3f1e7b75bd0"; charset=UTF-8
|
||||||
|
X-Spam-Status: No, score=1.2 required=7.0 tests=ALL_TRUSTED,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM, FREEMAIL_REPLYTO_END_DIGIT,HTML_IMAGE_ONLY_08,HTML_MESSAGE autolearn=no autolearn_force=no version=3.4.0
|
||||||
|
X-Spam-Level: *
|
||||||
|
X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on mail.protonmail.ch
|
||||||
|
|
||||||
|
-----------------------4a9ea9f4dad3f36079bdb3f1e7b75bd0
|
||||||
|
Content-Type: multipart/mixed; boundary="---------------------f0e64db835d0f5c3674df52a164b06bb"
|
||||||
|
|
||||||
|
-----------------------f0e64db835d0f5c3674df52a164b06bb
|
||||||
|
Content-Type: multipart/alternative; boundary="---------------------3ca028eaeffb3ca0fb0dd6461f639c2b"
|
||||||
|
|
||||||
|
-----------------------3ca028eaeffb3ca0fb0dd6461f639c2b
|
||||||
|
Content-Transfer-Encoding: quoted-printable
|
||||||
|
Content-Type: text/plain;charset=utf-8
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[Screenshot from 2018-02-06 17-13-21.png]
|
||||||
|
|
||||||
|
--=C2=A0
|
||||||
|
Julien Palard
|
||||||
|
https://mdk.fr
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------3ca028eaeffb3ca0fb0dd6461f639c2b
|
||||||
|
Content-Type: multipart/related; boundary="---------------------ce717c368c2d3981c954ad7c46cd7bf2"
|
||||||
|
|
||||||
|
-----------------------ce717c368c2d3981c954ad7c46cd7bf2
|
||||||
|
Content-Type: text/html;charset=utf-8
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
|
||||||
|
PGRpdj48ZGl2Pjxicj48L2Rpdj48ZGl2Pjxicj48L2Rpdj48ZGl2IGNsYXNzPSJwcm90b25tYWls
|
||||||
|
X3NpZ25hdHVyZV9ibG9jayI+PGRpdiBjbGFzcz0icHJvdG9ubWFpbF9zaWduYXR1cmVfYmxvY2st
|
||||||
|
dXNlciI+PGRpdj48aW1nIHNyYz0iY2lkOjQ2MDk4ZTliQHByb3Rvbm1haWwuY29tIiBjbGFzcz0i
|
||||||
|
cHJvdG9uLWVtYmVkZGVkIiBhbHQ9IlNjcmVlbnNob3QgZnJvbSAyMDE4LTAyLTA2IDE3LTEzLTIx
|
||||||
|
LnBuZyI+PGJyPjwvZGl2PjxkaXY+LS0mbmJzcDs8YnI+PC9kaXY+PGRpdj5KdWxpZW4gUGFsYXJk
|
||||||
|
PGJyPjwvZGl2PjxkaXY+PGNvZGUgc3R5bGU9ImZvbnQtZmFtaWx5OidTRk1vbm8tUmVndWxhcics
|
||||||
|
IENvbnNvbGFzLCAnTGliZXJhdGlvbiBNb25vJywgTWVubG8sIENvdXJpZXIsIG1vbm9zcGFjZTtm
|
||||||
|
b250LXNpemU6MTEuODk5OTk5NjE4NTMwMjczcHg7cGFkZGluZzowcHg7bWFyZ2luOjBweDtiYWNr
|
||||||
|
Z3JvdW5kLWNvbG9yOnRyYW5zcGFyZW50O3doaXRlLXNwYWNlOnByZTtib3JkZXI6MHB4O2Rpc3Bs
|
||||||
|
YXk6aW5saW5lO292ZXJmbG93OnZpc2libGU7bGluZS1oZWlnaHQ6aW5oZXJpdDsiPjxhIGhyZWY9
|
||||||
|
Imh0dHBzOi8vbWRrLmZyIj5odHRwczovL21kay5mcjwvYT48L2NvZGU+PGJyPjwvZGl2PjwvZGl2
|
||||||
|
PjxkaXYgY2xhc3M9InByb3Rvbm1haWxfc2lnbmF0dXJlX2Jsb2NrLXByb3RvbiBwcm90b25tYWls
|
||||||
|
X3NpZ25hdHVyZV9ibG9jay1lbXB0eSI+PGJyPjwvZGl2PjwvZGl2PjwvZGl2Pg==
|
||||||
|
-----------------------ce717c368c2d3981c954ad7c46cd7bf2--
|
||||||
|
-----------------------3ca028eaeffb3ca0fb0dd6461f639c2b--
|
||||||
|
-----------------------f0e64db835d0f5c3674df52a164b06bb
|
||||||
|
Content-Type: image/png; filename="Screenshot from 2018-02-06 17-13-21.png"; name="Screenshot from 2018-02-06 17-13-21.png"
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
Content-Disposition: inline; filename="Screenshot from 2018-02-06 17-13-21.png"; name="Screenshot from 2018-02-06 17-13-21.png"
|
||||||
|
Content-ID: <46098e9b@protonmail.com>
|
||||||
|
|
||||||
|
wsBcBAEBCAAQBQJbjodcCRDdVS3pfakUGgAAlhoH/2jBRjOSx5EdkiyyNcCT
|
||||||
|
4DVm+ACoF1KTWE5fLRuDPvSiD934cFoZShJs32r0Wcj/4W4tVhLYzjjtf6xO
|
||||||
|
Ymqe0p3o4oYxxMXIAd4COrnOPGjeD1ausqT6iUCAadqXoDYfowEg4f0Wd0RK
|
||||||
|
ElsP/OZaDjsNoRE3WeRcHTr5XWZxhEsIMgnW591iaTliYvbysLoQ08i3G53c
|
||||||
|
p6q+IANRznx5rDhMdo+shFvhcI2Zszg6X2WuCMhFtUyrqEN8WlZYXMX8PGPO
|
||||||
|
1kNDRl7B7/r4Ap+FffLpeYw+8rG6lQXGc3RCOAnfMq9X/9Ziqzxr7flYtRJH
|
||||||
|
RIzX2CG47PuGl/uvImFW/Iw=
|
||||||
|
|
||||||
|
-----------------------f0e64db835d0f5c3674df52a164b06bb
|
||||||
|
Content-Type: application/pgp-keys; filename="publickey - kaykeytest3@protonmail.com - 0xE1DADAE3.asc"; name="publickey - kaykeytest3@protonmail.com - 0xE1DADAE3.asc"
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
Content-Disposition: attachment; filename="publickey - kaykeytest3@protonmail.com - 0xE1DADAE3.asc"; name="publickey - kaykeytest3@protonmail.com - 0xE1DADAE3.asc"
|
||||||
|
|
||||||
|
LS0tLS1CRUdJTiBQR1AgUFVCTElDIEtFWSBCTE9DSy0tLS0tDQpWZXJzaW9uOiBPcGVuUEdQLmpz
|
||||||
|
IHYzLjEuMg0KQ29tbWVudDogaHR0cHM6Ly9vcGVucGdwanMub3JnDQoNCnhzQk5CRnQ2N2I4QkNB
|
||||||
|
QzBTMlU3VUJ3dnkyUnZqcEpwOHlyMlE0R25oNzk0QjUwVG1TMlViTXJRaEovaQpUWFRTZmJhb21l
|
||||||
|
NkdkcmJhSjlvVW0xY2hhMU5hVlNnWHE0RVB2WWxmSWVVdkt1U0tnTVdxaVMzT2xSdGYKT3JwMVZp
|
||||||
|
dXNpZWtldVczL2JtYUZBbzFLQWZvajBMNlF6cVVIY3ZZNnY1RExoWGV2MWlaUW9TN2lrQk9PCmor
|
||||||
|
Z05lUDJabjVIOXdQTFlxdWlqK0pnWFY4djRRQk5uNU82NUNYRkZIbjl1Mzl1Yng2bDJtY2tqaDVm
|
||||||
|
VQppU1FiUkh2RzhIdG96Y2xIcWV1bjBpanNjZEtoOTBsaENsWHlDcHlkZ2JwT2pjL2dDQ2R3WmVh
|
||||||
|
djNNSG0KZnhsd2VReDhmc0xxZ1h5TlNFd3pyODh0MTFWMFQ4TmRjeFdia1lRNllQN2R4UU10RkU0
|
||||||
|
bWM5akxBQkVCCkFBSE5PU0pyWVhsclpYbDBaWE4wTTBCd2NtOTBiMjV0WVdsc0xtTnZiU0lnUEd0
|
||||||
|
aGVXdGxlWFJsYzNRegpRSEJ5YjNSdmJtMWhhV3d1WTI5dFBzTEFkUVFRQVFnQUtRVUNXM3J0dndZ
|
||||||
|
TENRY0lBd0lKRU4xVkxlbDkKcVJRYUJCVUlDZ0lERmdJQkFoa0JBaHNEQWg0QkFBQ0dEZ2Y5SHVq
|
||||||
|
aG9QUGN5SHpLd25JbFJJaENRL1dLCm13SVVFdEw4eU03aGRvci9zK0kyL1A3WkJHWE1ReXBKb3JD
|
||||||
|
YTU1NUY2ODRMZnpWdUtBUVFMdXZpNHR6aQo5N2JSNE1ldHY4a2ptSUI1Rk0vNUhpWllWd090SDFK
|
||||||
|
dU5iM2RQWG9CVjJha09ScnFCeVRjbjEyeUIwOVkKd0tZR0Y4K25XNFhLU1F2V3VBWWVIZ0dQKzMz
|
||||||
|
ZTdCc0VvODhuRmJJUXl2cmUzUTN0TkJrWTVVVnA2L1M2ClpLZWJwaEFRQVlzM0ZVVlZVeThlZkhr
|
||||||
|
aEFmZFlSdUFBUUFoWnJGanU0V1J0RGZkUHdLR0UzZDZsUGswSApNSFNTUXNHb2thQTVoTnUycE1S
|
||||||
|
Mnl5UmtUa3JyNnRXbmlET2ZvSmtKcmc2VllHNVRwaHZnOE43dVdzZHQKZkhDdDBwWW9uYTRzclZx
|
||||||
|
a0RzN0FUUVJiZXUyL0FRZ0F6b2tCSGZucnFXUXE4RUVSYUVlOUpmZkQ3V0FpCnZyU29lNDdxQ05l
|
||||||
|
S2I2MmcvLzh0Q1dKMHVlRExTMFRyY0V4cnVzUi8rSFdoYUFTV2srL0lPTGhjRTcrVgp4V2Nab0dp
|
||||||
|
bzNuc1puTktWdnFhendNSW1vMnFqdUllUnVCVkJqRW5OOERhOXlxNkJ3YVkvSEs2czM5Y3IKQVVV
|
||||||
|
d2FtWjVuMDNtSFR6MzBMQllYR1VldVc5c3Z4NDIzbTlXb3N2WlQvUWRKWW1qMG44NmpGNGs2Tnh2
|
||||||
|
ClV4ejR1bmV1YWt1Wld5NmNURHg1WFdWVWF1YzlyV1Z5Uzk3cjJ0NllpRlF6MTFiOU5oZm4rcDVs
|
||||||
|
UmdZbgpzMzQwT1MyVmppK1BVeUVKZ2YzYi9MQlJ5V3Erbk1Vc2lRV09yYlQxblVCVzNRdDViWWhH
|
||||||
|
MUhnT1o5eEoKVjd2dndSZHFwQ1p2cVFBUkFRQUJ3c0JmQkJnQkNBQVRCUUpiZXUyL0NSRGRWUzNw
|
||||||
|
ZmFrVUdnSWJEQUFBClhrTUgvaTBoTnRwRWIrYUZONC9Ba0JCam1GOFJZV243anRyK2UyU05STHdF
|
||||||
|
RUMxcmdmakhjWXZnanJFTQo2Y3hBcXVzSWJKSEdnSUVYZ0s1YUlNOHBGLzRuamN2VXVxa0x1b1o3
|
||||||
|
QVJsanpwUTcvaHhyc0FNWnFYR2gKeEU4eXJZVlY0dGhhZWw0Q1NRUTRvRWlpbXB4Z28velE5bzhk
|
||||||
|
NGNQUTM4Ni9VNEgvMm9OczFUMElCOTZWCkJsTy9pM0w5eGM4K2w4RG8vcm5ieVV1Ym9LUVNKZmtp
|
||||||
|
RXNLMkRabEZoOVArdVltQ1AzVGJSb2NIUFZtVwpBT3NHVVhJSXROaVNTc05ORUlHeVBSNE8rMXRq
|
||||||
|
VUJPMFNHRnZoVVZUNnJLYTlaYUVyMzI2ZmU2S0pmZU8KYTl4a21WZEdaQm9SdENmbHhiakdnYjRq
|
||||||
|
dTJ3Z1E1TE5KWUNWZy9WRkxIRGI3MjQ9DQo9YmNvMw0KLS0tLS1FTkQgUEdQIFBVQkxJQyBLRVkg
|
||||||
|
QkxPQ0stLS0tLQ0KDQo=
|
||||||
|
-----------------------f0e64db835d0f5c3674df52a164b06bb--
|
||||||
|
-----------------------4a9ea9f4dad3f36079bdb3f1e7b75bd0
|
||||||
|
Content-Type: application/pgp-signature; name="signature.asc"
|
||||||
|
Content-Description: OpenPGP digital signature
|
||||||
|
Content-Disposition: attachment; filename="signature.asc"
|
||||||
|
|
||||||
|
-----BEGIN PGP SIGNATURE-----
|
||||||
|
Version: ProtonMail
|
||||||
|
Comment: https://protonmail.com
|
||||||
|
|
||||||
|
wsBcBAEBCAAQBQJbjodcCRDdVS3pfakUGgAAlhoH/2jBRjOSx5EdkiyyNcCT
|
||||||
|
4DVm+ACoF1KTWE5fLRuDPvSiD934cFoZShJs32r0Wcj/4W4tVhLYzjjtf6xO
|
||||||
|
Ymqe0p3o4oYxxMXIAd4COrnOPGjeD1ausqT6iUCAadqXoDYfowEg4f0Wd0RK
|
||||||
|
ElsP/OZaDjsNoRE3WeRcHTr5XWZxhEsIMgnW591iaTliYvbysLoQ08i3G53c
|
||||||
|
p6q+IANRznx5rDhMdo+shFvhcI2Zszg6X2WuCMhFtUyrqEN8WlZYXMX8PGPO
|
||||||
|
1kNDRl7B7/r4Ap+FffLpeYw+8rG6lQXGc3RCOAnfMq9X/9Ziqzxr7flYtRJH
|
||||||
|
RIzX2CG47PuGl/uvImFW/Iw=
|
||||||
|
=t7ak
|
||||||
|
-----END PGP SIGNATURE-----
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------4a9ea9f4dad3f36079bdb3f1e7b75bd0--
|
||||||
|
`
|
||||||
|
body, atts, attHeaders, err := ParseMIME(testMessage)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println()
|
||||||
|
fmt.Println("==BODY:")
|
||||||
|
fmt.Println(body.GetBody())
|
||||||
|
fmt.Println("==BODY HEADERS:")
|
||||||
|
fmt.Println(body.GetHeaders())
|
||||||
|
|
||||||
|
fmt.Println("==ATTACHMENTS:")
|
||||||
|
fmt.Println(len(atts))
|
||||||
|
for i, attachment := range atts {
|
||||||
|
fmt.Println("==ATTACHMENT HEADERS:")
|
||||||
|
fmt.Println(attHeaders[i])
|
||||||
|
fmt.Println("==ATTACHMENT:")
|
||||||
|
fmt.Println(attachment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue