diff --git a/config.example.py b/config.example.py index b4b3093..eeb7722 100644 --- a/config.example.py +++ b/config.example.py @@ -59,6 +59,11 @@ EMAIL_BLACKLIST = ( re.compile(r'(?i)@(msn\.com|passport\.(com|net))'), # '@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) diff --git a/nyaa/forms.py b/nyaa/forms.py index 662794b..649ad50 100644 --- a/nyaa/forms.py +++ b/nyaa/forms.py @@ -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 HTMLString, html_params # For DisabledSelectField +import dns.exception +import dns.resolver + from nyaa import bencode, models, utils from nyaa.extensions import config from nyaa.models import User @@ -69,7 +72,7 @@ def upload_recaptcha_validator_shim(form, field): return True -def register_email_validator(form, field): +def register_email_blacklist_validator(form, field): email_blacklist = app.config.get('EMAIL_BLACKLIST', []) email = field.data.strip() validation_exception = StopValidation('Blacklisted email provider') @@ -86,6 +89,42 @@ def register_email_validator(form, field): 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( r'^[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(), DataRequired(), Length(min=5, max=128), - register_email_validator, - Unique(User, User.email, 'Email already in use by another account') + register_email_blacklist_validator, + Unique(User, User.email, 'Email already in use by another account'), + register_email_server_validator ]) password = PasswordField('Password', [ diff --git a/requirements.txt b/requirements.txt index cd8049d..308fdd2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,6 +6,7 @@ blinker==1.4 cffi==1.10.0 click==6.7 dominate==2.3.1 +dnspython==1.15.0 elasticsearch==5.3.0 elasticsearch-dsl==5.2.0 flake8==3.3.0