mirror of
https://github.com/axllent/mailpit.git
synced 2025-03-21 21:47:19 +02:00
Security: Sanitize mailbox names
This commit is contained in:
parent
056bef7d5e
commit
1155443785
@ -140,40 +140,44 @@ func MailboxExists(name string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateMailbox will create a collection if it does not exist
|
// CreateMailbox will create a collection if it does not exist
|
||||||
func CreateMailbox(name string) error {
|
func CreateMailbox(mailbox string) error {
|
||||||
if !MailboxExists(name) {
|
mailbox = sanitizeMailboxName(mailbox)
|
||||||
logger.Log().Infof("[db] creating mailbox: %s", name)
|
|
||||||
|
|
||||||
if err := db.CreateCollection(name); err != nil {
|
if !MailboxExists(mailbox) {
|
||||||
|
logger.Log().Infof("[db] creating mailbox: %s", mailbox)
|
||||||
|
|
||||||
|
if err := db.CreateCollection(mailbox); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// create Created index
|
// create Created index
|
||||||
if err := db.CreateIndex(name, "Created"); err != nil {
|
if err := db.CreateIndex(mailbox, "Created"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// create Read index
|
// create Read index
|
||||||
if err := db.CreateIndex(name, "Read"); err != nil {
|
if err := db.CreateIndex(mailbox, "Read"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// create separate collection for data
|
// create separate collection for data
|
||||||
if err := db.CreateCollection(name + "_data"); err != nil {
|
if err := db.CreateCollection(mailbox + "_data"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// create Created index
|
// create Created index
|
||||||
if err := db.CreateIndex(name+"_data", "Created"); err != nil {
|
if err := db.CreateIndex(mailbox+"_data", "Created"); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return statsRefresh(name)
|
return statsRefresh(mailbox)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store will store a message in the database and return the unique ID
|
// Store will store a message in the database and return the unique ID
|
||||||
func Store(mailbox string, b []byte) (string, error) {
|
func Store(mailbox string, b []byte) (string, error) {
|
||||||
|
mailbox = sanitizeMailboxName(mailbox)
|
||||||
|
|
||||||
r := bytes.NewReader(b)
|
r := bytes.NewReader(b)
|
||||||
// Parse message body with enmime.
|
// Parse message body with enmime.
|
||||||
env, err := enmime.ReadEnvelope(r)
|
env, err := enmime.ReadEnvelope(r)
|
||||||
@ -254,6 +258,8 @@ func Store(mailbox string, b []byte) (string, error) {
|
|||||||
// as clover's `Skip()` returns a subset of all results which is much slower.
|
// as clover's `Skip()` returns a subset of all results which is much slower.
|
||||||
// @see https://github.com/ostafen/clover/issues/73
|
// @see https://github.com/ostafen/clover/issues/73
|
||||||
func List(mailbox string, start, limit int) ([]data.Summary, error) {
|
func List(mailbox string, start, limit int) ([]data.Summary, error) {
|
||||||
|
mailbox = sanitizeMailboxName(mailbox)
|
||||||
|
|
||||||
var lastDoc *clover.Document
|
var lastDoc *clover.Document
|
||||||
count := 0
|
count := 0
|
||||||
startAddingAt := start + 1
|
startAddingAt := start + 1
|
||||||
@ -314,6 +320,8 @@ func List(mailbox string, start, limit int) ([]data.Summary, error) {
|
|||||||
|
|
||||||
// Search returns a summary of items mathing a search. It searched the SearchText field.
|
// Search returns a summary of items mathing a search. It searched the SearchText field.
|
||||||
func Search(mailbox, search string, start, limit int) ([]data.Summary, error) {
|
func Search(mailbox, search string, start, limit int) ([]data.Summary, error) {
|
||||||
|
mailbox = sanitizeMailboxName(mailbox)
|
||||||
|
|
||||||
sq := fmt.Sprintf("(?i)%s", cleanString(regexp.QuoteMeta(search)))
|
sq := fmt.Sprintf("(?i)%s", cleanString(regexp.QuoteMeta(search)))
|
||||||
q, err := db.FindAll(clover.NewQuery(mailbox).
|
q, err := db.FindAll(clover.NewQuery(mailbox).
|
||||||
Skip(start).
|
Skip(start).
|
||||||
@ -340,11 +348,15 @@ func Search(mailbox, search string, start, limit int) ([]data.Summary, error) {
|
|||||||
|
|
||||||
// Count returns the total number of messages in a mailbox
|
// Count returns the total number of messages in a mailbox
|
||||||
func Count(mailbox string) (int, error) {
|
func Count(mailbox string) (int, error) {
|
||||||
|
mailbox = sanitizeMailboxName(mailbox)
|
||||||
|
|
||||||
return db.Count(clover.NewQuery(mailbox))
|
return db.Count(clover.NewQuery(mailbox))
|
||||||
}
|
}
|
||||||
|
|
||||||
// CountUnread returns the unread number of messages in a mailbox
|
// CountUnread returns the unread number of messages in a mailbox
|
||||||
func CountUnread(mailbox string) (int, error) {
|
func CountUnread(mailbox string) (int, error) {
|
||||||
|
mailbox = sanitizeMailboxName(mailbox)
|
||||||
|
|
||||||
return db.Count(
|
return db.Count(
|
||||||
clover.NewQuery(mailbox).
|
clover.NewQuery(mailbox).
|
||||||
Where(clover.Field("Read").IsFalse()),
|
Where(clover.Field("Read").IsFalse()),
|
||||||
@ -355,6 +367,8 @@ func CountUnread(mailbox string) (int, error) {
|
|||||||
// ID must be supplied as this is not stored within the CloverStore but rather the
|
// ID must be supplied as this is not stored within the CloverStore but rather the
|
||||||
// *clover.Document
|
// *clover.Document
|
||||||
func GetMessage(mailbox, id string) (*data.Message, error) {
|
func GetMessage(mailbox, id string) (*data.Message, error) {
|
||||||
|
mailbox = sanitizeMailboxName(mailbox)
|
||||||
|
|
||||||
q, err := db.FindById(mailbox+"_data", id)
|
q, err := db.FindById(mailbox+"_data", id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -440,6 +454,8 @@ func GetMessage(mailbox, id string) (*data.Message, error) {
|
|||||||
|
|
||||||
// GetAttachmentPart returns an *enmime.Part (attachment or inline) from a message
|
// GetAttachmentPart returns an *enmime.Part (attachment or inline) from a message
|
||||||
func GetAttachmentPart(mailbox, id, partID string) (*enmime.Part, error) {
|
func GetAttachmentPart(mailbox, id, partID string) (*enmime.Part, error) {
|
||||||
|
mailbox = sanitizeMailboxName(mailbox)
|
||||||
|
|
||||||
data, err := GetMessageRaw(mailbox, id)
|
data, err := GetMessageRaw(mailbox, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -475,6 +491,8 @@ func GetAttachmentPart(mailbox, id, partID string) (*enmime.Part, error) {
|
|||||||
|
|
||||||
// GetMessageRaw returns an []byte of the full message
|
// GetMessageRaw returns an []byte of the full message
|
||||||
func GetMessageRaw(mailbox, id string) ([]byte, error) {
|
func GetMessageRaw(mailbox, id string) ([]byte, error) {
|
||||||
|
mailbox = sanitizeMailboxName(mailbox)
|
||||||
|
|
||||||
q, err := db.FindById(mailbox+"_data", id)
|
q, err := db.FindById(mailbox+"_data", id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -491,6 +509,8 @@ func GetMessageRaw(mailbox, id string) ([]byte, error) {
|
|||||||
|
|
||||||
// UnreadMessage will delete all messages from a mailbox
|
// UnreadMessage will delete all messages from a mailbox
|
||||||
func UnreadMessage(mailbox, id string) error {
|
func UnreadMessage(mailbox, id string) error {
|
||||||
|
mailbox = sanitizeMailboxName(mailbox)
|
||||||
|
|
||||||
updates := make(map[string]interface{})
|
updates := make(map[string]interface{})
|
||||||
updates["Read"] = false
|
updates["Read"] = false
|
||||||
|
|
||||||
@ -501,6 +521,8 @@ func UnreadMessage(mailbox, id string) error {
|
|||||||
|
|
||||||
// DeleteOneMessage will delete a single message from a mailbox
|
// DeleteOneMessage will delete a single message from a mailbox
|
||||||
func DeleteOneMessage(mailbox, id string) error {
|
func DeleteOneMessage(mailbox, id string) error {
|
||||||
|
mailbox = sanitizeMailboxName(mailbox)
|
||||||
|
|
||||||
q, err := db.FindById(mailbox, id)
|
q, err := db.FindById(mailbox, id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -519,6 +541,7 @@ func DeleteOneMessage(mailbox, id string) error {
|
|||||||
|
|
||||||
// DeleteAllMessages will delete all messages from a mailbox
|
// DeleteAllMessages will delete all messages from a mailbox
|
||||||
func DeleteAllMessages(mailbox string) error {
|
func DeleteAllMessages(mailbox string) error {
|
||||||
|
mailbox = sanitizeMailboxName(mailbox)
|
||||||
|
|
||||||
totalStart := time.Now()
|
totalStart := time.Now()
|
||||||
|
|
||||||
|
@ -15,6 +15,8 @@ var (
|
|||||||
|
|
||||||
// StatsGet returns the total/unread statistics for a mailbox
|
// StatsGet returns the total/unread statistics for a mailbox
|
||||||
func StatsGet(mailbox string) data.MailboxStats {
|
func StatsGet(mailbox string) data.MailboxStats {
|
||||||
|
mailbox = sanitizeMailboxName(mailbox)
|
||||||
|
|
||||||
statsLock.Lock()
|
statsLock.Lock()
|
||||||
defer statsLock.Unlock()
|
defer statsLock.Unlock()
|
||||||
s, ok := mailboxStats[mailbox]
|
s, ok := mailboxStats[mailbox]
|
||||||
|
@ -92,3 +92,11 @@ func pruneCron() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SanitizeMailboxName returns a clean mailbox name
|
||||||
|
// allowing only `alphanumeric` characters and `-``
|
||||||
|
func sanitizeMailboxName(mailbox string) string {
|
||||||
|
re := regexp.MustCompile(`[^a-zA-Z0-9\-]`)
|
||||||
|
|
||||||
|
return re.ReplaceAllString(mailbox, "")
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user