Commit 5efd5abb authored by Joshua Tauberer's avatar Joshua Tauberer

move the email address syntax validation for users and aliases into my new...

move the email address syntax validation for users and aliases into my new email_validator library (https://github.com/JoshData/python-email-validator)
parent 6bb8f5d8
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
import subprocess, shutil, os, sqlite3, re import subprocess, shutil, os, sqlite3, re
import utils import utils
from email_validator import validate_email as validate_email_, EmailNotValidError
def validate_email(email, mode=None): def validate_email(email, mode=None):
# Checks that an email address is syntactically valid. Returns True/False. # Checks that an email address is syntactically valid. Returns True/False.
...@@ -15,60 +16,25 @@ def validate_email(email, mode=None): ...@@ -15,60 +16,25 @@ def validate_email(email, mode=None):
# When mode=="alias", we're allowing anything that can be in a Postfix # When mode=="alias", we're allowing anything that can be in a Postfix
# alias table, i.e. omitting the local part ("@domain.tld") is OK. # alias table, i.e. omitting the local part ("@domain.tld") is OK.
# Check that the address isn't absurdly long. # Check the syntax of the address.
if len(email) > 255: return False try:
validate_email_(email,
allow_smtputf8=False,
check_deliverability=False,
allow_empty_local=(mode=="alias")
)
except EmailNotValidError:
return False
if mode == 'user': if mode == 'user':
# There are a lot of characters permitted in email addresses, but # There are a lot of characters permitted in email addresses, but
# Dovecot's sqlite driver seems to get confused if there are any # Dovecot's sqlite auth driver seems to get confused if there are any
# unusual characters in the address. Bah. Also note that since # unusual characters in the address. Bah. Also note that since
# the mailbox path name is based on the email address, the address # the mailbox path name is based on the email address, the address
# shouldn't be absurdly long and must not have a forward slash. # shouldn't be absurdly long and must not have a forward slash.
ATEXT = r'[a-zA-Z0-9_\-]+' if len(email) > 255: return False
elif mode in (None, 'alias'): if re.search(r'[^\@\.a-zA-Z0-9_\-]+', email):
# For aliases, we can allow any valid email address. return False
# Based on RFC 2822 and https://github.com/SyrusAkbary/validate_email/blob/master/validate_email.py,
# these characters are permitted in email addresses.
ATEXT = r'[a-zA-Z0-9_!#$%&\'\*\+\-/=\?\^`\{\|\}~]+' # see 3.2.4
else:
raise ValueError(mode)
# per RFC 2822 3.2.4
DOT_ATOM_TEXT_LOCAL = ATEXT + r'(?:\.' + ATEXT + r')*'
if mode == 'alias':
# For aliases, Postfix accepts '@domain.tld' format for
# catch-all addresses on the source side and domain aliases
# on the destination side. Make the local part optional.
DOT_ATOM_TEXT_LOCAL = '(?:' + DOT_ATOM_TEXT_LOCAL + ')?'
# The domain part of the email address has a few more restrictions.
# In addition to the characters allowed by RFC 2822, the domain part
# must also satisfy the requirements of RFC 952/RFC 1123 which restrict
# the allowed characters of hostnames further. These are a subset of
# the Dovecot-allowed characters, fortunately. The hyphen cannot be at
# the beginning or end of a component of a hostname either, but we aren't
# testing that.
ATEXT2 = r'[a-zA-Z0-9\-]+'
# We can require that the host part have at least one period in it.
# We also know that all TLDs are at least two characters and end with a letter.
DOT_ATOM_TEXT_HOST = ATEXT2 + r'(?:\.' + ATEXT2 + r')*' + r'(?:\.' + ATEXT2 + r'[A-Za-z])'
# per RFC 2822 3.4.1
ADDR_SPEC = '^(%s)@(%s)$' % (DOT_ATOM_TEXT_LOCAL, DOT_ATOM_TEXT_HOST)
# Check the regular expression.
m = re.match(ADDR_SPEC, email)
if not m: return False
# Check that the domain part is valid IDNA.
localpart, domainpart = m.groups()
try:
domainpart.encode('ascii').decode("idna")
except:
# Domain is not valid IDNA.
return False
# Everything looks good. # Everything looks good.
return True return True
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
source setup/functions.sh source setup/functions.sh
apt_install python3-flask links duplicity libyaml-dev python3-dnspython python3-dateutil apt_install python3-flask links duplicity libyaml-dev python3-dnspython python3-dateutil
hide_output pip3 install rtyaml hide_output pip3 install rtyaml "email_validator==0.1.0-rc1"
# Create a backup directory and a random key for encrypting backups. # Create a backup directory and a random key for encrypting backups.
mkdir -p $STORAGE_ROOT/backup mkdir -p $STORAGE_ROOT/backup
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment