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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
import { Column, Entity, PrimaryColumn } from "typeorm";
import { BaseClassWithoutId } from "./BaseClass";
import crypto from "crypto";
import { promisify } from "util";
const generateKeyPair = promisify(crypto.generateKeyPair);
export enum ActorType {
USER = "users",
CHANNEL = "channels",
GUILD = "guilds",
}
@Entity("federation_keys")
export class FederationKey extends BaseClassWithoutId {
/** The ID of this actor. */
@PrimaryColumn()
actorId: string;
/** The type of this actor. I.e. User, Channel, Guild */
@Column()
type: ActorType;
/** The domain of this actor. I.e. spacebar.chat */
@Column()
domain: string;
/** The federated preferred username of remote users. Local usernames are null. */
@Column({ nullable: true, type: String })
username: string | null;
/** The remote ID ( actor URL ) of this user */
@Column()
federatedId: string;
/** The inbox of the remote user */
@Column()
inbox: string;
/** The outbox of the remote user */
@Column()
outbox: string;
/** The following collection of this user */
@Column()
following: string;
/** The followers collection of this user */
@Column()
followers: string;
/** The public key of this actor. Public keys of remote actors are cached. */
@Column()
publicKey: string;
/** Will only have a private key if this actor is ours */
@Column({ nullable: true, type: String })
privateKey: string | null;
/** Create a new FederationKey for an actor */
static generateSigningKeys = async (actorId: string, type: ActorType) => {
const existing = await FederationKey.findOne({ where: { actorId } });
if (existing) return existing;
// Lazy loading config to prevent circular dep
const { Config } = await import("../util/Config");
const { accountDomain, host } = Config.get().federation;
const keys = FederationKey.create({
actorId,
type,
federatedId: `https://${host}/federation/${type}/${actorId}`,
inbox: `https://${host}/federation/${type}/${actorId}/inbox`,
outbox: `https://${host}/federation/${type}/${actorId}/outbox`,
followers: `https://${host}/federation/${type}/${actorId}/followers`,
following: `https://${host}/federation/${type}/${actorId}/following`,
domain: accountDomain,
...(await generateKeyPair("rsa", {
modulusLength: 4096,
publicKeyEncoding: {
type: "spki",
format: "pem",
},
privateKeyEncoding: {
type: "pkcs8",
format: "pem",
},
})),
});
return await keys.save();
};
}
|