Plain is headed towards 1.0! Subscribe for development updates →

plain.password

Password authentication for Plain.

 1from plain import models
 2
 3from . import validators
 4from .hashers import (
 5    hash_password,
 6    identify_hasher,
 7)
 8
 9
10class PasswordField(models.CharField):
11    def __init__(self, *args, **kwargs):
12        kwargs["max_length"] = 128
13        kwargs.setdefault(
14            "validators",
15            [
16                validators.MinimumLengthValidator(),
17                validators.CommonPasswordValidator(),
18                validators.NumericPasswordValidator(),
19            ],
20        )
21        super().__init__(*args, **kwargs)
22
23    def deconstruct(self):
24        name, path, args, kwargs = super().deconstruct()
25        if kwargs.get("max_length") == 128:
26            del kwargs["max_length"]
27        return name, path, args, kwargs
28
29    def pre_save(self, model_instance, add):
30        value = super().pre_save(model_instance, add)
31
32        if value and not self._is_hashed(value):
33            value = hash_password(value)
34            # Set the hashed value back on the instance immediately too
35            setattr(model_instance, self.attname, value)
36
37        return value
38
39    @staticmethod
40    def _is_hashed(value):
41        try:
42            identify_hasher(value)
43            return True
44        except ValueError:
45            return False