Add support for wildcards in the email domain blocklist.

Eg: *.example.com, *.mail.example.com etc.

Closes #1275. Closes #1276.
This commit is contained in:
Kailash Nadh 2023-04-09 14:03:44 +05:30
parent 98729f63df
commit 3baf18ea45

View file

@ -24,7 +24,6 @@ import (
"sync" "sync"
"github.com/gofrs/uuid" "github.com/gofrs/uuid"
"github.com/knadh/koanf/maps"
"github.com/knadh/listmonk/internal/i18n" "github.com/knadh/listmonk/internal/i18n"
"github.com/knadh/listmonk/models" "github.com/knadh/listmonk/models"
"github.com/lib/pq" "github.com/lib/pq"
@ -52,10 +51,11 @@ const (
// Importer represents the bulk CSV subscriber import system. // Importer represents the bulk CSV subscriber import system.
type Importer struct { type Importer struct {
opt Options opt Options
db *sql.DB db *sql.DB
i18n *i18n.I18n i18n *i18n.I18n
domainBlocklist map[string]bool domainBlocklist map[string]bool
hasBlocklistWildcards bool
stop chan bool stop chan bool
status Status status Status
@ -135,10 +135,24 @@ func New(opt Options, db *sql.DB, i *i18n.I18n) *Importer {
opt: opt, opt: opt,
db: db, db: db,
i18n: i, i18n: i,
domainBlocklist: maps.StringSliceToLookupMap(opt.DomainBlocklist), domainBlocklist: make(map[string]bool, len(opt.DomainBlocklist)),
status: Status{Status: StatusNone, logBuf: bytes.NewBuffer(nil)}, status: Status{Status: StatusNone, logBuf: bytes.NewBuffer(nil)},
stop: make(chan bool, 1), stop: make(chan bool, 1),
} }
// Domain blocklist.
for _, d := range opt.DomainBlocklist {
im.domainBlocklist[d] = true
// Domains with *. as the subdomain prefix, strip that
// and add the full domain to the blocklist as welll.
// eg: *.example.com => example.com
if strings.Contains(d, "*.") {
im.hasBlocklistWildcards = true
im.domainBlocklist[strings.TrimPrefix(d, "*.")] = true
}
}
return &im return &im
} }
@ -587,13 +601,31 @@ func (im *Importer) SanitizeEmail(email string) (string, error) {
return "", errors.New(im.i18n.T("subscribers.invalidEmail")) return "", errors.New(im.i18n.T("subscribers.invalidEmail"))
} }
// Check if the e-mail's domain is blocklisted. // Check if the e-mail's domain is blocklisted. The e-mail domain and blocklist config
// are always lowercase.
d := strings.Split(em.Address, "@") d := strings.Split(em.Address, "@")
if len(d) == 2 { if len(d) == 2 {
_, ok := im.domainBlocklist[d[1]] domain := d[1]
if ok {
// Check the domain as-is.
if _, ok := im.domainBlocklist[domain]; ok {
return "", errors.New(im.i18n.T("subscribers.domainBlocklisted")) return "", errors.New(im.i18n.T("subscribers.domainBlocklisted"))
} }
// If there are wildcards in the blocklist and the email domain has a subdomain, check that.
if im.hasBlocklistWildcards && strings.Count(domain, ".") > 1 {
parts := strings.Split(domain, ".")
// Replace the first part of the subdomain with * and check if that exists in the blocklist.
// Eg: test.mail.example.com => *.mail.example.com
parts[0] = "*"
domain = strings.Join(parts, ".")
if _, ok := im.domainBlocklist[domain]; ok {
return "", errors.New(im.i18n.T("subscribers.domainBlocklisted"))
}
}
} }
return em.Address, nil return em.Address, nil