Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import re
- from functools import partial
- from django.contrib.auth.hashers import check_password
- from django.core.exceptions import ValidationError
- from django.template.defaultfilters import pluralize
- from django.utils.translation import ugettext_lazy as _
- from users.models import PasswordHistory
- class LastPasswordValidator(object):
- """
- Validate whether the password is not equal last passwords.
- """
- def __init__(self, last_password_compare_count=12):
- self.last_password_compare_count = last_password_compare_count
- def validate(self, password, user=None):
- if user:
- last_passwords = PasswordHistory.objects.filter(user=user)\
- .order_by('-created_at').values_list('password', flat=True)
- last_passwords = last_passwords[:self.last_password_compare_count]
- check_last_password = partial(check_password, password)
- equal_passwords = filter(check_last_password, last_passwords)
- if list(equal_passwords):
- raise ValidationError(
- _('This password repeats your previous %(value)s password%(plural)s.'),
- code='password_repeat',
- params={
- 'value': self.last_password_compare_count,
- 'plural': pluralize(self.last_password_compare_count),
- }
- )
- def get_help_text(self):
- return _("Your password can't repeat your previous passwords.")
- class NumberSequenceValidator(object):
- """
- Validate whether the password is not contain number sequence such as '456'.
- """
- sequence = '0123456789'
- reversed_sequence = sequence[::-1]
- def __init__(self, sequence_length=3):
- self.sequence_length = sequence_length
- def _get_sequence_pieces(self, sequence):
- origin_sequence = sequence[:]
- sequence = (origin_sequence[num:num + self.sequence_length]
- for num, i in enumerate(sequence))
- return filter(lambda x: len(x) == self.sequence_length, sequence)
- def _get_validation_regex(self):
- pieces = self._get_sequence_pieces(self.sequence)
- reversed_pieces = self._get_sequence_pieces(self.reversed_sequence)
- simple_pieces = (x*self.sequence_length for x in self.sequence)
- pieces = tuple(pieces) + tuple(reversed_pieces) + tuple(simple_pieces)
- pieces = '|'.join(pieces)
- return f'({pieces})'
- def validate(self, password, user=None):
- if user:
- validation_regex = self._get_validation_regex()
- if re.search(validation_regex, password):
- raise ValidationError(
- _('This password contains digit sequence.'),
- code='password_contain_digit_sequence',
- )
- def get_help_text(self):
- return _("Your password can't contain digit sequence.")
- class ComplexityValidator(object):
- """
- Password must contains characters from at least three of the bellow groups:
- * English uppercase characters (A-Z)
- * English lowercase characters (a-z)
- * Numerals (0-9)
- * Non-alphabetic characters (! $ # %)
- """
- UPPERCASE_REGEX = r'[A-Z]'
- LOWERCASE_REGEX = r'[a-z]'
- NUMERALS_REGEX = r'[0-9]'
- SPECIAL_CHARS_REGEX = r'[\!\$\*\?\[\]\(\)\/\\#%&@]'
- VALIDATION_REGEX = (UPPERCASE_REGEX, LOWERCASE_REGEX,
- NUMERALS_REGEX, SPECIAL_CHARS_REGEX)
- def __init__(self, min_group_count=3):
- self.min_group_count = min_group_count
- def validate(self, password, user=None):
- if user:
- contain_symbol_group = 0
- for regex in self.VALIDATION_REGEX:
- if re.search(regex, password):
- contain_symbol_group += 1
- if contain_symbol_group < self.min_group_count:
- raise ValidationError(
- _('This password must contains english upper and lower '
- 'case characters and numerals or special characters.'),
- code='password_is_simple',
- )
- def get_help_text(self):
- return _("Your password must contains english upper and lower case "
- "characters and numerals or special characters.")
Add Comment
Please, Sign In to add comment