Sanizize mailbox name for exporting

This commit is contained in:
Michal Horejsek
2020-10-16 08:33:52 +02:00
parent cfd8e56277
commit 26fb1fc34d
5 changed files with 50 additions and 3 deletions

View File

@ -8,6 +8,7 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/)
* GODT-749 Don't force PGP/Inline when sending plaintext messages. * GODT-749 Don't force PGP/Inline when sending plaintext messages.
* GODT-764 Fix deadlock in integration tests for Import-Export. * GODT-764 Fix deadlock in integration tests for Import-Export.
* GODT-662 Do not resume paused transfer progress after dismissing cancel popup. * GODT-662 Do not resume paused transfer progress after dismissing cancel popup.
* GODT-772 Sanitize mailbox names for exporting to follow OS restrictions.
### Changed ### Changed
* Bump crypto version to v0.0.0-20200818122824-ed5d25e28db8 * Bump crypto version to v0.0.0-20200818122824-ed5d25e28db8

View File

@ -61,7 +61,7 @@ func (p *EMLProvider) TransferFrom(rules transferRules, progress *Progress, ch <
func (p *EMLProvider) createFolders(rules transferRules) error { func (p *EMLProvider) createFolders(rules transferRules) error {
for rule := range rules.iterateActiveRules() { for rule := range rules.iterateActiveRules() {
for _, mailbox := range rule.TargetMailboxes { for _, mailbox := range rule.TargetMailboxes {
path := filepath.Join(p.root, mailbox.Name) path := filepath.Join(p.root, sanitizeFileName(mailbox.Name))
if err := os.MkdirAll(path, os.ModePerm); err != nil { if err := os.MkdirAll(path, os.ModePerm); err != nil {
return err return err
} }
@ -71,7 +71,7 @@ func (p *EMLProvider) createFolders(rules transferRules) error {
} }
func (p *EMLProvider) writeFile(msg Message) error { func (p *EMLProvider) writeFile(msg Message) error {
fileName := filepath.Base(msg.ID) fileName := sanitizeFileName(filepath.Base(msg.ID))
if filepath.Ext(fileName) != ".eml" { if filepath.Ext(fileName) != ".eml" {
fileName += ".eml" fileName += ".eml"
} }

View File

@ -57,7 +57,7 @@ func (p *MBOXProvider) TransferFrom(rules transferRules, progress *Progress, ch
func (p *MBOXProvider) writeMessage(msg Message) error { func (p *MBOXProvider) writeMessage(msg Message) error {
var multiErr error var multiErr error
for _, mailbox := range msg.Targets { for _, mailbox := range msg.Targets {
mboxName := filepath.Base(mailbox.Name) mboxName := sanitizeFileName(mailbox.Name)
if !strings.HasSuffix(mboxName, ".mbox") { if !strings.HasSuffix(mboxName, ".mbox") {
mboxName += ".mbox" mboxName += ".mbox"
} }

View File

@ -24,6 +24,7 @@ import (
"net/mail" "net/mail"
"net/textproto" "net/textproto"
"path/filepath" "path/filepath"
"runtime"
"sort" "sort"
"strings" "strings"
@ -139,3 +140,24 @@ func getMessageHeader(body []byte) (mail.Header, error) {
} }
return mail.Header(header), nil return mail.Header(header), nil
} }
// sanitizeFileName replaces problematic special characters with underscore.
func sanitizeFileName(fileName string) string {
if len(fileName) == 0 {
return fileName
}
if runtime.GOOS != "windows" && (fileName[0] == '-' || fileName[0] == '.') { //nolint[goconst]
fileName = "_" + fileName[1:]
}
return strings.Map(func(r rune) rune {
switch r {
case '\\', '/', ':', '*', '?', '"', '<', '>', '|':
return '_'
case '[', ']', '(', ')', '{', '}', '^', '#', '%', '&', '!', '@', '+', '=', '\'', '~':
if runtime.GOOS != "windows" {
return '_'
}
}
return r
}, fileName)
}

View File

@ -21,6 +21,7 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"path/filepath" "path/filepath"
"runtime"
"testing" "testing"
r "github.com/stretchr/testify/require" r "github.com/stretchr/testify/require"
@ -188,3 +189,26 @@ Body
r.Equal(t, header.Get("subject"), "Hello") r.Equal(t, header.Get("subject"), "Hello")
r.Equal(t, header.Get("from"), "user@example.com") r.Equal(t, header.Get("from"), "user@example.com")
} }
func TestSanitizeFileName(t *testing.T) {
tests := map[string]string{
"hello": "hello",
"a\\b/c:*?d\"<>|e": "a_b_c___d____e",
}
if runtime.GOOS == "darwin" || runtime.GOOS == "linux" {
tests[".hello"] = "_hello"
tests["-hello"] = "_hello"
}
if runtime.GOOS == "windows" {
tests["[hello]&@=~~"] = "_hello______"
}
for path, wantPath := range tests {
path := path
wantPath := wantPath
t.Run(path, func(t *testing.T) {
gotPath := sanitizeFileName(path)
r.Equal(t, wantPath, gotPath)
})
}
}