takahe/users/models/identity.py

80 lines
2.5 KiB
Python

import base64
import uuid
from functools import partial
import urlman
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from django.conf import settings
from django.db import models
from django.utils import timezone
def upload_namer(prefix, instance, filename):
"""
Names uploaded images etc.
"""
now = timezone.now()
filename = base64.b32encode(uuid.uuid4().bytes).decode("ascii")
return f"{prefix}/{now.year}/{now.month}/{now.day}/{filename}"
class Identity(models.Model):
"""
Represents both local and remote Fediverse identities (actors)
"""
# The handle includes the domain!
handle = models.CharField(max_length=500, unique=True)
name = models.CharField(max_length=500, blank=True, null=True)
bio = models.TextField(blank=True, null=True)
profile_image = models.ImageField(upload_to=partial(upload_namer, "profile_images"))
background_image = models.ImageField(
upload_to=partial(upload_namer, "background_images")
)
local = models.BooleanField()
users = models.ManyToManyField("users.User", related_name="identities")
private_key = models.TextField(null=True, blank=True)
public_key = models.TextField(null=True, blank=True)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
deleted = models.DateTimeField(null=True, blank=True)
@property
def short_handle(self):
if self.handle.endswith("@" + settings.DEFAULT_DOMAIN):
return self.handle.split("@", 1)[0]
return self.handle
@property
def domain(self):
return self.handle.split("@", 1)[1]
def generate_keypair(self):
private_key = rsa.generate_private_key(
public_exponent=65537,
key_size=2048,
)
self.private_key = private_key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption(),
)
self.public_key = private_key.public_key().public_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PublicFormat.SubjectPublicKeyInfo,
)
self.save()
def __str__(self):
return self.name or self.handle
class urls(urlman.Urls):
view = "/@{self.short_handle}/"
actor = "{view}actor/"
inbox = "{actor}inbox/"
activate = "{view}activate/"