mirror of
https://github.com/mjl-/mox.git
synced 2025-06-28 01:08:15 +03:00
Don't allow mailboxes named "." or ".." and normalize names during imports too
It only serves to confuse. When exporting such mailboxes in zip files or tar files, extracting will cause trouble.
This commit is contained in:
parent
7872b138a5
commit
e572d01341
@ -19,12 +19,22 @@ func TestCreate(t *testing.T) {
|
||||
tc.transactf("no", "create inbox") // Already exists and not allowed. ../rfc/9051:1913
|
||||
tc.transactf("no", "create Inbox") // Idem.
|
||||
|
||||
// Don't allow names that can cause trouble when exporting to directories.
|
||||
tc.transactf("no", "create .")
|
||||
tc.transactf("no", "create ..")
|
||||
tc.transactf("no", "create legit/..")
|
||||
tc.transactf("ok", "create ...") // No special meaning.
|
||||
|
||||
// ../rfc/9051:1937
|
||||
tc.transactf("ok", "create inbox/a/c")
|
||||
tc.xuntagged(imapclient.UntaggedList{Flags: []string{`\Subscribed`}, Separator: '/', Mailbox: "Inbox/a"}, imapclient.UntaggedList{Flags: []string{`\Subscribed`}, Separator: '/', Mailbox: "Inbox/a/c"})
|
||||
|
||||
tc2.transactf("ok", "noop")
|
||||
tc2.xuntagged(imapclient.UntaggedList{Flags: []string{`\Subscribed`}, Separator: '/', Mailbox: "Inbox/a"}, imapclient.UntaggedList{Flags: []string{`\Subscribed`}, Separator: '/', Mailbox: "Inbox/a/c"})
|
||||
tc2.xuntagged(
|
||||
imapclient.UntaggedList{Flags: []string{`\Subscribed`}, Separator: '/', Mailbox: "..."},
|
||||
imapclient.UntaggedList{Flags: []string{`\Subscribed`}, Separator: '/', Mailbox: "Inbox/a"},
|
||||
imapclient.UntaggedList{Flags: []string{`\Subscribed`}, Separator: '/', Mailbox: "Inbox/a/c"},
|
||||
)
|
||||
|
||||
tc.transactf("no", "create inbox/a/c") // Exists.
|
||||
|
||||
|
@ -16,6 +16,8 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/text/unicode/norm"
|
||||
|
||||
"github.com/mjl-/mox/config"
|
||||
"github.com/mjl-/mox/message"
|
||||
"github.com/mjl-/mox/metrics"
|
||||
@ -189,6 +191,11 @@ func importctl(ctx context.Context, ctl *ctl, mbox bool) {
|
||||
var mdnewf, mdcurf *os.File
|
||||
var msgreader store.MsgSource
|
||||
|
||||
// Ensure normalized form.
|
||||
mailbox = norm.NFC.String(mailbox)
|
||||
mailbox, _, err = store.CheckMailboxName(mailbox, true)
|
||||
ctl.xcheck(err, "checking mailbox name")
|
||||
|
||||
// Open account, creating a database file if it doesn't exist yet. It must be known
|
||||
// in the configuration file.
|
||||
a, err := store.OpenAccount(ctl.log, account, false)
|
||||
|
@ -2355,6 +2355,8 @@ func (a *Account) Subjectpass(email string) (key string, err error) {
|
||||
//
|
||||
// Modseq is used, and initialized if 0, for created mailboxes.
|
||||
//
|
||||
// Name must be in normalized form, see CheckMailboxName.
|
||||
//
|
||||
// Caller must hold account wlock.
|
||||
// Caller must propagate changes if any.
|
||||
func (a *Account) MailboxEnsure(tx *bstore.Tx, name string, subscribe bool, specialUse SpecialUse, modseq *ModSeq) (mb Mailbox, changes []Change, rerr error) {
|
||||
@ -3341,7 +3343,7 @@ func MailboxID(tx *bstore.Tx, id int64) (Mailbox, error) {
|
||||
// The mailbox is created with special-use flags, with those flags taken away from
|
||||
// other mailboxes if they have them, reflected in the returned changes.
|
||||
//
|
||||
// Name must be in normalized form.
|
||||
// Name must be in normalized form, see CheckMailboxName.
|
||||
func (a *Account) MailboxCreate(tx *bstore.Tx, name string, specialUse SpecialUse) (nmb Mailbox, changes []Change, created []string, exists bool, rerr error) {
|
||||
elems := strings.Split(name, "/")
|
||||
var p string
|
||||
@ -3375,7 +3377,7 @@ func (a *Account) MailboxCreate(tx *bstore.Tx, name string, specialUse SpecialUs
|
||||
// MailboxRename renames mailbox mbsrc to dst, including children of mbsrc, and
|
||||
// adds missing parents for dst.
|
||||
//
|
||||
// Names must be in normalized form and cannot be Inbox.
|
||||
// Name must be in normalized form, see CheckMailboxName, and cannot be Inbox.
|
||||
func (a *Account) MailboxRename(tx *bstore.Tx, mbsrc *Mailbox, dst string, modseq *ModSeq) (changes []Change, isInbox, alreadyExists bool, rerr error) {
|
||||
if mbsrc.Name == "Inbox" || dst == "Inbox" {
|
||||
return nil, true, false, fmt.Errorf("inbox cannot be renamed")
|
||||
@ -3576,8 +3578,8 @@ func (a *Account) MailboxDelete(ctx context.Context, log mlog.Log, tx *bstore.Tx
|
||||
// If name is the inbox, and allowInbox is false, this is indicated with the isInbox return parameter.
|
||||
// For that case, and for other invalid names, an error is returned.
|
||||
func CheckMailboxName(name string, allowInbox bool) (normalizedName string, isInbox bool, rerr error) {
|
||||
first := strings.SplitN(name, "/", 2)[0]
|
||||
if strings.EqualFold(first, "inbox") {
|
||||
t := strings.Split(name, "/")
|
||||
if strings.EqualFold(t[0], "inbox") {
|
||||
if len(name) == len("inbox") && !allowInbox {
|
||||
return "", true, fmt.Errorf("special mailbox name Inbox not allowed")
|
||||
}
|
||||
@ -3588,8 +3590,15 @@ func CheckMailboxName(name string, allowInbox bool) (normalizedName string, isIn
|
||||
return "", false, errors.New("non-unicode-normalized mailbox names not allowed")
|
||||
}
|
||||
|
||||
if name == "" {
|
||||
return "", false, errors.New("empty mailbox name")
|
||||
for _, e := range t {
|
||||
switch e {
|
||||
case "":
|
||||
return "", false, errors.New("empty mailbox name")
|
||||
case ".":
|
||||
return "", false, errors.New(`"." not allowed`)
|
||||
case "..":
|
||||
return "", false, errors.New(`".." not allowed`)
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(name, "/") || strings.HasSuffix(name, "/") || strings.Contains(name, "//") {
|
||||
return "", false, errors.New("bad slashes in mailbox name")
|
||||
|
@ -433,10 +433,10 @@ func importMessages(ctx context.Context, log mlog.Log, token string, acc *store.
|
||||
}
|
||||
|
||||
xensureMailbox := func(name string) *store.Mailbox {
|
||||
// Ensure name is normalized.
|
||||
name = norm.NFC.String(name)
|
||||
if strings.ToLower(name) == "inbox" {
|
||||
name = "Inbox"
|
||||
}
|
||||
name, _, err := store.CheckMailboxName(name, true)
|
||||
ximportcheckf(err, "checking mailbox name")
|
||||
|
||||
if mb, ok := mailboxNames[name]; ok {
|
||||
return mb
|
||||
|
Loading…
x
Reference in New Issue
Block a user