mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-24 21:09:30 +01:00
* Fix #1997 (allow the use of an external file for the email blacklist) * Change config key names for blacklist (compatibility break) * Accept globs rather than regexes for blacklist by default * Blacklist comparison is now case-insensitive
This commit is contained in:
parent
6b386ce2ac
commit
2013beb7c8
@ -418,8 +418,13 @@ accounts:
|
||||
# username: "admin"
|
||||
# password: "hunter2"
|
||||
# implicit-tls: false # TLS from the first byte, typically on port 465
|
||||
blacklist-regexes:
|
||||
# - ".*@mailinator.com"
|
||||
# addresses that are not accepted for registration:
|
||||
address-blacklist:
|
||||
# - "*@mailinator.com"
|
||||
address-blacklist-syntax: "glob" # change to "regex" for regular expressions
|
||||
# file of newline-delimited address blacklist entries in the above syntax;
|
||||
# supersedes address-blacklist if set:
|
||||
# address-blacklist-file: "/path/to/address-blacklist-file"
|
||||
timeout: 60s
|
||||
# email-based password reset:
|
||||
password-reset:
|
||||
|
@ -4,10 +4,13 @@
|
||||
package email
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
@ -23,6 +26,38 @@ var (
|
||||
ErrNoMXRecord = errors.New("Couldn't resolve MX record")
|
||||
)
|
||||
|
||||
type BlacklistSyntax uint
|
||||
|
||||
const (
|
||||
BlacklistSyntaxGlob BlacklistSyntax = iota
|
||||
BlacklistSyntaxRegexp
|
||||
)
|
||||
|
||||
func blacklistSyntaxFromString(status string) (BlacklistSyntax, error) {
|
||||
switch strings.ToLower(status) {
|
||||
case "glob", "":
|
||||
return BlacklistSyntaxGlob, nil
|
||||
case "re", "regex", "regexp":
|
||||
return BlacklistSyntaxRegexp, nil
|
||||
default:
|
||||
return BlacklistSyntaxRegexp, fmt.Errorf("Unknown blacklist syntax type `%s`", status)
|
||||
}
|
||||
}
|
||||
|
||||
func (bs *BlacklistSyntax) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var orig string
|
||||
var err error
|
||||
if err = unmarshal(&orig); err != nil {
|
||||
return err
|
||||
}
|
||||
if result, err := blacklistSyntaxFromString(orig); err == nil {
|
||||
*bs = result
|
||||
return nil
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
type MTAConfig struct {
|
||||
Server string
|
||||
Port int
|
||||
@ -43,7 +78,9 @@ type MailtoConfig struct {
|
||||
VerifyMessageSubject string `yaml:"verify-message-subject"`
|
||||
DKIM DKIMConfig
|
||||
MTAReal MTAConfig `yaml:"mta"`
|
||||
BlacklistRegexes []string `yaml:"blacklist-regexes"`
|
||||
AddressBlacklist []string `yaml:"address-blacklist"`
|
||||
AddressBlacklistSyntax BlacklistSyntax `yaml:"address-blacklist-syntax"`
|
||||
AddressBlacklistFile string `yaml:"address-blacklist-file"`
|
||||
blacklistRegexes []*regexp.Regexp
|
||||
Timeout time.Duration
|
||||
PasswordReset struct {
|
||||
@ -53,6 +90,44 @@ type MailtoConfig struct {
|
||||
} `yaml:"password-reset"`
|
||||
}
|
||||
|
||||
func (config *MailtoConfig) compileBlacklistEntry(source string) (re *regexp.Regexp, err error) {
|
||||
if config.AddressBlacklistSyntax == BlacklistSyntaxGlob {
|
||||
return utils.CompileGlob(source, false)
|
||||
} else {
|
||||
return regexp.Compile(fmt.Sprintf("^%s$", source))
|
||||
}
|
||||
}
|
||||
|
||||
func (config *MailtoConfig) processBlacklistFile(filename string) (result []*regexp.Regexp, err error) {
|
||||
f, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
reader := bufio.NewReader(f)
|
||||
lineNo := 0
|
||||
for {
|
||||
line, err := reader.ReadString('\n')
|
||||
lineNo++
|
||||
line = strings.TrimSpace(line)
|
||||
if line != "" && line[0] != '#' {
|
||||
if compiled, compileErr := config.compileBlacklistEntry(line); compileErr == nil {
|
||||
result = append(result, compiled)
|
||||
} else {
|
||||
return result, fmt.Errorf("Failed to compile line %d of blacklist-regex-file `%s`: %w", lineNo, line, compileErr)
|
||||
}
|
||||
}
|
||||
switch err {
|
||||
case io.EOF:
|
||||
return result, nil
|
||||
case nil:
|
||||
continue
|
||||
default:
|
||||
return result, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (config *MailtoConfig) Postprocess(heloDomain string) (err error) {
|
||||
if config.Sender == "" {
|
||||
return errors.New("Invalid mailto sender address")
|
||||
@ -68,13 +143,21 @@ func (config *MailtoConfig) Postprocess(heloDomain string) (err error) {
|
||||
config.HeloDomain = heloDomain
|
||||
}
|
||||
|
||||
for _, reg := range config.BlacklistRegexes {
|
||||
compiled, err := regexp.Compile(fmt.Sprintf("^%s$", reg))
|
||||
if config.AddressBlacklistFile != "" {
|
||||
config.blacklistRegexes, err = config.processBlacklistFile(config.AddressBlacklistFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if len(config.AddressBlacklist) != 0 {
|
||||
config.blacklistRegexes = make([]*regexp.Regexp, 0, len(config.AddressBlacklist))
|
||||
for _, reg := range config.AddressBlacklist {
|
||||
compiled, err := config.compileBlacklistEntry(reg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.blacklistRegexes = append(config.blacklistRegexes, compiled)
|
||||
}
|
||||
}
|
||||
|
||||
if config.MTAConfig.Server != "" {
|
||||
// smarthost, nothing more to validate
|
||||
@ -118,8 +201,9 @@ func ComposeMail(config MailtoConfig, recipient, subject string) (message bytes.
|
||||
}
|
||||
|
||||
func SendMail(config MailtoConfig, recipient string, msg []byte) (err error) {
|
||||
recipientLower := strings.ToLower(recipient)
|
||||
for _, reg := range config.blacklistRegexes {
|
||||
if reg.MatchString(recipient) {
|
||||
if reg.MatchString(recipientLower) {
|
||||
return ErrBlacklistedAddress
|
||||
}
|
||||
}
|
||||
|
@ -391,8 +391,13 @@ accounts:
|
||||
# username: "admin"
|
||||
# password: "hunter2"
|
||||
# implicit-tls: false # TLS from the first byte, typically on port 465
|
||||
blacklist-regexes:
|
||||
# - ".*@mailinator.com"
|
||||
# addresses that are not accepted for registration:
|
||||
address-blacklist:
|
||||
# - "*@mailinator.com"
|
||||
address-blacklist-syntax: "glob" # change to "regex" for regular expressions
|
||||
# file of newline-delimited address blacklist entries in the above syntax;
|
||||
# supersedes address-blacklist if set:
|
||||
# address-blacklist-file: "/path/to/address-blacklist-file"
|
||||
timeout: 60s
|
||||
# email-based password reset:
|
||||
password-reset:
|
||||
|
Loading…
Reference in New Issue
Block a user