class User(AbstractBaseUser): email = models.EmailField( verbose_name='email address', max_length=191, unique=True, ) is_active = models.BooleanField(default=True) is_admin = models.BooleanField(default=False) registration_remote_ip = models.CharField(max_length=1024, blank=True) locked = models.DateTimeField(null=True, blank=True) created = models.DateTimeField(auto_now_add=True) limit_domains = models.IntegerField(default=settings.LIMIT_USER_DOMAIN_COUNT_DEFAULT, null=True, blank=True) dyn = models.BooleanField(default=False) objects = MyUserManager() USERNAME_FIELD = 'email' REQUIRED_FIELDS = [] def get_full_name(self): return self.email def get_short_name(self): return self.email def get_or_create_first_token(self): try: token = Token.objects.filter(user=self).earliest('created') except Token.DoesNotExist: token = Token.objects.create(user=self) return token.key def __str__(self): return self.email # noinspection PyMethodMayBeStatic def has_perm(self, *_): """Does the user have a specific permission?""" # Simplest possible answer: Yes, always return True # noinspection PyMethodMayBeStatic def has_module_perms(self, *_): """Does the user have permissions to view the app `app_label`?""" # Simplest possible answer: Yes, always return True @property def is_staff(self): """Is the user a member of staff?""" # Simplest possible answer: All admins are staff return self.is_admin
class PluralityAuthToken(models.Model): """ A token class which can have multiple active tokens per user. """ key = models.CharField(max_length=40, primary_key=False, db_index=True) user = models.ForeignKey( AUTH_USER_MODEL, related_name="auth_tokens", null=False, on_delete=models.PROTECT, ) created = models.DateTimeField(auto_now_add=True) active = models.BooleanField(default=True) class Meta: # Work around for a bug in Django: # https://code.djangoproject.com/ticket/19422 # # Also see corresponding ticket: # https://github.com/tomchristie/django-rest-framework/issues/705 abstract = "rest_framework.authtoken" not in settings.INSTALLED_APPS def save(self, *args, **kwargs): if not self.key: self.key = self.generate_key() return super(PluralityAuthToken, self).save(*args, **kwargs) def generate_key(self): return binascii.hexlify(os.urandom(20)).decode() def __str__(self): return self.key
class Token(ExportModelOperationsMixin('Token'), rest_framework.authtoken.models.Token): @staticmethod def _allowed_subnets_default(): return [ ipaddress.IPv4Network('0.0.0.0/0'), ipaddress.IPv6Network('::/0') ] id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) key = models.CharField("Key", max_length=128, db_index=True, unique=True) user = models.ForeignKey(User, related_name='auth_tokens', on_delete=models.CASCADE, verbose_name="User") name = models.CharField('Name', blank=True, max_length=64) last_used = models.DateTimeField(null=True, blank=True) perm_manage_tokens = models.BooleanField(default=False) allowed_subnets = ArrayField(CidrAddressField(), default=_allowed_subnets_default.__func__) max_age = models.DurationField( null=True, default=None, validators=[MinValueValidator(timedelta(0))]) max_unused_period = models.DurationField( null=True, default=None, validators=[MinValueValidator(timedelta(0))]) plain = None objects = NetManager() @property def is_valid(self): now = timezone.now() # Check max age try: if self.created + self.max_age < now: return False except TypeError: pass # Check regular usage requirement try: if (self.last_used or self.created) + self.max_unused_period < now: return False except TypeError: pass return True def generate_key(self): self.plain = secrets.token_urlsafe(21) self.key = Token.make_hash(self.plain) return self.key @staticmethod def make_hash(plain): return make_password(plain, salt='static', hasher='pbkdf2_sha256_iter1')
class Token(ExportModelOperationsMixin('Token'), rest_framework.authtoken.models.Token): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) key = models.CharField("Key", max_length=128, db_index=True, unique=True) user = models.ForeignKey(User, related_name='auth_tokens', on_delete=models.CASCADE, verbose_name="User") name = models.CharField('Name', blank=True, max_length=64) last_used = models.DateTimeField(null=True, blank=True) perm_manage_tokens = models.BooleanField(default=False) plain = None def generate_key(self): self.plain = secrets.token_urlsafe(21) self.key = Token.make_hash(self.plain) return self.key @staticmethod def make_hash(plain): return make_password(plain, salt='static', hasher='pbkdf2_sha256_iter1')
class User(ExportModelOperationsMixin('User'), AbstractBaseUser): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) email = models.EmailField( verbose_name='email address', max_length=191, unique=True, ) is_active = models.BooleanField(default=True) is_admin = models.BooleanField(default=False) created = models.DateTimeField(auto_now_add=True) limit_domains = models.IntegerField( default=settings.LIMIT_USER_DOMAIN_COUNT_DEFAULT, null=True, blank=True) objects = MyUserManager() USERNAME_FIELD = 'email' REQUIRED_FIELDS = [] def get_full_name(self): return self.email def get_short_name(self): return self.email def __str__(self): return self.email # noinspection PyMethodMayBeStatic def has_perm(self, *_): """Does the user have a specific permission?""" # Simplest possible answer: Yes, always return True # noinspection PyMethodMayBeStatic def has_module_perms(self, *_): """Does the user have permissions to view the app `app_label`?""" # Simplest possible answer: Yes, always return True @property def is_staff(self): """Is the user a member of staff?""" # Simplest possible answer: All admins are staff return self.is_admin def activate(self): self.is_active = True self.save() def change_email(self, email): old_email = self.email self.email = email self.validate_unique() self.save() self.send_email('change-email-confirmation-old-email', recipient=old_email) def change_password(self, raw_password): self.set_password(raw_password) self.save() self.send_email('password-change-confirmation') def send_email(self, reason, context=None, recipient=None): fast_lane = 'email_fast_lane' slow_lane = 'email_slow_lane' lanes = { 'activate': slow_lane, 'activate-with-domain': slow_lane, 'change-email': slow_lane, 'change-email-confirmation-old-email': fast_lane, 'password-change-confirmation': fast_lane, 'reset-password': fast_lane, 'delete-user': fast_lane, 'domain-dyndns': fast_lane, } if reason not in lanes: raise ValueError( f'Cannot send email to user {self.pk} without a good reason: {reason}' ) context = context or {} context.setdefault( 'link_expiration_hours', settings.VALIDITY_PERIOD_VERIFICATION_SIGNATURE // timedelta(hours=1)) content = get_template(f'emails/{reason}/content.txt').render(context) content += f'\nSupport Reference: user_id = {self.pk}\n' footer = get_template('emails/footer.txt').render() logger.warning( f'Queuing email for user account {self.pk} (reason: {reason})') return EmailMessage( subject=get_template(f'emails/{reason}/subject.txt').render( context).strip(), body=content + footer, from_email=get_template('emails/from.txt').render(), to=[recipient or self.email], connection=get_connection(lane=lanes[reason], debug={ 'user': self.pk, 'reason': reason })).send()