2019-07-30 20:51:46 +03:00
|
|
|
package imports
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
|
2020-12-29 19:47:20 +02:00
|
|
|
"github.com/ProtonMail/go-crypto/openpgp"
|
|
|
|
"github.com/ProtonMail/go-crypto/openpgp/armor"
|
2019-07-30 20:51:46 +03:00
|
|
|
"github.com/emersion/go-message/mail"
|
|
|
|
|
2024-03-26 21:26:28 +02:00
|
|
|
"github.com/0ranki/hydroxide-push/protonmail"
|
2019-07-30 20:51:46 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
func ImportMessage(c *protonmail.Client, r io.Reader) error {
|
|
|
|
mr, err := mail.CreateReader(r)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer mr.Close()
|
|
|
|
|
|
|
|
// TODO: support attachments
|
|
|
|
hdr := mr.Header
|
|
|
|
var body io.Reader
|
|
|
|
for {
|
|
|
|
p, err := mr.NextPart()
|
|
|
|
if err == io.EOF {
|
|
|
|
break
|
|
|
|
} else if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, ok := p.Header.(*mail.InlineHeader); ok {
|
2020-06-11 12:04:05 +03:00
|
|
|
if t := p.Header.Get("Content-Type"); t != "" {
|
|
|
|
hdr.Set("Content-Type", t)
|
|
|
|
}
|
2019-07-30 20:51:46 +03:00
|
|
|
body = p.Body
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if body == nil {
|
|
|
|
return fmt.Errorf("message has no body")
|
|
|
|
}
|
|
|
|
|
|
|
|
addrs, err := c.ListAddresses()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
// TODO: choose address depending on message header
|
|
|
|
var importAddr *protonmail.Address
|
|
|
|
for _, addr := range addrs {
|
|
|
|
if addr.Send == protonmail.AddressSendPrimary {
|
|
|
|
importAddr = addr
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if importAddr == nil {
|
|
|
|
return fmt.Errorf("no primary address found")
|
|
|
|
}
|
|
|
|
|
|
|
|
publicKey, err := importAddr.Keys[0].Entity()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
key := "0"
|
|
|
|
metadata := map[string]*protonmail.Message{
|
|
|
|
key: {
|
|
|
|
Unread: 1,
|
|
|
|
LabelIDs: []string{protonmail.LabelInbox},
|
|
|
|
Type: protonmail.MessageInbox,
|
|
|
|
AddressID: importAddr.ID,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
importer, err := c.Import(metadata)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
w, err := importer.ImportMessage(key)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-12-17 15:28:19 +02:00
|
|
|
var ihdr mail.InlineHeader
|
|
|
|
ihdr.Set("Content-Type", hdr.Get("Content-Type"))
|
|
|
|
ihdr.Set("Content-Transfer-Encoding", "8bit")
|
|
|
|
|
|
|
|
hdr.Del("Content-Type")
|
|
|
|
hdr.Del("Content-Transfer-Encoding")
|
|
|
|
hdr.Del("Content-Disposition")
|
|
|
|
mwc, err := mail.CreateWriter(w, hdr)
|
2019-07-30 20:51:46 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer mwc.Close()
|
|
|
|
|
2020-12-17 15:28:19 +02:00
|
|
|
iwc, err := mwc.CreateSingleInline(ihdr)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
awc, err := armor.Encode(iwc, "PGP MESSAGE", nil)
|
2019-07-30 20:51:46 +03:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer awc.Close()
|
|
|
|
ewc, err := openpgp.Encrypt(awc, []*openpgp.Entity{publicKey}, nil, nil, nil)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer ewc.Close()
|
|
|
|
|
2020-06-11 12:04:57 +03:00
|
|
|
if _, err := io.Copy(ewc, body); err != nil {
|
2019-07-30 20:51:46 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := ewc.Close(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := awc.Close(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-12-17 15:28:19 +02:00
|
|
|
if err := iwc.Close(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-07-30 20:51:46 +03:00
|
|
|
if err := mwc.Close(); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-11-14 10:38:30 +02:00
|
|
|
if result, err := importer.Commit(); err != nil {
|
|
|
|
return err
|
|
|
|
} else if err := result.Err(); err != nil {
|
2019-07-30 20:51:46 +03:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|