aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/activitypub
diff options
context:
space:
mode:
Diffstat (limited to 'server/models/activitypub')
-rw-r--r--server/models/activitypub/actor.ts245
1 files changed, 245 insertions, 0 deletions
diff --git a/server/models/activitypub/actor.ts b/server/models/activitypub/actor.ts
new file mode 100644
index 000000000..4cae6a6ec
--- /dev/null
+++ b/server/models/activitypub/actor.ts
@@ -0,0 +1,245 @@
1import { join } from 'path'
2import * as Sequelize from 'sequelize'
3import {
4 AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, HasMany, Is, IsUUID, Model, Table,
5 UpdatedAt
6} from 'sequelize-typescript'
7import { Avatar } from '../../../shared/models/avatars/avatar.model'
8import { activityPubContextify } from '../../helpers'
9import {
10 isActivityPubUrlValid,
11 isActorFollowersCountValid,
12 isActorFollowingCountValid, isActorPreferredUsernameValid,
13 isActorPrivateKeyValid,
14 isActorPublicKeyValid
15} from '../../helpers/custom-validators/activitypub'
16import { isUserUsernameValid } from '../../helpers/custom-validators/users'
17import { AVATARS_DIR, CONFIG, CONSTRAINTS_FIELDS } from '../../initializers'
18import { AccountFollowModel } from '../account/account-follow'
19import { AvatarModel } from '../avatar/avatar'
20import { ServerModel } from '../server/server'
21import { throwIfNotValid } from '../utils'
22
23@Table({
24 tableName: 'actor'
25})
26export class ActorModel extends Model<ActorModel> {
27
28 @AllowNull(false)
29 @Default(DataType.UUIDV4)
30 @IsUUID(4)
31 @Column(DataType.UUID)
32 uuid: string
33
34 @AllowNull(false)
35 @Is('ActorName', value => throwIfNotValid(value, isActorPreferredUsernameValid, 'actor name'))
36 @Column
37 name: string
38
39 @AllowNull(false)
40 @Is('ActorUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'url'))
41 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max))
42 url: string
43
44 @AllowNull(true)
45 @Is('ActorPublicKey', value => throwIfNotValid(value, isActorPublicKeyValid, 'public key'))
46 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.PUBLIC_KEY.max))
47 publicKey: string
48
49 @AllowNull(true)
50 @Is('ActorPublicKey', value => throwIfNotValid(value, isActorPrivateKeyValid, 'private key'))
51 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.PRIVATE_KEY.max))
52 privateKey: string
53
54 @AllowNull(false)
55 @Is('ActorFollowersCount', value => throwIfNotValid(value, isActorFollowersCountValid, 'followers count'))
56 @Column
57 followersCount: number
58
59 @AllowNull(false)
60 @Is('ActorFollowersCount', value => throwIfNotValid(value, isActorFollowingCountValid, 'following count'))
61 @Column
62 followingCount: number
63
64 @AllowNull(false)
65 @Is('ActorInboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'inbox url'))
66 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max))
67 inboxUrl: string
68
69 @AllowNull(false)
70 @Is('ActorOutboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'outbox url'))
71 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max))
72 outboxUrl: string
73
74 @AllowNull(false)
75 @Is('ActorSharedInboxUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'shared inbox url'))
76 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max))
77 sharedInboxUrl: string
78
79 @AllowNull(false)
80 @Is('ActorFollowersUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'followers url'))
81 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max))
82 followersUrl: string
83
84 @AllowNull(false)
85 @Is('ActorFollowingUrl', value => throwIfNotValid(value, isActivityPubUrlValid, 'following url'))
86 @Column(DataType.STRING(CONSTRAINTS_FIELDS.ACTOR.URL.max))
87 followingUrl: string
88
89 @CreatedAt
90 createdAt: Date
91
92 @UpdatedAt
93 updatedAt: Date
94
95 @ForeignKey(() => AvatarModel)
96 @Column
97 avatarId: number
98
99 @BelongsTo(() => AvatarModel, {
100 foreignKey: {
101 allowNull: true
102 },
103 onDelete: 'cascade'
104 })
105 Avatar: AvatarModel
106
107 @HasMany(() => AccountFollowModel, {
108 foreignKey: {
109 name: 'accountId',
110 allowNull: false
111 },
112 onDelete: 'cascade'
113 })
114 AccountFollowing: AccountFollowModel[]
115
116 @HasMany(() => AccountFollowModel, {
117 foreignKey: {
118 name: 'targetAccountId',
119 allowNull: false
120 },
121 as: 'followers',
122 onDelete: 'cascade'
123 })
124 AccountFollowers: AccountFollowModel[]
125
126 @ForeignKey(() => ServerModel)
127 @Column
128 serverId: number
129
130 @BelongsTo(() => ServerModel, {
131 foreignKey: {
132 allowNull: true
133 },
134 onDelete: 'cascade'
135 })
136 Server: ServerModel
137
138 static listByFollowersUrls (followersUrls: string[], transaction?: Sequelize.Transaction) {
139 const query = {
140 where: {
141 followersUrl: {
142 [ Sequelize.Op.in ]: followersUrls
143 }
144 },
145 transaction
146 }
147
148 return ActorModel.findAll(query)
149 }
150
151 toFormattedJSON () {
152 let avatar: Avatar = null
153 if (this.Avatar) {
154 avatar = {
155 path: join(AVATARS_DIR.ACCOUNT, this.Avatar.filename),
156 createdAt: this.Avatar.createdAt,
157 updatedAt: this.Avatar.updatedAt
158 }
159 }
160
161 let host = CONFIG.WEBSERVER.HOST
162 let score: number
163 if (this.Server) {
164 host = this.Server.host
165 score = this.Server.score
166 }
167
168 return {
169 id: this.id,
170 host,
171 score,
172 followingCount: this.followingCount,
173 followersCount: this.followersCount,
174 avatar
175 }
176 }
177
178 toActivityPubObject (name: string, uuid: string, type: 'Account' | 'VideoChannel') {
179 let activityPubType
180 if (type === 'Account') {
181 activityPubType = this.serverId ? 'Application' as 'Application' : 'Person' as 'Person'
182 } else { // VideoChannel
183 activityPubType = 'Group'
184 }
185
186 const json = {
187 type,
188 id: this.url,
189 following: this.getFollowingUrl(),
190 followers: this.getFollowersUrl(),
191 inbox: this.inboxUrl,
192 outbox: this.outboxUrl,
193 preferredUsername: name,
194 url: this.url,
195 name,
196 endpoints: {
197 sharedInbox: this.sharedInboxUrl
198 },
199 uuid,
200 publicKey: {
201 id: this.getPublicKeyUrl(),
202 owner: this.url,
203 publicKeyPem: this.publicKey
204 }
205 }
206
207 return activityPubContextify(json)
208 }
209
210 getFollowerSharedInboxUrls (t: Sequelize.Transaction) {
211 const query = {
212 attributes: [ 'sharedInboxUrl' ],
213 include: [
214 {
215 model: AccountFollowModel,
216 required: true,
217 as: 'followers',
218 where: {
219 targetAccountId: this.id
220 }
221 }
222 ],
223 transaction: t
224 }
225
226 return ActorModel.findAll(query)
227 .then(accounts => accounts.map(a => a.sharedInboxUrl))
228 }
229
230 getFollowingUrl () {
231 return this.url + '/following'
232 }
233
234 getFollowersUrl () {
235 return this.url + '/followers'
236 }
237
238 getPublicKeyUrl () {
239 return this.url + '#main-key'
240 }
241
242 isOwned () {
243 return this.serverId === null
244 }
245}