mirror of
https://github.com/mjl-/mox.git
synced 2025-06-28 05:08:14 +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") // Already exists and not allowed. ../rfc/9051:1913
|
||||||
tc.transactf("no", "create Inbox") // Idem.
|
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
|
// ../rfc/9051:1937
|
||||||
tc.transactf("ok", "create inbox/a/c")
|
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"})
|
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.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.
|
tc.transactf("no", "create inbox/a/c") // Exists.
|
||||||
|
|
||||||
|
@ -16,6 +16,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/text/unicode/norm"
|
||||||
|
|
||||||
"github.com/mjl-/mox/config"
|
"github.com/mjl-/mox/config"
|
||||||
"github.com/mjl-/mox/message"
|
"github.com/mjl-/mox/message"
|
||||||
"github.com/mjl-/mox/metrics"
|
"github.com/mjl-/mox/metrics"
|
||||||
@ -189,6 +191,11 @@ func importctl(ctx context.Context, ctl *ctl, mbox bool) {
|
|||||||
var mdnewf, mdcurf *os.File
|
var mdnewf, mdcurf *os.File
|
||||||
var msgreader store.MsgSource
|
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
|
// Open account, creating a database file if it doesn't exist yet. It must be known
|
||||||
// in the configuration file.
|
// in the configuration file.
|
||||||
a, err := store.OpenAccount(ctl.log, account, false)
|
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.
|
// 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 hold account wlock.
|
||||||
// Caller must propagate changes if any.
|
// 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) {
|
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
|
// 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.
|
// 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) {
|
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, "/")
|
elems := strings.Split(name, "/")
|
||||||
var p string
|
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
|
// MailboxRename renames mailbox mbsrc to dst, including children of mbsrc, and
|
||||||
// adds missing parents for dst.
|
// 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) {
|
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" {
|
if mbsrc.Name == "Inbox" || dst == "Inbox" {
|
||||||
return nil, true, false, fmt.Errorf("inbox cannot be renamed")
|
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.
|
// 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.
|
// For that case, and for other invalid names, an error is returned.
|
||||||
func CheckMailboxName(name string, allowInbox bool) (normalizedName string, isInbox bool, rerr error) {
|
func CheckMailboxName(name string, allowInbox bool) (normalizedName string, isInbox bool, rerr error) {
|
||||||
first := strings.SplitN(name, "/", 2)[0]
|
t := strings.Split(name, "/")
|
||||||
if strings.EqualFold(first, "inbox") {
|
if strings.EqualFold(t[0], "inbox") {
|
||||||
if len(name) == len("inbox") && !allowInbox {
|
if len(name) == len("inbox") && !allowInbox {
|
||||||
return "", true, fmt.Errorf("special mailbox name Inbox not allowed")
|
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")
|
return "", false, errors.New("non-unicode-normalized mailbox names not allowed")
|
||||||
}
|
}
|
||||||
|
|
||||||
if name == "" {
|
for _, e := range t {
|
||||||
return "", false, errors.New("empty mailbox name")
|
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, "//") {
|
if strings.HasPrefix(name, "/") || strings.HasSuffix(name, "/") || strings.Contains(name, "//") {
|
||||||
return "", false, errors.New("bad slashes in mailbox 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 {
|
xensureMailbox := func(name string) *store.Mailbox {
|
||||||
|
// Ensure name is normalized.
|
||||||
name = norm.NFC.String(name)
|
name = norm.NFC.String(name)
|
||||||
if strings.ToLower(name) == "inbox" {
|
name, _, err := store.CheckMailboxName(name, true)
|
||||||
name = "Inbox"
|
ximportcheckf(err, "checking mailbox name")
|
||||||
}
|
|
||||||
|
|
||||||
if mb, ok := mailboxNames[name]; ok {
|
if mb, ok := mailboxNames[name]; ok {
|
||||||
return mb
|
return mb
|
||||||
|
Loading…
x
Reference in New Issue
Block a user