diff --git a/internal/bridge/credits.go b/internal/bridge/credits.go index 9977b19f..5913ab56 100644 --- a/internal/bridge/credits.go +++ b/internal/bridge/credits.go @@ -15,8 +15,8 @@ // You should have received a copy of the GNU General Public License // along with ProtonMail Bridge. If not, see . -// Code generated by ./credits.sh at Tue Nov 24 08:56:01 AM CET 2020. DO NOT EDIT. +// Code generated by ./credits.sh at Fri Nov 27 09:08:56 CET 2020. DO NOT EDIT. package bridge -const Credits = "github.com/0xAX/notificator;github.com/abiosoft/ishell;github.com/abiosoft/readline;github.com/allan-simon/go-singleinstance;github.com/chzyer/logex;github.com/chzyer/test;github.com/cucumber/godog;github.com/docker/docker-credential-helpers;github.com/emersion/go-imap;github.com/emersion/go-imap-appendlimit;github.com/emersion/go-imap-idle;github.com/emersion/go-imap-move;github.com/emersion/go-imap-quota;github.com/emersion/go-imap-specialuse;github.com/emersion/go-imap-unselect;github.com/emersion/go-mbox;github.com/emersion/go-message;github.com/emersion/go-sasl;github.com/emersion/go-smtp;github.com/emersion/go-textwrapper;github.com/emersion/go-vcard;github.com/fatih/color;github.com/flynn-archive/go-shlex;github.com/getsentry/sentry-go;github.com/golang/mock;github.com/google/go-cmp;github.com/google/uuid;github.com/gopherjs/gopherjs;github.com/go-resty/resty/v2;github.com/hashicorp/go-multierror;github.com/jameskeane/bcrypt;github.com/jaytaylor/html2text;github.com/kardianos/osext;github.com/keybase/go-keychain;github.com/logrusorgru/aurora;github.com/Masterminds/semver/v3;github.com/mattn/go-runewidth;github.com/miekg/dns;github.com/myesui/uuid;github.com/nsf/jsondiff;github.com/olekukonko/tablewriter;github.com/pkg/errors;github.com/ProtonMail/bcrypt;github.com/ProtonMail/crypto;github.com/ProtonMail/docker-credential-helpers;github.com/ProtonMail/go-appdir;github.com/ProtonMail/go-apple-mobileconfig;github.com/ProtonMail/go-autostart;github.com/ProtonMail/go-imap;github.com/ProtonMail/go-imap-id;github.com/ProtonMail/gopenpgp/v2;github.com/ProtonMail/go-rfc5322;github.com/ProtonMail/go-smtp;github.com/ProtonMail/go-vcard;github.com/PuerkitoBio/goquery;github.com/sirupsen/logrus;github.com/skratchdot/open-golang;github.com/ssor/bom;github.com/stretchr/testify;github.com/therecipe/qt;github.com/twinj/uuid;github.com/urfave/cli;go.etcd.io/bbolt;golang.org/x/crypto;golang.org/x/net;golang.org/x/text;gopkg.in/stretchr/testify.v1;;Font Awesome 4.7.0;;Qt 5.13 by Qt group;" +const Credits = "github.com/0xAX/notificator;github.com/Masterminds/semver/v3;github.com/ProtonMail/bcrypt;github.com/ProtonMail/crypto;github.com/ProtonMail/docker-credential-helpers;github.com/ProtonMail/go-appdir;github.com/ProtonMail/go-apple-mobileconfig;github.com/ProtonMail/go-autostart;github.com/ProtonMail/go-imap;github.com/ProtonMail/go-imap-id;github.com/ProtonMail/go-rfc5322;github.com/ProtonMail/go-smtp;github.com/ProtonMail/go-vcard;github.com/ProtonMail/gopenpgp/v2;github.com/PuerkitoBio/goquery;github.com/abiosoft/ishell;github.com/abiosoft/readline;github.com/allan-simon/go-singleinstance;github.com/chzyer/logex;github.com/chzyer/test;github.com/cucumber/godog;github.com/docker/docker-credential-helpers;github.com/emersion/go-imap;github.com/emersion/go-imap-appendlimit;github.com/emersion/go-imap-idle;github.com/emersion/go-imap-move;github.com/emersion/go-imap-quota;github.com/emersion/go-imap-specialuse;github.com/emersion/go-imap-unselect;github.com/emersion/go-mbox;github.com/emersion/go-message;github.com/emersion/go-sasl;github.com/emersion/go-smtp;github.com/emersion/go-textwrapper;github.com/emersion/go-vcard;github.com/fatih/color;github.com/flynn-archive/go-shlex;github.com/getsentry/sentry-go;github.com/go-resty/resty/v2;github.com/golang/mock;github.com/google/go-cmp;github.com/google/uuid;github.com/gopherjs/gopherjs;github.com/hashicorp/go-multierror;github.com/jameskeane/bcrypt;github.com/jaytaylor/html2text;github.com/kardianos/osext;github.com/keybase/go-keychain;github.com/logrusorgru/aurora;github.com/mattn/go-runewidth;github.com/miekg/dns;github.com/myesui/uuid;github.com/nsf/jsondiff;github.com/olekukonko/tablewriter;github.com/pkg/errors;github.com/sirupsen/logrus;github.com/skratchdot/open-golang;github.com/ssor/bom;github.com/stretchr/testify;github.com/therecipe/qt;github.com/twinj/uuid;github.com/urfave/cli;go.etcd.io/bbolt;golang.org/x/crypto;golang.org/x/net;golang.org/x/text;gopkg.in/stretchr/testify.v1;;Font Awesome 4.7.0;;Qt 5.13 by Qt group;" diff --git a/internal/frontend/qml/ImportExportUI/DialogImport.qml b/internal/frontend/qml/ImportExportUI/DialogImport.qml index bcf0d8b9..6a158336 100644 --- a/internal/frontend/qml/ImportExportUI/DialogImport.qml +++ b/internal/frontend/qml/ImportExportUI/DialogImport.qml @@ -355,6 +355,25 @@ Dialog { InlineLabelSelect { id: globalLabels } + + Row { + spacing: Style.dialog.spacing + CheckBoxLabel { + id: importEncrypted + text: qsTr("Import encrypted emails as they are") + anchors { + bottom: parent.bottom + bottomMargin: Style.dialog.fontSize/1.8 + } + } + + InfoToolTip { + anchors { + verticalCenter: importEncrypted.verticalCenter + } + info: qsTr("When this option is enabled, encrypted emails will be imported as ciphertext. Otherwise, such messages will be skipped.", "todo") + } + } } // Buttons @@ -1018,7 +1037,7 @@ Dialog { ) break case DialogImport.Page.Progress: - go.startImport(root.address) + go.startImport(root.address, importEncrypted.checked) break } } diff --git a/internal/frontend/qt-ie/import.go b/internal/frontend/qt-ie/import.go index 2ad3e6e9..0dacc805 100644 --- a/internal/frontend/qt-ie/import.go +++ b/internal/frontend/qt-ie/import.go @@ -73,7 +73,7 @@ func (f *FrontendQt) loadStructuresForImport() error { return nil } -func (f *FrontendQt) StartImport(email string) { // TODO email not needed +func (f *FrontendQt) StartImport(email string, importEncrypted bool) { // TODO email not needed log.Trace("Starting import") f.Qml.SetProgressDescription("init") // TODO use const @@ -84,6 +84,7 @@ func (f *FrontendQt) StartImport(email string) { // TODO email not needed f.Qml.SetTotal(1) f.Qml.SetImportLogFileName("") + f.transfer.SetSkipEncryptedMessages(!importEncrypted) progress := f.transfer.Start() f.Qml.SetImportLogFileName(progress.FileReport()) diff --git a/internal/frontend/qt-ie/ui.go b/internal/frontend/qt-ie/ui.go index 1040d2ea..563bdb48 100644 --- a/internal/frontend/qt-ie/ui.go +++ b/internal/frontend/qt-ie/ui.go @@ -95,7 +95,7 @@ type GoQMLInterface struct { _ func() string `slot:"leastUsedColor"` _ func(username string, name string, color string, isLabel bool, sourceID string) bool `slot:"createLabelOrFolder"` _ func(fpath, address, fileType string, attachEncryptedBody bool) `slot:"startExport"` - _ func(email string) `slot:"startImport"` + _ func(email string, importEncrypted bool) `slot:"startImport"` _ func() `slot:"resetSource"` _ func(isFromIMAP bool, sourcePath, sourceEmail, sourcePassword, sourceServe, sourcePort, targetAddress string) `slot:"setupAndLoadForImport"` diff --git a/internal/importexport/credits.go b/internal/importexport/credits.go index 2f5febee..9b29292b 100644 --- a/internal/importexport/credits.go +++ b/internal/importexport/credits.go @@ -15,8 +15,8 @@ // You should have received a copy of the GNU General Public License // along with ProtonMail Bridge. If not, see . -// Code generated by ./credits.sh at Tue Nov 24 08:56:01 AM CET 2020. DO NOT EDIT. +// Code generated by ./credits.sh at Fri Nov 27 09:08:56 CET 2020. DO NOT EDIT. package importexport -const Credits = "github.com/0xAX/notificator;github.com/abiosoft/ishell;github.com/abiosoft/readline;github.com/allan-simon/go-singleinstance;github.com/chzyer/logex;github.com/chzyer/test;github.com/cucumber/godog;github.com/docker/docker-credential-helpers;github.com/emersion/go-imap;github.com/emersion/go-imap-appendlimit;github.com/emersion/go-imap-idle;github.com/emersion/go-imap-move;github.com/emersion/go-imap-quota;github.com/emersion/go-imap-specialuse;github.com/emersion/go-imap-unselect;github.com/emersion/go-mbox;github.com/emersion/go-message;github.com/emersion/go-sasl;github.com/emersion/go-smtp;github.com/emersion/go-textwrapper;github.com/emersion/go-vcard;github.com/fatih/color;github.com/flynn-archive/go-shlex;github.com/getsentry/sentry-go;github.com/golang/mock;github.com/google/go-cmp;github.com/google/uuid;github.com/gopherjs/gopherjs;github.com/go-resty/resty/v2;github.com/hashicorp/go-multierror;github.com/jameskeane/bcrypt;github.com/jaytaylor/html2text;github.com/kardianos/osext;github.com/keybase/go-keychain;github.com/logrusorgru/aurora;github.com/Masterminds/semver/v3;github.com/mattn/go-runewidth;github.com/miekg/dns;github.com/myesui/uuid;github.com/nsf/jsondiff;github.com/olekukonko/tablewriter;github.com/pkg/errors;github.com/ProtonMail/bcrypt;github.com/ProtonMail/crypto;github.com/ProtonMail/docker-credential-helpers;github.com/ProtonMail/go-appdir;github.com/ProtonMail/go-apple-mobileconfig;github.com/ProtonMail/go-autostart;github.com/ProtonMail/go-imap;github.com/ProtonMail/go-imap-id;github.com/ProtonMail/gopenpgp/v2;github.com/ProtonMail/go-rfc5322;github.com/ProtonMail/go-smtp;github.com/ProtonMail/go-vcard;github.com/PuerkitoBio/goquery;github.com/sirupsen/logrus;github.com/skratchdot/open-golang;github.com/ssor/bom;github.com/stretchr/testify;github.com/therecipe/qt;github.com/twinj/uuid;github.com/urfave/cli;go.etcd.io/bbolt;golang.org/x/crypto;golang.org/x/net;golang.org/x/text;gopkg.in/stretchr/testify.v1;;Font Awesome 4.7.0;;Qt 5.13 by Qt group;" +const Credits = "github.com/0xAX/notificator;github.com/Masterminds/semver/v3;github.com/ProtonMail/bcrypt;github.com/ProtonMail/crypto;github.com/ProtonMail/docker-credential-helpers;github.com/ProtonMail/go-appdir;github.com/ProtonMail/go-apple-mobileconfig;github.com/ProtonMail/go-autostart;github.com/ProtonMail/go-imap;github.com/ProtonMail/go-imap-id;github.com/ProtonMail/go-rfc5322;github.com/ProtonMail/go-smtp;github.com/ProtonMail/go-vcard;github.com/ProtonMail/gopenpgp/v2;github.com/PuerkitoBio/goquery;github.com/abiosoft/ishell;github.com/abiosoft/readline;github.com/allan-simon/go-singleinstance;github.com/chzyer/logex;github.com/chzyer/test;github.com/cucumber/godog;github.com/docker/docker-credential-helpers;github.com/emersion/go-imap;github.com/emersion/go-imap-appendlimit;github.com/emersion/go-imap-idle;github.com/emersion/go-imap-move;github.com/emersion/go-imap-quota;github.com/emersion/go-imap-specialuse;github.com/emersion/go-imap-unselect;github.com/emersion/go-mbox;github.com/emersion/go-message;github.com/emersion/go-sasl;github.com/emersion/go-smtp;github.com/emersion/go-textwrapper;github.com/emersion/go-vcard;github.com/fatih/color;github.com/flynn-archive/go-shlex;github.com/getsentry/sentry-go;github.com/go-resty/resty/v2;github.com/golang/mock;github.com/google/go-cmp;github.com/google/uuid;github.com/gopherjs/gopherjs;github.com/hashicorp/go-multierror;github.com/jameskeane/bcrypt;github.com/jaytaylor/html2text;github.com/kardianos/osext;github.com/keybase/go-keychain;github.com/logrusorgru/aurora;github.com/mattn/go-runewidth;github.com/miekg/dns;github.com/myesui/uuid;github.com/nsf/jsondiff;github.com/olekukonko/tablewriter;github.com/pkg/errors;github.com/sirupsen/logrus;github.com/skratchdot/open-golang;github.com/ssor/bom;github.com/stretchr/testify;github.com/therecipe/qt;github.com/twinj/uuid;github.com/urfave/cli;go.etcd.io/bbolt;golang.org/x/crypto;golang.org/x/net;golang.org/x/text;gopkg.in/stretchr/testify.v1;;Font Awesome 4.7.0;;Qt 5.13 by Qt group;" diff --git a/internal/transfer/provider_pmapi_target.go b/internal/transfer/provider_pmapi_target.go index 9011a4e5..cd542568 100644 --- a/internal/transfer/provider_pmapi_target.go +++ b/internal/transfer/provider_pmapi_target.go @@ -124,6 +124,12 @@ func (p *PMAPIProvider) importDraft(msg Message, globalMailbox *Mailbox) (string return "", errors.Wrap(err, "failed to parse message") } + // Trying to encrypt an encrypted draft will return an error; + // users are forbidden to import messages encrypted with foreign keys to drafts. + if message.IsEncrypted() { + return "", errors.New("refusing to import draft encrypted by foreign key") + } + p.timeIt.start("encrypt", msg.ID) err = message.Encrypt(p.keyRing, nil) p.timeIt.stop("encrypt", msg.ID) @@ -171,13 +177,12 @@ func (p *PMAPIProvider) importDraft(msg Message, globalMailbox *Mailbox) (string } func (p *PMAPIProvider) transferMessage(rules transferRules, progress *Progress, msg Message, preparedImportRequestsCh chan map[string]*pmapi.ImportMsgReq) { - importMsgReq, err := p.generateImportMsgReq(msg, rules.globalMailbox) + importMsgReq, err := p.generateImportMsgReq(rules, progress, msg) if err != nil { progress.messageImported(msg.ID, "", err) return } - - if progress.shouldStop() { + if importMsgReq == nil || progress.shouldStop() { return } @@ -191,17 +196,26 @@ func (p *PMAPIProvider) transferMessage(rules transferRules, progress *Progress, p.nextImportRequestsSize += importMsgReqSize } -func (p *PMAPIProvider) generateImportMsgReq(msg Message, globalMailbox *Mailbox) (*pmapi.ImportMsgReq, error) { +func (p *PMAPIProvider) generateImportMsgReq(rules transferRules, progress *Progress, msg Message) (*pmapi.ImportMsgReq, error) { message, attachmentReaders, err := p.parseMessage(msg) if err != nil { return nil, errors.Wrap(err, "failed to parse message") } - p.timeIt.start("encrypt", msg.ID) - body, err := p.encryptMessage(message, attachmentReaders) - p.timeIt.stop("encrypt", msg.ID) - if err != nil { - return nil, errors.Wrap(err, "failed to encrypt message") + var body []byte + if message.IsEncrypted() { + if rules.skipEncryptedMessages { + progress.messageSkipped(msg.ID) + return nil, nil + } + body = msg.Body + } else { + p.timeIt.start("encrypt", msg.ID) + body, err = p.encryptMessage(message, attachmentReaders) + p.timeIt.stop("encrypt", msg.ID) + if err != nil { + return nil, errors.Wrap(err, "failed to encrypt message") + } } unread := 0 @@ -216,8 +230,8 @@ func (p *PMAPIProvider) generateImportMsgReq(msg Message, globalMailbox *Mailbox labelIDs = append(labelIDs, target.ID) } } - if globalMailbox != nil { - labelIDs = append(labelIDs, globalMailbox.ID) + if rules.globalMailbox != nil { + labelIDs = append(labelIDs, rules.globalMailbox.ID) } return &pmapi.ImportMsgReq{ diff --git a/internal/transfer/rules.go b/internal/transfer/rules.go index bfbc572d..26a13487 100644 --- a/internal/transfer/rules.go +++ b/internal/transfer/rules.go @@ -49,7 +49,7 @@ type transferRules struct { globalToTime int64 // skipEncryptedMessages determines whether message which cannot - // be decrypted should be exported or skipped. + // be decrypted should be imported/exported or skipped. skipEncryptedMessages bool } diff --git a/internal/transfer/transfer.go b/internal/transfer/transfer.go index 1bf6f7ef..ec37a80f 100644 --- a/internal/transfer/transfer.go +++ b/internal/transfer/transfer.go @@ -90,7 +90,7 @@ func (t *Transfer) setDefaultRules() error { } // SetSkipEncryptedMessages sets whether message which cannot be decrypted -// should be exported or skipped. +// should be imported/exported or skipped. func (t *Transfer) SetSkipEncryptedMessages(skip bool) { t.rules.setSkipEncryptedMessages(skip) } diff --git a/pkg/pmapi/import.go b/pkg/pmapi/import.go index 6f179c6f..64cc3e4b 100644 --- a/pkg/pmapi/import.go +++ b/pkg/pmapi/import.go @@ -67,6 +67,14 @@ func (req *ImportReq) WriteTo(w *multipart.Writer) (err error) { if _, err = fw.Write(msg.Body); err != nil { return } + + // Adding new line to properly fetch the whole body on the API side. + // The reason is the bug in PHP: https://bugs.php.net/bug.php?id=75923 + // Messages generated by PM already have it but importing already + // encrypted messages might not have it. + if _, err = fw.Write([]byte("\r\n")); err != nil { + return + } } return err diff --git a/pkg/pmapi/import_test.go b/pkg/pmapi/import_test.go index 38d8fe91..d6b2e9b5 100644 --- a/pkg/pmapi/import_test.go +++ b/pkg/pmapi/import_test.go @@ -127,7 +127,7 @@ func TestClient_Import(t *testing.T) { // nolint[funlen] t.Error("Expected no error while reading second part body, got:", err) } - if string(b) != string(testImportReqs[0].Body) { + if string(b) != string(testImportReqs[0].Body)+"\r\n" { t.Errorf("Invalid message body: expected %v but got %v", string(testImportReqs[0].Body), string(b)) } diff --git a/pkg/pmapi/messages.go b/pkg/pmapi/messages.go index 32ee60d2..b6114a02 100644 --- a/pkg/pmapi/messages.go +++ b/pkg/pmapi/messages.go @@ -253,6 +253,10 @@ func (m *Message) HasLabelID(labelID string) bool { return false } +func (m *Message) IsEncrypted() bool { + return strings.HasPrefix(m.Header.Get("Content-Type"), "multipart/encrypted") || m.IsBodyEncrypted() +} + func (m *Message) IsBodyEncrypted() bool { trimmedBody := strings.TrimSpace(m.Body) return strings.HasPrefix(trimmedBody, MessageHeader) && diff --git a/test/context/context.go b/test/context/context.go index 7dcc6d7b..59f76737 100644 --- a/test/context/context.go +++ b/test/context/context.go @@ -68,10 +68,11 @@ type TestContext struct { smtpLastResponses map[string]*mocks.SMTPResponse // Transfer related variables. - transferLocalRootForImport string - transferLocalRootForExport string - transferRemoteIMAPServer *mocks.IMAPServer - transferProgress *transfer.Progress + transferLocalRootForImport string + transferLocalRootForExport string + transferRemoteIMAPServer *mocks.IMAPServer + transferProgress *transfer.Progress + transferSkipEncryptedMessages bool // Store releated variables. bddMessageIDsToAPIIDs map[string]string diff --git a/test/context/transfer.go b/test/context/transfer.go index a2e792ae..259acada 100644 --- a/test/context/transfer.go +++ b/test/context/transfer.go @@ -37,6 +37,16 @@ func (ctx *TestContext) GetTransferProgress() *transfer.Progress { return ctx.transferProgress } +// SetTransferSkipEncryptedMessages sets whether encrypted messages will be skipped. +func (ctx *TestContext) SetTransferSkipEncryptedMessages(value bool) { + ctx.transferSkipEncryptedMessages = value +} + +// GetTransferSkipEncryptedMessages gets whether encrypted messages will be skipped. +func (ctx *TestContext) GetTransferSkipEncryptedMessages() bool { + return ctx.transferSkipEncryptedMessages +} + // GetTransferLocalRootForImport creates temporary root for importing // if it not exists yet, and returns its path. func (ctx *TestContext) GetTransferLocalRootForImport() string { diff --git a/test/features/ie/transfer/import_encrypted.feature b/test/features/ie/transfer/import_encrypted.feature new file mode 100644 index 00000000..8969ca0f --- /dev/null +++ b/test/features/ie/transfer/import_encrypted.feature @@ -0,0 +1,183 @@ +Feature: Import from EML files + Background: + Given there is connected user "user" + And there is EML file "Inbox/clear.eml" + """ + Subject: clear + From: Bridge Test + To: Internal Bridge + + secret + """ + And there is EML file "Inbox/encrypted.eml" + """ + Subject: encrypted + From: Bridge Test + To: Internal Bridge + + -----BEGIN PGP MESSAGE----- + + hQEMA7hGUUsYs0fEAQgA10NwJSNTLm3vpxVtoYBaA9AjFI5H4hKuV3/f2NHbWb2s + k5enK3tEIOYdFdrO+NLrV6weHq3Dgu4er3URTQ62tFwjSJyeXxmY0d9J+JdxibJg + wqZubuSHYzQHpFqJgoUUWEVEsv0Ao8yQo8BE9iybCKoZf6KojROUuE748oxlxJnV + m1XuaVIzgw4xN0GUA5sLLuWeL94b2dZe5SDDQE5POzDgueZ7faefX8U1pGErCRJ0 + sO6FSw3SF4NpvrxVESWgCmsG5pcuxE2JqB0UoHnNDcqsW8w1Q+GabAPo6UqHhgIg + 56MRCWeou2djHIIj9TMUIVFzSG/HvTYQWVS+i4Z7AdJJAXr53GgbZQznO80Qxwcb + FFdlwOXHuaXqhqCb338jlQWnbcnUsuJWxBAxkHrlP/nluFqPdIBOglC38kdYSBed + 3YwuEB9sXV/fcw== + =B05V + -----END PGP MESSAGE----- + """ + And there is EML file "Inbox/encrypted-mime.eml" + """ + Subject: encrypted mime + From: Bridge Test + To: Internal Bridge + MIME-Version: 1.0 + Content-Type: multipart/encrypted; protocol="application/pgp-encrypted"; boundary="WLjzd46aUAiOcuNXjWTJItBZonI56MuAk" + + --WLjzd46aUAiOcuNXjWTJItBZonI56MuAk + Content-Type: application/pgp-encrypted + Content-Description: PGP/MIME version identification + + + --WLjzd46aUAiOcuNXjWTJItBZonI56MuAk + Content-Type: application/octet-stream; name="encrypted.asc" + Content-Description: OpenPGP encrypted message + Content-Disposition: inline; filename="encrypted.asc" + + -----BEGIN PGP MESSAGE----- + + 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 + =4M3l + -----END PGP MESSAGE----- + + --WLjzd46aUAiOcuNXjWTJItBZonI56MuAk-- + """ + And there is EML file "Inbox/signed.eml" + """ + Subject: signed + From: Bridge Test + To: Internal Bridge + + -----BEGIN PGP SIGNED MESSAGE----- + Hash: SHA256 + + secret + -----BEGIN PGP SIGNATURE----- + + iQEzBAEBCAAdFiEENaE2ZPemenI4pZah/SJcGo7SJWIFAl+cCAgACgkQ/SJcGo7S + JWKsOQf/YakNXkMNjZIu8Hf1WflxtiDXVzTugOicC05k5W64oIqSHt0xNaFKE37k + //3eDMWbHvqHKFVdg7qcLsVPeVBaW3bdZUiexGM24OiGgyEitufnHQLOtEDTound + JyH5nUeHpvpBKIIOJZNBDM0HsRYnwKwrOWk3N2VRwog4J8J3cmJ/f9bPWNI/0OPT + qmtVGRVg6Ge83nZn51Vof//jFzkO4wGYCsE0aF0Ywc7nISZuyKQzmu/qgmwzDG50 + PjpvIQ/ygisRPNdRlylXEqyoIDCQ+v0AnxhhwX/5dbt6xMuMMOxBrFSC94Zce1Vj + x2ssXlT4ONPnkI/YWwhtQPLU628IMg== + =GiS3 + -----END PGP SIGNATURE----- + """ + And there is EML file "Inbox/encrypted-signed.eml" + """ + Subject: encrypted and signed + From: Bridge Test + To: Internal Bridge + + -----BEGIN PGP MESSAGE----- + + hQEMA7hGUUsYs0fEAQf/dppHciWIf+o4l0gEfHeyHV/HVhG4es0aVQYrwFQlSWVx + estMuyLBSMfrsQXLago7Q9ZNo/XnKszzprCXxxYH52hAg64oAsjKB3jgRmVizs8b + 8lj0BRf003wUluS/0msV9SiEZBGeL8jGq6Te9vaM8OHHhIVzVjGnRdTSC0jBE6cS + vy8IBHXYe0LfdZiPojPDPGQdSej+H3uu7eZGBvVHTDeQLPDel4k7Ykdr0qlNXs6O + 5XpM5YG4w+t0aG+YROPH+BUj8PpPojQ/lrv/yFISTRbHlEd8N50w8BNTnBet+9Vm + oPcyvN+RQxBlvRuPpDjUmREvmtObKZV6+m6gocemx9LAzQEeVLcpjO/hJhl8gX72 + MNz3McU7aXf5sSoOPdHDNx8T2NON/2bwG5FE+PRMuVywTKhCB7o8VAsJpGMQ8xRM + 5WCNhow0AI7kni8yZA+GbvspnJWfit9tCTR5MIFHCSH9J3kJJnWkxQSN04GGpBcd + n43GWn7O7ufA4lMMZiGXMdi/J1iV9waAsIfMPk29BMq6xK0/jJYdHqQS+vNsSnF5 + xL/Ir4RYq4SFFA06A/E7HpXr2ruZhBQCkzaIIdrVJR/Lp2VLJIVulTBQK8y2AFtj + JeeKS0kIuC/7UPF2O624kwNr8dmIhDJYusFs6ZeED/nAKwDO/vP2CSwVC3sUjn3N + u+sWqQUTxSmjhRVf9b0+VyTh0mXCovJQXomL6Zz6lxXuJqqzELIOfCxYD1z9GwTG + cT08Aa2eEpf3agdLCTxvjO3iq9FksMHvIN+LSCQ6Pw+aTByjrk0oMmvGbANAogTk + yrplG/iRVlmq0p/Cfl5UEjKqT/nt5j9zbpeuYXmhjiBT9SBE07oUVLY1VT7ihcY= + =qYnL + -----END PGP MESSAGE----- + """ + + Scenario: Import encrypted + Given there is skip encrypted messages set to "false" + When user "user" imports local files + Then progress result is "OK" + And transfer failed for 0 messages + And transfer exported 5 messages + And transfer imported 5 messages + And transfer skipped 0 messages + And API mailbox "INBOX" for "user" has messages + | from | to | subject | + | bridgetest@pm.test | test@protonmail.com | clear | + | bridgetest@pm.test | test@protonmail.com | encrypted | + | bridgetest@pm.test | test@protonmail.com | encrypted mime | + | bridgetest@pm.test | test@protonmail.com | signed | + | bridgetest@pm.test | test@protonmail.com | encrypted and signed | + + Scenario: Skip encrypted + Given there is skip encrypted messages set to "true" + When user "user" imports local files + Then progress result is "OK" + And transfer failed for 0 messages + And transfer exported 5 messages + And transfer imported 2 messages + And transfer skipped 3 messages + And API mailbox "INBOX" for "user" has messages + | from | to | subject | + | bridgetest@pm.test | test@protonmail.com | clear | + | bridgetest@pm.test | test@protonmail.com | signed | diff --git a/test/transfer_actions_test.go b/test/transfer_actions_test.go index ae049c2e..f5b86b7a 100644 --- a/test/transfer_actions_test.go +++ b/test/transfer_actions_test.go @@ -143,6 +143,7 @@ func doTransfer(bddUserID, bddAddressID string, rules *gherkin.DataTable, getTra if err := setRules(transferrer, rules); err != nil { return internalError(err, "failed to set rules") } + transferrer.SetSkipEncryptedMessages(ctx.GetTransferSkipEncryptedMessages()) progress := transferrer.Start() ctx.SetTransferProgress(progress) return nil diff --git a/test/transfer_checks_test.go b/test/transfer_checks_test.go index 1ab5ac15..e1ea01fa 100644 --- a/test/transfer_checks_test.go +++ b/test/transfer_checks_test.go @@ -40,6 +40,7 @@ func TransferChecksFeatureContext(s *godog.Suite) { s.Step(`^progress result is "([^"]*)"$`, progressFinishedWith) s.Step(`^transfer exported (\d+) messages$`, transferExportedNumberOfMessages) s.Step(`^transfer imported (\d+) messages$`, transferImportedNumberOfMessages) + s.Step(`^transfer skipped (\d+) messages$`, transferSkippedNumberOfMessages) s.Step(`^transfer failed for (\d+) messages$`, transferFailedForNumberOfMessages) s.Step(`^transfer exported messages$`, transferExportedMessages) s.Step(`^exported messages match the original ones$`, exportedMessagesMatchTheOriginalOnes) @@ -77,6 +78,13 @@ func transferImportedNumberOfMessages(wantCount int) error { return ctx.GetTestingError() } +func transferSkippedNumberOfMessages(wantCount int) error { + progress := ctx.GetTransferProgress() + counts := progress.GetCounts() + a.Equal(ctx.GetTestingT(), uint(wantCount), counts.Skipped) + return ctx.GetTestingError() +} + func transferFailedForNumberOfMessages(wantCount int) error { progress := ctx.GetTransferProgress() failedMessages := progress.GetFailedMessages() diff --git a/test/transfer_setup_test.go b/test/transfer_setup_test.go index b52bec46..68ad076e 100644 --- a/test/transfer_setup_test.go +++ b/test/transfer_setup_test.go @@ -41,6 +41,7 @@ func TransferSetupFeatureContext(s *godog.Suite) { 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) + s.Step(`^there is skip encrypted messages set to "([^"]*)"$`, thereIsSkipEncryptedMessagesSetTo) } func thereAreEMLFiles(messages *gherkin.DataTable) error { @@ -259,3 +260,15 @@ func createFile(fileName, body string) error { _, err = f.WriteString(body) return internalError(err, "failed to write to file") } + +func thereIsSkipEncryptedMessagesSetTo(value string) error { + switch value { + case "true": + ctx.SetTransferSkipEncryptedMessages(true) + case "false": + ctx.SetTransferSkipEncryptedMessages(false) + default: + return fmt.Errorf("expected either true or false, was %v", value) + } + return nil +} diff --git a/unreleased.md b/unreleased.md index 0fb9ce82..cacff4f6 100644 --- a/unreleased.md +++ b/unreleased.md @@ -9,3 +9,5 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/) ### Changed ### Removed +* GODT-651 Build creates proper binary names. +* GODT-148 Allow import (using the Import-Export app) of already encrypted messages as is.