Add decryptMime and refactor package structure
This commit is contained in:
parent
07b3a2c739
commit
97e70855b8
27 changed files with 516 additions and 486 deletions
166
crypto/signature_collector.go
Normal file
166
crypto/signature_collector.go
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/textproto"
|
||||
"proton/pmmime"
|
||||
"golang.org/x/crypto/openpgp/packet"
|
||||
"golang.org/x/crypto/openpgp"
|
||||
"io/ioutil"
|
||||
"bytes"
|
||||
"bufio"
|
||||
"mime/multipart"
|
||||
"mime"
|
||||
)
|
||||
|
||||
type SignatureCollector struct {
|
||||
config *packet.Config
|
||||
keyring openpgp.KeyRing
|
||||
target pmmime.VisitAcceptor
|
||||
signature string
|
||||
verified int
|
||||
}
|
||||
|
||||
func newSignatureCollector(targetAccepter pmmime.VisitAcceptor, keyring openpgp.KeyRing, config *packet.Config) *SignatureCollector {
|
||||
return &SignatureCollector{
|
||||
target: targetAccepter,
|
||||
config: config,
|
||||
keyring: keyring,
|
||||
}
|
||||
}
|
||||
|
||||
func getRawMimePart(rawdata io.Reader, boundary string) (io.Reader, io.Reader) {
|
||||
b, _ := ioutil.ReadAll(rawdata)
|
||||
tee := bytes.NewReader(b)
|
||||
|
||||
reader := bufio.NewReader(bytes.NewReader(b))
|
||||
byteBoundary := []byte(boundary)
|
||||
bodyBuffer := &bytes.Buffer{}
|
||||
for {
|
||||
line, _, err := reader.ReadLine()
|
||||
if err != nil {
|
||||
return tee, bytes.NewReader(bodyBuffer.Bytes())
|
||||
}
|
||||
if bytes.HasPrefix(line, byteBoundary) {
|
||||
break
|
||||
}
|
||||
}
|
||||
lineEndingLength := 0
|
||||
for {
|
||||
line, isPrefix, err := reader.ReadLine()
|
||||
if err != nil {
|
||||
return tee, bytes.NewReader(bodyBuffer.Bytes())
|
||||
}
|
||||
if bytes.HasPrefix(line, byteBoundary) {
|
||||
break
|
||||
}
|
||||
lineEndingLength = 0
|
||||
bodyBuffer.Write(line)
|
||||
if !isPrefix {
|
||||
reader.UnreadByte()
|
||||
reader.UnreadByte()
|
||||
token, _ := reader.ReadByte()
|
||||
if token == '\r' {
|
||||
lineEndingLength++
|
||||
bodyBuffer.WriteByte(token)
|
||||
}
|
||||
lineEndingLength++
|
||||
bodyBuffer.WriteByte(token)
|
||||
}
|
||||
}
|
||||
ioutil.ReadAll(reader)
|
||||
data := bodyBuffer.Bytes()
|
||||
return tee, bytes.NewReader(data[0:len(data) - lineEndingLength])
|
||||
}
|
||||
|
||||
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" {
|
||||
newPart, rawBody := getRawMimePart(part, "--" + params["boundary"])
|
||||
var multiparts []io.Reader
|
||||
var multipartHeaders []textproto.MIMEHeader
|
||||
if multiparts, multipartHeaders, err = getMultipartParts(newPart, 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 {
|
||||
sc.verified = notSigned
|
||||
// Invalid multipart/signed format just pass along
|
||||
ioutil.ReadAll(rawBody)
|
||||
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), multipartHeaders[1].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)
|
||||
str, _ := ioutil.ReadAll(rawBody)
|
||||
rawBody = bytes.NewReader(str)
|
||||
if sc.keyring != nil {
|
||||
_, err = openpgp.CheckArmoredDetachedSignature(sc.keyring, rawBody, bytes.NewReader(buffer), sc.config)
|
||||
|
||||
if err != nil {
|
||||
sc.verified = failed
|
||||
} else {
|
||||
sc.verified = ok
|
||||
}
|
||||
} else {
|
||||
sc.verified = noVerifier
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return
|
||||
}
|
||||
sc.target.Accept(part, header, hasPlainSibling, isFirst, isLast)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ac SignatureCollector) GetSignature() string {
|
||||
return ac.signature
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue