summaryrefslogtreecommitdiffstats
path: root/users/models/identity.py
blob: 495b4a4b15e30e1c54417bf2d11afb938b8ebcb1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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/"