mirror of
https://github.com/ProtonMail/proton-bridge.git
synced 2025-12-17 23:56:56 +00:00
Import/Export backend
This commit is contained in:
261
test/transfer_setup_test.go
Normal file
261
test/transfer_setup_test.go
Normal file
@ -0,0 +1,261 @@
|
||||
// Copyright (c) 2020 Proton Technologies AG
|
||||
//
|
||||
// This file is part of ProtonMail Bridge.Bridge.
|
||||
//
|
||||
// ProtonMail Bridge is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// ProtonMail Bridge is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
package tests
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"net/textproto"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/ProtonMail/proton-bridge/pkg/message"
|
||||
"github.com/cucumber/godog"
|
||||
"github.com/cucumber/godog/gherkin"
|
||||
"github.com/emersion/go-imap"
|
||||
"github.com/emersion/go-mbox"
|
||||
)
|
||||
|
||||
func TransferSetupFeatureContext(s *godog.Suite) {
|
||||
s.Step(`^there are EML files$`, thereAreEMLFiles)
|
||||
s.Step(`^there is EML file "([^"]*)"$`, thereIsEMLFile)
|
||||
s.Step(`^there is MBOX file "([^"]*)" with messages$`, thereIsMBOXFileWithMessages)
|
||||
s.Step(`^there is MBOX file "([^"]*)"$`, thereIsMBOXFile)
|
||||
s.Step(`^there are IMAP mailboxes$`, thereAreIMAPMailboxes)
|
||||
s.Step(`^there are IMAP messages$`, thereAreIMAPMessages)
|
||||
s.Step(`^there is IMAP message in mailbox "([^"]*)" with seq (\d+), uid (\d+), time "([^"]*)" and subject "([^"]*)"$`, thereIsIMAPMessage)
|
||||
}
|
||||
|
||||
func thereAreEMLFiles(messages *gherkin.DataTable) error {
|
||||
head := messages.Rows[0].Cells
|
||||
for _, row := range messages.Rows[1:] {
|
||||
fileName := ""
|
||||
for n, cell := range row.Cells {
|
||||
switch head[n].Value {
|
||||
case "file":
|
||||
fileName = cell.Value
|
||||
case "from", "to", "subject", "time", "body":
|
||||
default:
|
||||
return fmt.Errorf("unexpected column name: %s", head[n].Value)
|
||||
}
|
||||
}
|
||||
|
||||
body := getBodyFromDataRow(head, row)
|
||||
if err := createFile(fileName, body); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func thereIsEMLFile(fileName string, message *gherkin.DocString) error {
|
||||
return createFile(fileName, message.Content)
|
||||
}
|
||||
|
||||
func thereIsMBOXFileWithMessages(fileName string, messages *gherkin.DataTable) error {
|
||||
mboxBuffer := &bytes.Buffer{}
|
||||
mboxWriter := mbox.NewWriter(mboxBuffer)
|
||||
|
||||
head := messages.Rows[0].Cells
|
||||
for _, row := range messages.Rows[1:] {
|
||||
from := ""
|
||||
for n, cell := range row.Cells {
|
||||
switch head[n].Value {
|
||||
case "from":
|
||||
from = cell.Value
|
||||
case "to", "subject", "time", "body":
|
||||
default:
|
||||
return fmt.Errorf("unexpected column name: %s", head[n].Value)
|
||||
}
|
||||
}
|
||||
|
||||
body := getBodyFromDataRow(head, row)
|
||||
|
||||
messageWriter, err := mboxWriter.CreateMessage(from, time.Now())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = messageWriter.Write([]byte(body))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return createFile(fileName, mboxBuffer.String())
|
||||
}
|
||||
|
||||
func thereIsMBOXFile(fileName string, messages *gherkin.DocString) error {
|
||||
return createFile(fileName, messages.Content)
|
||||
}
|
||||
|
||||
func thereAreIMAPMailboxes(mailboxes *gherkin.DataTable) error {
|
||||
imapServer := ctx.GetTransferRemoteIMAPServer()
|
||||
head := mailboxes.Rows[0].Cells
|
||||
for _, row := range mailboxes.Rows[1:] {
|
||||
mailboxName := ""
|
||||
for n, cell := range row.Cells {
|
||||
switch head[n].Value {
|
||||
case "name":
|
||||
mailboxName = cell.Value
|
||||
default:
|
||||
return fmt.Errorf("unexpected column name: %s", head[n].Value)
|
||||
}
|
||||
}
|
||||
imapServer.AddMailbox(mailboxName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func thereAreIMAPMessages(messages *gherkin.DataTable) (err error) {
|
||||
imapServer := ctx.GetTransferRemoteIMAPServer()
|
||||
head := messages.Rows[0].Cells
|
||||
for _, row := range messages.Rows[1:] {
|
||||
mailboxName := ""
|
||||
date := time.Now()
|
||||
subject := ""
|
||||
seqNum := 0
|
||||
uid := 0
|
||||
for n, cell := range row.Cells {
|
||||
switch head[n].Value {
|
||||
case "mailbox":
|
||||
mailboxName = cell.Value
|
||||
case "uid":
|
||||
uid, err = strconv.Atoi(cell.Value)
|
||||
if err != nil {
|
||||
return internalError(err, "failed to parse uid")
|
||||
}
|
||||
case "seqnum":
|
||||
seqNum, err = strconv.Atoi(cell.Value)
|
||||
if err != nil {
|
||||
return internalError(err, "failed to parse seqnum")
|
||||
}
|
||||
case "time":
|
||||
date, err = time.Parse(timeFormat, cell.Value)
|
||||
if err != nil {
|
||||
return internalError(err, "failed to parse time")
|
||||
}
|
||||
case "subject":
|
||||
subject = cell.Value
|
||||
case "from", "to", "body":
|
||||
default:
|
||||
return fmt.Errorf("unexpected column name: %s", head[n].Value)
|
||||
}
|
||||
}
|
||||
|
||||
body := getBodyFromDataRow(head, row)
|
||||
imapMessage, err := getIMAPMessage(seqNum, uid, date, subject, body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
imapServer.AddMessage(mailboxName, imapMessage)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func thereIsIMAPMessage(mailboxName string, seqNum, uid int, dateValue, subject string, message *gherkin.DocString) error {
|
||||
imapServer := ctx.GetTransferRemoteIMAPServer()
|
||||
|
||||
date, err := time.Parse(timeFormat, dateValue)
|
||||
if err != nil {
|
||||
return internalError(err, "failed to parse time")
|
||||
}
|
||||
|
||||
imapMessage, err := getIMAPMessage(seqNum, uid, date, subject, message.Content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
imapServer.AddMessage(mailboxName, imapMessage)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getBodyFromDataRow(head []*gherkin.TableCell, row *gherkin.TableRow) string {
|
||||
body := "hello"
|
||||
headers := textproto.MIMEHeader{}
|
||||
for n, cell := range row.Cells {
|
||||
switch head[n].Value {
|
||||
case "from":
|
||||
headers.Set("from", cell.Value)
|
||||
case "to":
|
||||
headers.Set("to", cell.Value)
|
||||
case "subject":
|
||||
headers.Set("subject", cell.Value)
|
||||
case "time":
|
||||
date, err := time.Parse(timeFormat, cell.Value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
headers.Set("date", date.Format(time.RFC1123))
|
||||
case "body":
|
||||
body = cell.Value
|
||||
}
|
||||
}
|
||||
|
||||
buffer := &bytes.Buffer{}
|
||||
_ = message.WriteHeader(buffer, headers)
|
||||
return buffer.String() + body + "\n\n"
|
||||
}
|
||||
|
||||
func getIMAPMessage(seqNum, uid int, date time.Time, subject, body string) (*imap.Message, error) {
|
||||
reader := bytes.NewBufferString(body)
|
||||
bodyStructure, err := message.NewBodyStructure(reader)
|
||||
if err != nil {
|
||||
return nil, internalError(err, "failed to parse body structure")
|
||||
}
|
||||
imapBodyStructure, err := bodyStructure.IMAPBodyStructure([]int{})
|
||||
if err != nil {
|
||||
return nil, internalError(err, "failed to parse body structure")
|
||||
}
|
||||
bodySection, _ := imap.ParseBodySectionName("BODY[]")
|
||||
|
||||
return &imap.Message{
|
||||
SeqNum: uint32(seqNum),
|
||||
Uid: uint32(uid),
|
||||
Size: uint32(len(body)),
|
||||
Envelope: &imap.Envelope{
|
||||
Date: date,
|
||||
Subject: subject,
|
||||
},
|
||||
BodyStructure: imapBodyStructure,
|
||||
Body: map[*imap.BodySectionName]imap.Literal{
|
||||
bodySection: bytes.NewBufferString(body),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func createFile(fileName, body string) error {
|
||||
root := ctx.GetTransferLocalRootForImport()
|
||||
filePath := filepath.Join(root, fileName)
|
||||
|
||||
dirPath := filepath.Dir(filePath)
|
||||
err := os.MkdirAll(dirPath, os.ModePerm)
|
||||
if err != nil {
|
||||
return internalError(err, "failed to create dir")
|
||||
}
|
||||
|
||||
f, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
return internalError(err, "failed to create file")
|
||||
}
|
||||
defer f.Close() //nolint
|
||||
|
||||
_, err = f.WriteString(body)
|
||||
return internalError(err, "failed to write to file")
|
||||
}
|
||||
Reference in New Issue
Block a user