config/forms: allow blacklisting email servers by IP (#518)

Adds a new config entry (EMAIL_SERVER_BLACKLIST, tuple of IPv4 addresses
as strings) and an email validator for registering, which will query all
the MX records for the domain and reject the registration if any of the
A records for any of the MX records are found in the blacklist.
If the query fails, the blacklist is ignored; the email is accepted.
This commit is contained in:
Anna-Maria Meriniemi 2018-08-20 21:29:30 +03:00 committed by Arylide
parent 86b7eb7ccd
commit 8c892f09cc
3 changed files with 49 additions and 3 deletions

View File

@ -59,6 +59,11 @@ EMAIL_BLACKLIST = (
re.compile(r'(?i)@(msn\.com|passport\.(com|net))'), re.compile(r'(?i)@(msn\.com|passport\.(com|net))'),
# '@dodgydomain.tk' # '@dodgydomain.tk'
) )
EMAIL_SERVER_BLACKLIST = (
# Bad mailserver IPs here (MX server.com -> A mail.server.com > 11.22.33.44)
# '1.2.3.4', '11.22.33.44'
)
# Recaptcha keys (https://www.google.com/recaptcha) # Recaptcha keys (https://www.google.com/recaptcha)

View File

@ -14,6 +14,9 @@ from wtforms.validators import (DataRequired, Email, EqualTo, Length, Optional,
from wtforms.widgets import Select as SelectWidget # For DisabledSelectField from wtforms.widgets import Select as SelectWidget # For DisabledSelectField
from wtforms.widgets import HTMLString, html_params # For DisabledSelectField from wtforms.widgets import HTMLString, html_params # For DisabledSelectField
import dns.exception
import dns.resolver
from nyaa import bencode, models, utils from nyaa import bencode, models, utils
from nyaa.extensions import config from nyaa.extensions import config
from nyaa.models import User from nyaa.models import User
@ -69,7 +72,7 @@ def upload_recaptcha_validator_shim(form, field):
return True return True
def register_email_validator(form, field): def register_email_blacklist_validator(form, field):
email_blacklist = app.config.get('EMAIL_BLACKLIST', []) email_blacklist = app.config.get('EMAIL_BLACKLIST', [])
email = field.data.strip() email = field.data.strip()
validation_exception = StopValidation('Blacklisted email provider') validation_exception = StopValidation('Blacklisted email provider')
@ -86,6 +89,42 @@ def register_email_validator(form, field):
return True return True
def register_email_server_validator(form, field):
server_blacklist = app.config.get('EMAIL_SERVER_BLACKLIST', [])
if not server_blacklist:
return True
validation_exception = StopValidation('Blacklisted email provider')
email = field.data.strip()
email_domain = email.split('@', 1)[-1]
try:
# Query domain MX records
mx_records = list(dns.resolver.query(email_domain, 'MX'))
except dns.exception.DNSException:
app.logger.error('Unable to query MX records for email: %s - ignoring',
email, exc_info=False)
return True
for mx_record in mx_records:
try:
# Query mailserver A records
a_records = list(dns.resolver.query(mx_record.exchange))
for a_record in a_records:
# Check for address in blacklist
if a_record.address in server_blacklist:
app.logger.warning('Rejected email %s due to blacklisted mailserver (%s, %s)',
email, a_record.address, mx_record.exchange)
raise validation_exception
except dns.exception.DNSException:
app.logger.warning('Failed to query A records for mailserver: %s (%s) - ignoring',
mx_record.exchange, email, exc_info=False)
return True
_username_validator = Regexp( _username_validator = Regexp(
r'^[a-zA-Z0-9_\-]+$', r'^[a-zA-Z0-9_\-]+$',
message='Your username must only consist of alphanumerics and _- (a-zA-Z0-9_-)') message='Your username must only consist of alphanumerics and _- (a-zA-Z0-9_-)')
@ -129,8 +168,9 @@ class RegisterForm(FlaskForm):
Email(), Email(),
DataRequired(), DataRequired(),
Length(min=5, max=128), Length(min=5, max=128),
register_email_validator, register_email_blacklist_validator,
Unique(User, User.email, 'Email already in use by another account') Unique(User, User.email, 'Email already in use by another account'),
register_email_server_validator
]) ])
password = PasswordField('Password', [ password = PasswordField('Password', [

View File

@ -6,6 +6,7 @@ blinker==1.4
cffi==1.10.0 cffi==1.10.0
click==6.7 click==6.7
dominate==2.3.1 dominate==2.3.1
dnspython==1.15.0
elasticsearch==5.3.0 elasticsearch==5.3.0
elasticsearch-dsl==5.2.0 elasticsearch-dsl==5.2.0
flake8==3.3.0 flake8==3.3.0