models.py 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. __package__ = 'archivebox.api'
  2. import uuid
  3. import secrets
  4. from datetime import timedelta
  5. from django.conf import settings
  6. from django.db import models
  7. from django.utils import timezone
  8. from django_stubs_ext.db.models import TypedModelMeta
  9. def generate_secret_token() -> str:
  10. # returns cryptographically secure string with len() == 32
  11. return secrets.token_hex(16)
  12. class APIToken(models.Model):
  13. id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
  14. user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
  15. token = models.CharField(max_length=32, default=generate_secret_token, unique=True)
  16. created = models.DateTimeField(auto_now_add=True)
  17. expires = models.DateTimeField(null=True, blank=True)
  18. class Meta(TypedModelMeta):
  19. verbose_name = "API Key"
  20. verbose_name_plural = "API Keys"
  21. def __str__(self) -> str:
  22. return self.token
  23. def __repr__(self) -> str:
  24. return f'<APIToken user={self.user.username} token=************{self.token[-4:]}>'
  25. def __json__(self) -> dict:
  26. return {
  27. "TYPE": "APIToken",
  28. "id": str(self.id),
  29. "user_id": str(self.user.id),
  30. "user_username": self.user.username,
  31. "token": self.token,
  32. "created": self.created.isoformat(),
  33. "expires": self.expires_as_iso8601,
  34. }
  35. @property
  36. def expires_as_iso8601(self):
  37. """Returns the expiry date of the token in ISO 8601 format or a date 100 years in the future if none."""
  38. expiry_date = self.expires or (timezone.now() + timedelta(days=365 * 100))
  39. return expiry_date.isoformat()
  40. def is_valid(self, for_date=None):
  41. for_date = for_date or timezone.now()
  42. if self.expires and self.expires < for_date:
  43. return False
  44. return True