Bug 584490: restricting user email domains with blacklist.
This commit is contained in:
Родитель
80ada91627
Коммит
6bf2218bec
|
@ -1,11 +1,10 @@
|
|||
from django.contrib import admin, messages
|
||||
from django.db.utils import IntegrityError
|
||||
from django.utils.encoding import smart_unicode
|
||||
|
||||
import jingo
|
||||
|
||||
from access.admin import GroupUserInline
|
||||
from .models import UserProfile, BlacklistedUsername
|
||||
from .models import UserProfile, BlacklistedUsername, BlacklistedEmailDomain
|
||||
from .users import forms
|
||||
|
||||
|
||||
|
@ -36,44 +35,56 @@ class UserAdmin(admin.ModelAdmin):
|
|||
)
|
||||
|
||||
|
||||
class BlacklistedUsernameAdmin(admin.ModelAdmin):
|
||||
list_display = search_fields = ('username',)
|
||||
|
||||
class BlacklistModelAdmin(admin.ModelAdmin):
|
||||
def add_view(self, request, form_url='', extra_context=None):
|
||||
"""Override the default admin add view for bulk add."""
|
||||
form = forms.BlacklistedUsernameAddForm()
|
||||
form = self.model_add_form()
|
||||
if request.method == 'POST':
|
||||
form = forms.BlacklistedUsernameAddForm(request.POST)
|
||||
form = self.model_add_form(request.POST)
|
||||
if form.is_valid():
|
||||
inserted = 0
|
||||
duplicates = 0
|
||||
|
||||
for n in form.cleaned_data['usernames'].splitlines():
|
||||
for x in form.cleaned_data[self.add_form_field].splitlines():
|
||||
# check with teh cache
|
||||
if BlacklistedUsername.blocked(n):
|
||||
if self.blacklist_model.blocked(x):
|
||||
duplicates += 1
|
||||
continue
|
||||
n = smart_unicode(n).lower().encode('utf-8')
|
||||
try:
|
||||
BlacklistedUsername.objects.create(username=n)
|
||||
self.blacklist_model.objects.create(
|
||||
**{self.model_field: x.lower()})
|
||||
inserted += 1
|
||||
except IntegrityError:
|
||||
# although unlikely, someone else could have added
|
||||
# the username.
|
||||
# the same value.
|
||||
# note: unless we manage the transactions manually,
|
||||
# we do lose a primary id here
|
||||
# we do lose a primary id here.
|
||||
duplicates += 1
|
||||
msg = '%s new usernames added to the blacklist.' % (inserted)
|
||||
msg = '%s new values added to the blacklist.' % (inserted)
|
||||
if duplicates:
|
||||
msg += ' %s duplicates were ignored.' % (duplicates)
|
||||
messages.success(request, msg)
|
||||
form = forms.BlacklistedUsernameAddForm()
|
||||
# Default django admin change list view does not print messages
|
||||
# no redirect for now
|
||||
# return http.HttpResponseRedirect(reverse(
|
||||
# 'admin:users_blacklistedusername_changelist'))
|
||||
return jingo.render(request, 'admin/blacklisted_username/add.html',
|
||||
{'form': form})
|
||||
form = self.model_add_form()
|
||||
return jingo.render(request, self.template_path, {'form': form})
|
||||
|
||||
|
||||
class BlacklistedUsernameAdmin(BlacklistModelAdmin):
|
||||
list_display = search_fields = ('username',)
|
||||
blacklist_model = BlacklistedUsername
|
||||
model_field = 'username'
|
||||
model_add_form = forms.BlacklistedUsernameAddForm
|
||||
add_form_field = 'usernames'
|
||||
template_path = 'admin/blacklisted_username/add.html'
|
||||
|
||||
|
||||
class BlacklistedEmailDomainAdmin(BlacklistModelAdmin):
|
||||
list_display = search_fields = ('domain',)
|
||||
blacklist_model = BlacklistedEmailDomain
|
||||
model_field = 'domain'
|
||||
model_add_form = forms.BlacklistedEmailDomainAddForm
|
||||
add_form_field = 'domains'
|
||||
template_path = 'admin/blacklisted_email_domain/add.html'
|
||||
|
||||
admin.site.register(UserProfile, UserAdmin)
|
||||
admin.site.register(BlacklistedUsername, BlacklistedUsernameAdmin)
|
||||
admin.site.register(BlacklistedEmailDomain, BlacklistedEmailDomainAdmin)
|
||||
|
|
|
@ -164,5 +164,14 @@
|
|||
"modified": "2010-07-21 23:32:05",
|
||||
"created": "2010-07-21 23:32:05"
|
||||
}
|
||||
},
|
||||
{
|
||||
"pk": 1,
|
||||
"model": "users.blacklistedemaildomain",
|
||||
"fields": {
|
||||
"domain": "mailinator.com",
|
||||
"modified": "2010-09-07 00:31:40",
|
||||
"created": "2010-09-07 00:31:40"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -10,7 +10,7 @@ import commonware.log
|
|||
import happyforms
|
||||
from tower import ugettext as _, ugettext_lazy as _lazy
|
||||
|
||||
from .models import UserProfile, BlacklistedUsername
|
||||
from .models import UserProfile, BlacklistedUsername, BlacklistedEmailDomain
|
||||
import tasks
|
||||
|
||||
log = commonware.log.getLogger('z.users')
|
||||
|
@ -88,6 +88,14 @@ class UserRegisterForm(happyforms.ModelForm):
|
|||
if not settings.RECAPTCHA_PRIVATE_KEY:
|
||||
del self.fields['recaptcha']
|
||||
|
||||
def clean_email(self):
|
||||
d = self.cleaned_data['email'].split('@')[-1]
|
||||
if BlacklistedEmailDomain.blocked(d):
|
||||
raise forms.ValidationError(_('Please use an email address from a '
|
||||
'different provider to complete '
|
||||
'your registration.'))
|
||||
return self.cleaned_data['email']
|
||||
|
||||
def clean_username(self):
|
||||
name = self.cleaned_data['username']
|
||||
if BlacklistedUsername.blocked(name):
|
||||
|
@ -216,3 +224,23 @@ class BlacklistedUsernameAddForm(forms.Form):
|
|||
self._errors['usernames'] = ErrorList([msg])
|
||||
|
||||
return data
|
||||
|
||||
|
||||
class BlacklistedEmailDomainAddForm(forms.Form):
|
||||
"""Form for adding blacklisted user e-mail domains in bulk fashion."""
|
||||
domains = forms.CharField(
|
||||
widget=forms.Textarea(attrs={'cols': 40, 'rows': 16}))
|
||||
|
||||
def clean(self):
|
||||
super(BlacklistedEmailDomainAddForm, self).clean()
|
||||
data = self.cleaned_data
|
||||
|
||||
if 'domains' in data:
|
||||
l = filter(None, [s.strip() for s in data['domains'].splitlines()])
|
||||
data['domains'] = os.linesep.join(l)
|
||||
|
||||
if not data.get('domains', ''):
|
||||
msg = 'Please enter at least one e-mail domain to blacklist.'
|
||||
self._errors['domains'] = ErrorList([msg])
|
||||
|
||||
return data
|
||||
|
|
|
@ -11,7 +11,7 @@ from django.contrib.auth.models import User as DjangoUser
|
|||
from django.core.mail import send_mail
|
||||
from django.db import models
|
||||
from django.template import Context, loader
|
||||
from django.utils.encoding import smart_unicode, smart_str
|
||||
from django.utils.encoding import smart_str
|
||||
|
||||
import caching.base as caching
|
||||
import commonware.log
|
||||
|
@ -301,11 +301,33 @@ class BlacklistedUsername(amo.models.ModelBase):
|
|||
@classmethod
|
||||
def blocked(cls, username):
|
||||
"""Check to see if a username is in the (cached) blacklist."""
|
||||
username = smart_unicode(username).lower()
|
||||
qs = cls.objects.all()
|
||||
f = lambda: [u.lower() for u in qs.values_list('username', flat=True)]
|
||||
blacklist = caching.cached_with(qs, f, 'blocked')
|
||||
return username in blacklist
|
||||
return username.lower() in blacklist
|
||||
|
||||
|
||||
class BlacklistedEmailDomain(amo.models.ModelBase):
|
||||
"""Blacklisted user e-mail domains."""
|
||||
domain = models.CharField(max_length=255, unique=True, default='',
|
||||
blank=False)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.domain
|
||||
|
||||
@classmethod
|
||||
def blocked(cls, domain):
|
||||
qs = cls.objects.all()
|
||||
f = lambda: list(qs.values_list('domain', flat=True))
|
||||
blacklist = caching.cached_with(qs, f, 'blocked')
|
||||
# because there isn't a good way to know if the domain is
|
||||
# "example.com" or "example.co.jp", we'll re-construct it...
|
||||
# so if it's "bad.example.co.jp", the following check the
|
||||
# values in ['bad.example.co.jp', 'example.co.jp', 'co.jp']
|
||||
x = domain.lower().split('.')
|
||||
for d in ['.'.join(x[y:]) for y in range(len(x) - 1)]:
|
||||
if d in blacklist:
|
||||
return True
|
||||
|
||||
|
||||
class PersonaAuthor(unicode):
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
{% extends "admin/base.html" %}
|
||||
{% from 'includes/forms.html' import required %}
|
||||
{% block extrahead %}
|
||||
{{ super() }}
|
||||
<link rel="stylesheet" href="{{ MEDIA_URL }}css/zamboni/admin-django.css">
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}{{ page_title('Add Blacklisted E-mail Domains') }}{% endblock %}
|
||||
|
||||
{% block bodyclass %}users-blacklistedemaildomain change-form{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="breadcrumbs">
|
||||
<a href="{{ url('admin:index') }}">Home</a> ›
|
||||
<a href="{{ url('admin:app_list', app_label='users') }}">Users</a> ›
|
||||
<a href="{{ url('admin:users_blacklistedemaildomain_changelist') }}">Blacklisted e-mail domains</a> ›
|
||||
Add
|
||||
</div>
|
||||
<div id="content" class="colM">
|
||||
<h2>Add Blacklisted E-mail Domains</h2>
|
||||
<div id="content-main">
|
||||
|
||||
{% include "messages.html" %}
|
||||
|
||||
{% if form %}
|
||||
<form method="post" action="">
|
||||
{{ csrf() }}
|
||||
<p>Enter one domain per line.</p>
|
||||
<div class="form-row">
|
||||
{{ form.domains.errors|safe }}
|
||||
<label for="id_usernames">Blacklisted E-mail Domains {{ required() }}</label>
|
||||
{{ form.domains|safe }}
|
||||
</div>
|
||||
<div class="submit-row">
|
||||
<input type="submit" name="_save" class="default" value="Save">
|
||||
</div>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
|
@ -301,6 +301,16 @@ class TestUserRegisterForm(UserFormBase):
|
|||
self.assertFormError(r, 'form', 'username',
|
||||
'This username is invalid.')
|
||||
|
||||
def test_invalid_email_domain(self):
|
||||
data = {'email': 'fake@mailinator.com',
|
||||
'password': 'xxx',
|
||||
'password2': 'xxx',
|
||||
'username': 'trulyfake', }
|
||||
r = self.client.post('/en-US/firefox/users/register', data)
|
||||
self.assertFormError(r, 'form', 'email',
|
||||
'Please use an email address from a different '
|
||||
'provider to complete your registration.')
|
||||
|
||||
def test_invalid_homepage(self):
|
||||
data = {'homepage': 'example.com:alert(String.fromCharCode(88,83,83)'}
|
||||
m = 'This URL has an invalid format. '
|
||||
|
@ -352,7 +362,28 @@ class TestBlacklistedUsernameAdminAddForm(UserFormBase):
|
|||
url = reverse('admin:users_blacklistedusername_add')
|
||||
data = {'usernames': "IE6Fan\nfubar\n\n", }
|
||||
r = self.client.post(url, data)
|
||||
msg = '1 new usernames added to the blacklist. '
|
||||
msg = '1 new values added to the blacklist. '
|
||||
msg += '1 duplicates were ignored.'
|
||||
self.assertContains(r, msg)
|
||||
self.assertNotContains(r, 'fubar')
|
||||
|
||||
|
||||
class TestBlacklistedEmailDomainAdminAddForm(UserFormBase):
|
||||
|
||||
def test_no_domains(self):
|
||||
self.client.login(username='testo@example.com', password='foo')
|
||||
url = reverse('admin:users_blacklistedemaildomain_add')
|
||||
data = {'domains': "\n\n", }
|
||||
r = self.client.post(url, data)
|
||||
msg = 'Please enter at least one e-mail domain to blacklist.'
|
||||
self.assertFormError(r, 'form', 'domains', msg)
|
||||
|
||||
def test_add(self):
|
||||
self.client.login(username='testo@example.com', password='foo')
|
||||
url = reverse('admin:users_blacklistedemaildomain_add')
|
||||
data = {'domains': "mailinator.com\ntrash-mail.de\n\n", }
|
||||
r = self.client.post(url, data)
|
||||
msg = '1 new values added to the blacklist. '
|
||||
msg += '1 duplicates were ignored.'
|
||||
self.assertContains(r, msg)
|
||||
self.assertNotContains(r, 'fubar')
|
||||
|
|
|
@ -12,7 +12,8 @@ import amo.test_utils
|
|||
from addons.models import Addon, AddonUser
|
||||
from bandwagon.models import Collection
|
||||
from reviews.models import Review
|
||||
from users.models import UserProfile, get_hexdigest, BlacklistedUsername
|
||||
from users.models import UserProfile, get_hexdigest, BlacklistedUsername,\
|
||||
BlacklistedEmailDomain
|
||||
|
||||
|
||||
class TestUserProfile(amo.test_utils.ExtraSetup, test_utils.TestCase):
|
||||
|
@ -165,3 +166,12 @@ class TestBlacklistedUsername(amo.test_utils.ExtraSetup, test_utils.TestCase):
|
|||
def test_blocked(self):
|
||||
eq_(BlacklistedUsername.blocked('IE6Fan'), True)
|
||||
eq_(BlacklistedUsername.blocked('testo'), False)
|
||||
|
||||
|
||||
class TestBlacklistedEmailDomain(amo.test_utils.ExtraSetup,
|
||||
test_utils.TestCase):
|
||||
fixtures = ['users/test_backends']
|
||||
|
||||
def test_blocked(self):
|
||||
eq_(BlacklistedEmailDomain.blocked('mailinator.com'), True)
|
||||
assert not BlacklistedEmailDomain.blocked('mozilla.com')
|
||||
|
|
|
@ -0,0 +1,72 @@
|
|||
CREATE TABLE `users_blacklistedemaildomain` (
|
||||
`id` int(11) NOT NULL auto_increment,
|
||||
`domain` varchar(255) NOT NULL default '',
|
||||
`created` datetime NOT NULL,
|
||||
`modified` datetime NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `domain` (`domain`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
||||
|
||||
INSERT INTO
|
||||
`users_blacklistedemaildomain` (`domain`, `created`, `modified`)
|
||||
VALUES
|
||||
('mailinator.com',NOW(),NOW()),
|
||||
('mailinator2.com',NOW(),NOW()),
|
||||
('fuckingduh.com',NOW(),NOW()),
|
||||
('sogetthis.com',NOW(),NOW()),
|
||||
('mailin8r.com',NOW(),NOW()),
|
||||
('mailinator.net',NOW(),NOW()),
|
||||
('klassmaster.com',NOW(),NOW()),
|
||||
('putthisinyourspamdatabase.com',NOW(),NOW()),
|
||||
('thisisnotmyrealemail.com',NOW(),NOW()),
|
||||
('binkmail.com',NOW(),NOW()),
|
||||
('spamhereplease.com',NOW(),NOW()),
|
||||
('spamherelots.com',NOW(),NOW()),
|
||||
('sendspamhere.com',NOW(),NOW()),
|
||||
('chogmail.com',NOW(),NOW()),
|
||||
('spamthisplease.com',NOW(),NOW()),
|
||||
('frapmail.com',NOW(),NOW()),
|
||||
('obobbo.com',NOW(),NOW()),
|
||||
('devnullmail.com',NOW(),NOW()),
|
||||
('bumpymail.com',NOW(),NOW()),
|
||||
('centermail.com',NOW(),NOW()),
|
||||
('centermail.net',NOW(),NOW()),
|
||||
('discardmail.com',NOW(),NOW()),
|
||||
('dodgeit.com',NOW(),NOW()),
|
||||
('e4ward.com',NOW(),NOW()),
|
||||
('emailias.com',NOW(),NOW()),
|
||||
('fakeinformation.com',NOW(),NOW()),
|
||||
('front14.org',NOW(),NOW()),
|
||||
('ghosttexter.de',NOW(),NOW()),
|
||||
('jetable.net',NOW(),NOW()),
|
||||
('kasmail.com',NOW(),NOW()),
|
||||
('link2mail.net',NOW(),NOW()),
|
||||
('mailexpire.com',NOW(),NOW()),
|
||||
('mailmoat.com',NOW(),NOW()),
|
||||
('messagebeamer.de',NOW(),NOW()),
|
||||
('mytrashmail.com',NOW(),NOW()),
|
||||
('nervmich.net',NOW(),NOW()),
|
||||
('netmails.net',NOW(),NOW()),
|
||||
('netzidiot.de',NOW(),NOW()),
|
||||
('nurfuerspam.de',NOW(),NOW()),
|
||||
('oneoffemail.com',NOW(),NOW()),
|
||||
('pookmail.com',NOW(),NOW()),
|
||||
('privacy.net',NOW(),NOW()),
|
||||
('punkass.com',NOW(),NOW()),
|
||||
('sneakemail.com',NOW(),NOW()),
|
||||
('sofort-mail.de',NOW(),NOW()),
|
||||
('spam.la',NOW(),NOW()),
|
||||
('spambob.com',NOW(),NOW()),
|
||||
('spambob.net',NOW(),NOW()),
|
||||
('spambob.org',NOW(),NOW()),
|
||||
('spamex.com',NOW(),NOW()),
|
||||
('spamgourmet.com',NOW(),NOW()),
|
||||
('spamhole.com',NOW(),NOW()),
|
||||
('spaminator.de',NOW(),NOW()),
|
||||
('spammotel.com',NOW(),NOW()),
|
||||
('spamtrail.com',NOW(),NOW()),
|
||||
('trash-mail.de',NOW(),NOW()),
|
||||
('trashmail.net',NOW(),NOW()),
|
||||
('wuzup.net',NOW(),NOW()),
|
||||
('suremail.info',NOW(),NOW()),
|
||||
('spammote.com',NOW(),NOW());
|
Загрузка…
Ссылка в новой задаче