diff options
Diffstat (limited to 'server/lib/activitypub/actor.ts')
-rw-r--r-- | server/lib/activitypub/actor.ts | 80 |
1 files changed, 77 insertions, 3 deletions
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index b6ba2cc22..0882ab843 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts | |||
@@ -7,10 +7,11 @@ import { ActivityPubActor, ActivityPubActorType } from '../../../shared/models/a | |||
7 | import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects' | 7 | import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects' |
8 | import { isActorObjectValid } from '../../helpers/custom-validators/activitypub/actor' | 8 | import { isActorObjectValid } from '../../helpers/custom-validators/activitypub/actor' |
9 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 9 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
10 | import { retryTransactionWrapper } from '../../helpers/database-utils' | 10 | import { retryTransactionWrapper, updateInstanceWithAnother } from '../../helpers/database-utils' |
11 | import { logger } from '../../helpers/logger' | 11 | import { logger } from '../../helpers/logger' |
12 | import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto' | 12 | import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto' |
13 | import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' | 13 | import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' |
14 | import { getUrlFromWebfinger } from '../../helpers/webfinger' | ||
14 | import { AVATAR_MIMETYPE_EXT, CONFIG, sequelizeTypescript } from '../../initializers' | 15 | import { AVATAR_MIMETYPE_EXT, CONFIG, sequelizeTypescript } from '../../initializers' |
15 | import { AccountModel } from '../../models/account/account' | 16 | import { AccountModel } from '../../models/account/account' |
16 | import { ActorModel } from '../../models/activitypub/actor' | 17 | import { ActorModel } from '../../models/activitypub/actor' |
@@ -63,7 +64,7 @@ async function getOrCreateActorAndServerAndModel (actorUrl: string, recurseIfNee | |||
63 | actor = await retryTransactionWrapper(saveActorAndServerAndModelIfNotExist, options) | 64 | actor = await retryTransactionWrapper(saveActorAndServerAndModelIfNotExist, options) |
64 | } | 65 | } |
65 | 66 | ||
66 | return actor | 67 | return refreshActorIfNeeded(actor) |
67 | } | 68 | } |
68 | 69 | ||
69 | function buildActorInstance (type: ActivityPubActorType, url: string, preferredUsername: string, uuid?: string) { | 70 | function buildActorInstance (type: ActivityPubActorType, url: string, preferredUsername: string, uuid?: string) { |
@@ -84,6 +85,45 @@ function buildActorInstance (type: ActivityPubActorType, url: string, preferredU | |||
84 | }) | 85 | }) |
85 | } | 86 | } |
86 | 87 | ||
88 | async function updateActorInstance (actorInstance: ActorModel, attributes: ActivityPubActor) { | ||
89 | const followersCount = await fetchActorTotalItems(attributes.followers) | ||
90 | const followingCount = await fetchActorTotalItems(attributes.following) | ||
91 | |||
92 | actorInstance.set('type', attributes.type) | ||
93 | actorInstance.set('uuid', attributes.uuid) | ||
94 | actorInstance.set('preferredUsername', attributes.preferredUsername) | ||
95 | actorInstance.set('url', attributes.id) | ||
96 | actorInstance.set('publicKey', attributes.publicKey.publicKeyPem) | ||
97 | actorInstance.set('followersCount', followersCount) | ||
98 | actorInstance.set('followingCount', followingCount) | ||
99 | actorInstance.set('inboxUrl', attributes.inbox) | ||
100 | actorInstance.set('outboxUrl', attributes.outbox) | ||
101 | actorInstance.set('sharedInboxUrl', attributes.endpoints.sharedInbox) | ||
102 | actorInstance.set('followersUrl', attributes.followers) | ||
103 | actorInstance.set('followingUrl', attributes.following) | ||
104 | } | ||
105 | |||
106 | async function updateActorAvatarInstance (actorInstance: ActorModel, avatarName: string, t: Transaction) { | ||
107 | if (avatarName !== undefined) { | ||
108 | if (actorInstance.avatarId) { | ||
109 | try { | ||
110 | await actorInstance.Avatar.destroy({ transaction: t }) | ||
111 | } catch (err) { | ||
112 | logger.error('Cannot remove old avatar of actor %s.', actorInstance.url, err) | ||
113 | } | ||
114 | } | ||
115 | |||
116 | const avatar = await AvatarModel.create({ | ||
117 | filename: avatarName | ||
118 | }, { transaction: t }) | ||
119 | |||
120 | actorInstance.set('avatarId', avatar.id) | ||
121 | actorInstance.Avatar = avatar | ||
122 | } | ||
123 | |||
124 | return actorInstance | ||
125 | } | ||
126 | |||
87 | async function fetchActorTotalItems (url: string) { | 127 | async function fetchActorTotalItems (url: string) { |
88 | const options = { | 128 | const options = { |
89 | uri: url, | 129 | uri: url, |
@@ -129,7 +169,9 @@ export { | |||
129 | buildActorInstance, | 169 | buildActorInstance, |
130 | setAsyncActorKeys, | 170 | setAsyncActorKeys, |
131 | fetchActorTotalItems, | 171 | fetchActorTotalItems, |
132 | fetchAvatarIfExists | 172 | fetchAvatarIfExists, |
173 | updateActorInstance, | ||
174 | updateActorAvatarInstance | ||
133 | } | 175 | } |
134 | 176 | ||
135 | // --------------------------------------------------------------------------- | 177 | // --------------------------------------------------------------------------- |
@@ -263,3 +305,35 @@ async function saveVideoChannel (actor: ActorModel, result: FetchRemoteActorResu | |||
263 | 305 | ||
264 | return videoChannel.save({ transaction: t }) | 306 | return videoChannel.save({ transaction: t }) |
265 | } | 307 | } |
308 | |||
309 | async function refreshActorIfNeeded (actor: ActorModel) { | ||
310 | if (!actor.isOutdated()) return actor | ||
311 | |||
312 | const actorUrl = await getUrlFromWebfinger(actor.preferredUsername, actor.getHost()) | ||
313 | const result = await fetchRemoteActor(actorUrl) | ||
314 | if (result === undefined) throw new Error('Cannot fetch remote actor in refresh actor.') | ||
315 | |||
316 | return sequelizeTypescript.transaction(async t => { | ||
317 | updateInstanceWithAnother(actor, result.actor) | ||
318 | |||
319 | if (result.avatarName !== undefined) { | ||
320 | await updateActorAvatarInstance(actor, result.avatarName, t) | ||
321 | } | ||
322 | |||
323 | await actor.save({ transaction: t }) | ||
324 | |||
325 | if (actor.Account) { | ||
326 | await actor.save({ transaction: t }) | ||
327 | |||
328 | actor.Account.set('name', result.name) | ||
329 | await actor.Account.save({ transaction: t }) | ||
330 | } else if (actor.VideoChannel) { | ||
331 | await actor.save({ transaction: t }) | ||
332 | |||
333 | actor.VideoChannel.set('name', result.name) | ||
334 | await actor.VideoChannel.save({ transaction: t }) | ||
335 | } | ||
336 | |||
337 | return actor | ||
338 | }) | ||
339 | } | ||