diff options
Diffstat (limited to 'server/lib/activitypub/actor.ts')
-rw-r--r-- | server/lib/activitypub/actor.ts | 82 |
1 files changed, 56 insertions, 26 deletions
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index 9f5d12eb4..13b73077e 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts | |||
@@ -22,13 +22,27 @@ import { JobQueue } from '../job-queue' | |||
22 | import { getServerActor } from '../../helpers/utils' | 22 | import { getServerActor } from '../../helpers/utils' |
23 | import { ActorFetchByUrlType, fetchActorByUrl } from '../../helpers/actor' | 23 | import { ActorFetchByUrlType, fetchActorByUrl } from '../../helpers/actor' |
24 | import { sequelizeTypescript } from '../../initializers/database' | 24 | import { sequelizeTypescript } from '../../initializers/database' |
25 | import { | ||
26 | MAccount, | ||
27 | MAccountDefault, | ||
28 | MActor, | ||
29 | MActorAccountChannelId, | ||
30 | MActorAccountChannelIdActor, | ||
31 | MActorAccountId, | ||
32 | MActorDefault, | ||
33 | MActorFull, | ||
34 | MActorFullActor, | ||
35 | MActorId, | ||
36 | MChannel, | ||
37 | MChannelAccountDefault | ||
38 | } from '../../typings/models' | ||
25 | 39 | ||
26 | // Set account keys, this could be long so process after the account creation and do not block the client | 40 | // Set account keys, this could be long so process after the account creation and do not block the client |
27 | function setAsyncActorKeys (actor: ActorModel) { | 41 | function setAsyncActorKeys <T extends MActor> (actor: T) { |
28 | return createPrivateAndPublicKeys() | 42 | return createPrivateAndPublicKeys() |
29 | .then(({ publicKey, privateKey }) => { | 43 | .then(({ publicKey, privateKey }) => { |
30 | actor.set('publicKey', publicKey) | 44 | actor.publicKey = publicKey |
31 | actor.set('privateKey', privateKey) | 45 | actor.privateKey = privateKey |
32 | return actor.save() | 46 | return actor.save() |
33 | }) | 47 | }) |
34 | .catch(err => { | 48 | .catch(err => { |
@@ -37,12 +51,26 @@ function setAsyncActorKeys (actor: ActorModel) { | |||
37 | }) | 51 | }) |
38 | } | 52 | } |
39 | 53 | ||
54 | function getOrCreateActorAndServerAndModel ( | ||
55 | activityActor: string | ActivityPubActor, | ||
56 | fetchType: 'all', | ||
57 | recurseIfNeeded?: boolean, | ||
58 | updateCollections?: boolean | ||
59 | ): Promise<MActorFullActor> | ||
60 | |||
61 | function getOrCreateActorAndServerAndModel ( | ||
62 | activityActor: string | ActivityPubActor, | ||
63 | fetchType?: 'association-ids', | ||
64 | recurseIfNeeded?: boolean, | ||
65 | updateCollections?: boolean | ||
66 | ): Promise<MActorAccountChannelId> | ||
67 | |||
40 | async function getOrCreateActorAndServerAndModel ( | 68 | async function getOrCreateActorAndServerAndModel ( |
41 | activityActor: string | ActivityPubActor, | 69 | activityActor: string | ActivityPubActor, |
42 | fetchType: ActorFetchByUrlType = 'actor-and-association-ids', | 70 | fetchType: ActorFetchByUrlType = 'association-ids', |
43 | recurseIfNeeded = true, | 71 | recurseIfNeeded = true, |
44 | updateCollections = false | 72 | updateCollections = false |
45 | ) { | 73 | ): Promise<MActorFullActor | MActorAccountChannelId> { |
46 | const actorUrl = getAPId(activityActor) | 74 | const actorUrl = getAPId(activityActor) |
47 | let created = false | 75 | let created = false |
48 | let accountPlaylistsUrl: string | 76 | let accountPlaylistsUrl: string |
@@ -61,7 +89,7 @@ async function getOrCreateActorAndServerAndModel ( | |||
61 | 89 | ||
62 | // Create the attributed to actor | 90 | // Create the attributed to actor |
63 | // In PeerTube a video channel is owned by an account | 91 | // In PeerTube a video channel is owned by an account |
64 | let ownerActor: ActorModel = undefined | 92 | let ownerActor: MActorFullActor |
65 | if (recurseIfNeeded === true && result.actor.type === 'Group') { | 93 | if (recurseIfNeeded === true && result.actor.type === 'Group') { |
66 | const accountAttributedTo = result.attributedTo.find(a => a.type === 'Person') | 94 | const accountAttributedTo = result.attributedTo.find(a => a.type === 'Person') |
67 | if (!accountAttributedTo) throw new Error('Cannot find account attributed to video channel ' + actor.url) | 95 | if (!accountAttributedTo) throw new Error('Cannot find account attributed to video channel ' + actor.url) |
@@ -85,8 +113,8 @@ async function getOrCreateActorAndServerAndModel ( | |||
85 | accountPlaylistsUrl = result.playlists | 113 | accountPlaylistsUrl = result.playlists |
86 | } | 114 | } |
87 | 115 | ||
88 | if (actor.Account) actor.Account.Actor = actor | 116 | if (actor.Account) (actor as MActorAccountChannelIdActor).Account.Actor = actor |
89 | if (actor.VideoChannel) actor.VideoChannel.Actor = actor | 117 | if (actor.VideoChannel) (actor as MActorAccountChannelIdActor).VideoChannel.Actor = actor |
90 | 118 | ||
91 | const { actor: actorRefreshed, refreshed } = await retryTransactionWrapper(refreshActorIfNeeded, actor, fetchType) | 119 | const { actor: actorRefreshed, refreshed } = await retryTransactionWrapper(refreshActorIfNeeded, actor, fetchType) |
92 | if (!actorRefreshed) throw new Error('Actor ' + actorRefreshed.url + ' does not exist anymore.') | 120 | if (!actorRefreshed) throw new Error('Actor ' + actorRefreshed.url + ' does not exist anymore.') |
@@ -120,7 +148,7 @@ function buildActorInstance (type: ActivityPubActorType, url: string, preferredU | |||
120 | sharedInboxUrl: WEBSERVER.URL + '/inbox', | 148 | sharedInboxUrl: WEBSERVER.URL + '/inbox', |
121 | followersUrl: url + '/followers', | 149 | followersUrl: url + '/followers', |
122 | followingUrl: url + '/following' | 150 | followingUrl: url + '/following' |
123 | }) | 151 | }) as MActor |
124 | } | 152 | } |
125 | 153 | ||
126 | async function updateActorInstance (actorInstance: ActorModel, attributes: ActivityPubActor) { | 154 | async function updateActorInstance (actorInstance: ActorModel, attributes: ActivityPubActor) { |
@@ -140,7 +168,8 @@ async function updateActorInstance (actorInstance: ActorModel, attributes: Activ | |||
140 | actorInstance.followingUrl = attributes.following | 168 | actorInstance.followingUrl = attributes.following |
141 | } | 169 | } |
142 | 170 | ||
143 | async function updateActorAvatarInstance (actor: ActorModel, info: { name: string, onDisk: boolean, fileUrl: string }, t: Transaction) { | 171 | type AvatarInfo = { name: string, onDisk: boolean, fileUrl: string } |
172 | async function updateActorAvatarInstance (actor: MActorDefault, info: AvatarInfo, t: Transaction) { | ||
144 | if (info.name !== undefined) { | 173 | if (info.name !== undefined) { |
145 | if (actor.avatarId) { | 174 | if (actor.avatarId) { |
146 | try { | 175 | try { |
@@ -212,14 +241,16 @@ async function addFetchOutboxJob (actor: Pick<ActorModel, 'id' | 'outboxUrl'>) { | |||
212 | return JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload }) | 241 | return JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload }) |
213 | } | 242 | } |
214 | 243 | ||
215 | async function refreshActorIfNeeded ( | 244 | async function refreshActorIfNeeded <T extends MActorFull | MActorAccountChannelId> ( |
216 | actorArg: ActorModel, | 245 | actorArg: T, |
217 | fetchedType: ActorFetchByUrlType | 246 | fetchedType: ActorFetchByUrlType |
218 | ): Promise<{ actor: ActorModel, refreshed: boolean }> { | 247 | ): Promise<{ actor: T | MActorFull, refreshed: boolean }> { |
219 | if (!actorArg.isOutdated()) return { actor: actorArg, refreshed: false } | 248 | if (!actorArg.isOutdated()) return { actor: actorArg, refreshed: false } |
220 | 249 | ||
221 | // We need more attributes | 250 | // We need more attributes |
222 | const actor = fetchedType === 'all' ? actorArg : await ActorModel.loadByUrlAndPopulateAccountAndChannel(actorArg.url) | 251 | const actor = fetchedType === 'all' |
252 | ? actorArg as MActorFull | ||
253 | : await ActorModel.loadByUrlAndPopulateAccountAndChannel(actorArg.url) | ||
223 | 254 | ||
224 | try { | 255 | try { |
225 | let actorUrl: string | 256 | let actorUrl: string |
@@ -297,9 +328,9 @@ export { | |||
297 | 328 | ||
298 | function saveActorAndServerAndModelIfNotExist ( | 329 | function saveActorAndServerAndModelIfNotExist ( |
299 | result: FetchRemoteActorResult, | 330 | result: FetchRemoteActorResult, |
300 | ownerActor?: ActorModel, | 331 | ownerActor?: MActorFullActor, |
301 | t?: Transaction | 332 | t?: Transaction |
302 | ): Bluebird<ActorModel> | Promise<ActorModel> { | 333 | ): Bluebird<MActorFullActor> | Promise<MActorFullActor> { |
303 | let actor = result.actor | 334 | let actor = result.actor |
304 | 335 | ||
305 | if (t !== undefined) return save(t) | 336 | if (t !== undefined) return save(t) |
@@ -336,7 +367,7 @@ function saveActorAndServerAndModelIfNotExist ( | |||
336 | 367 | ||
337 | // Force the actor creation, sometimes Sequelize skips the save() when it thinks the instance already exists | 368 | // Force the actor creation, sometimes Sequelize skips the save() when it thinks the instance already exists |
338 | // (which could be false in a retried query) | 369 | // (which could be false in a retried query) |
339 | const [ actorCreated ] = await ActorModel.findOrCreate({ | 370 | const [ actorCreated ] = await ActorModel.findOrCreate<MActorFullActor>({ |
340 | defaults: actor.toJSON(), | 371 | defaults: actor.toJSON(), |
341 | where: { | 372 | where: { |
342 | url: actor.url | 373 | url: actor.url |
@@ -345,12 +376,11 @@ function saveActorAndServerAndModelIfNotExist ( | |||
345 | }) | 376 | }) |
346 | 377 | ||
347 | if (actorCreated.type === 'Person' || actorCreated.type === 'Application') { | 378 | if (actorCreated.type === 'Person' || actorCreated.type === 'Application') { |
348 | actorCreated.Account = await saveAccount(actorCreated, result, t) | 379 | actorCreated.Account = await saveAccount(actorCreated, result, t) as MAccountDefault |
349 | actorCreated.Account.Actor = actorCreated | 380 | actorCreated.Account.Actor = actorCreated |
350 | } else if (actorCreated.type === 'Group') { // Video channel | 381 | } else if (actorCreated.type === 'Group') { // Video channel |
351 | actorCreated.VideoChannel = await saveVideoChannel(actorCreated, result, ownerActor, t) | 382 | const channel = await saveVideoChannel(actorCreated, result, ownerActor, t) |
352 | actorCreated.VideoChannel.Actor = actorCreated | 383 | actorCreated.VideoChannel = Object.assign(channel, { Actor: actorCreated, Account: ownerActor.Account }) |
353 | actorCreated.VideoChannel.Account = ownerActor.Account | ||
354 | } | 384 | } |
355 | 385 | ||
356 | actorCreated.Server = server | 386 | actorCreated.Server = server |
@@ -360,7 +390,7 @@ function saveActorAndServerAndModelIfNotExist ( | |||
360 | } | 390 | } |
361 | 391 | ||
362 | type FetchRemoteActorResult = { | 392 | type FetchRemoteActorResult = { |
363 | actor: ActorModel | 393 | actor: MActor |
364 | name: string | 394 | name: string |
365 | summary: string | 395 | summary: string |
366 | support?: string | 396 | support?: string |
@@ -429,7 +459,7 @@ async function fetchRemoteActor (actorUrl: string): Promise<{ statusCode?: numbe | |||
429 | } | 459 | } |
430 | } | 460 | } |
431 | 461 | ||
432 | async function saveAccount (actor: ActorModel, result: FetchRemoteActorResult, t: Transaction) { | 462 | async function saveAccount (actor: MActorId, result: FetchRemoteActorResult, t: Transaction) { |
433 | const [ accountCreated ] = await AccountModel.findOrCreate({ | 463 | const [ accountCreated ] = await AccountModel.findOrCreate({ |
434 | defaults: { | 464 | defaults: { |
435 | name: result.name, | 465 | name: result.name, |
@@ -442,10 +472,10 @@ async function saveAccount (actor: ActorModel, result: FetchRemoteActorResult, t | |||
442 | transaction: t | 472 | transaction: t |
443 | }) | 473 | }) |
444 | 474 | ||
445 | return accountCreated | 475 | return accountCreated as MAccount |
446 | } | 476 | } |
447 | 477 | ||
448 | async function saveVideoChannel (actor: ActorModel, result: FetchRemoteActorResult, ownerActor: ActorModel, t: Transaction) { | 478 | async function saveVideoChannel (actor: MActorId, result: FetchRemoteActorResult, ownerActor: MActorAccountId, t: Transaction) { |
449 | const [ videoChannelCreated ] = await VideoChannelModel.findOrCreate({ | 479 | const [ videoChannelCreated ] = await VideoChannelModel.findOrCreate({ |
450 | defaults: { | 480 | defaults: { |
451 | name: result.name, | 481 | name: result.name, |
@@ -460,5 +490,5 @@ async function saveVideoChannel (actor: ActorModel, result: FetchRemoteActorResu | |||
460 | transaction: t | 490 | transaction: t |
461 | }) | 491 | }) |
462 | 492 | ||
463 | return videoChannelCreated | 493 | return videoChannelCreated as MChannel |
464 | } | 494 | } |