diff options
Diffstat (limited to 'server/lib/activitypub/actor.ts')
-rw-r--r-- | server/lib/activitypub/actor.ts | 130 |
1 files changed, 69 insertions, 61 deletions
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index f7bf7c65a..a3f379b76 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts | |||
@@ -4,7 +4,7 @@ import * as url from 'url' | |||
4 | import * as uuidv4 from 'uuid/v4' | 4 | import * as uuidv4 from 'uuid/v4' |
5 | import { ActivityPubActor, ActivityPubActorType } from '../../../shared/models/activitypub' | 5 | import { ActivityPubActor, ActivityPubActorType } from '../../../shared/models/activitypub' |
6 | import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects' | 6 | import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects' |
7 | import { checkUrlsSameHost, getAPUrl } from '../../helpers/activitypub' | 7 | import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub' |
8 | import { isActorObjectValid, normalizeActor } from '../../helpers/custom-validators/activitypub/actor' | 8 | import { isActorObjectValid, normalizeActor } 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, updateInstanceWithAnother } from '../../helpers/database-utils' | 10 | import { retryTransactionWrapper, updateInstanceWithAnother } from '../../helpers/database-utils' |
@@ -42,7 +42,7 @@ async function getOrCreateActorAndServerAndModel ( | |||
42 | recurseIfNeeded = true, | 42 | recurseIfNeeded = true, |
43 | updateCollections = false | 43 | updateCollections = false |
44 | ) { | 44 | ) { |
45 | const actorUrl = getAPUrl(activityActor) | 45 | const actorUrl = getAPId(activityActor) |
46 | let created = false | 46 | let created = false |
47 | 47 | ||
48 | let actor = await fetchActorByUrl(actorUrl, fetchType) | 48 | let actor = await fetchActorByUrl(actorUrl, fetchType) |
@@ -201,6 +201,69 @@ async function addFetchOutboxJob (actor: ActorModel) { | |||
201 | return JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload }) | 201 | return JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload }) |
202 | } | 202 | } |
203 | 203 | ||
204 | async function refreshActorIfNeeded ( | ||
205 | actorArg: ActorModel, | ||
206 | fetchedType: ActorFetchByUrlType | ||
207 | ): Promise<{ actor: ActorModel, refreshed: boolean }> { | ||
208 | if (!actorArg.isOutdated()) return { actor: actorArg, refreshed: false } | ||
209 | |||
210 | // We need more attributes | ||
211 | const actor = fetchedType === 'all' ? actorArg : await ActorModel.loadByUrlAndPopulateAccountAndChannel(actorArg.url) | ||
212 | |||
213 | try { | ||
214 | let actorUrl: string | ||
215 | try { | ||
216 | actorUrl = await getUrlFromWebfinger(actor.preferredUsername + '@' + actor.getHost()) | ||
217 | } catch (err) { | ||
218 | logger.warn('Cannot get actor URL from webfinger, keeping the old one.', err) | ||
219 | actorUrl = actor.url | ||
220 | } | ||
221 | |||
222 | const { result, statusCode } = await fetchRemoteActor(actorUrl) | ||
223 | |||
224 | if (statusCode === 404) { | ||
225 | logger.info('Deleting actor %s because there is a 404 in refresh actor.', actor.url) | ||
226 | actor.Account ? actor.Account.destroy() : actor.VideoChannel.destroy() | ||
227 | return { actor: undefined, refreshed: false } | ||
228 | } | ||
229 | |||
230 | if (result === undefined) { | ||
231 | logger.warn('Cannot fetch remote actor in refresh actor.') | ||
232 | return { actor, refreshed: false } | ||
233 | } | ||
234 | |||
235 | return sequelizeTypescript.transaction(async t => { | ||
236 | updateInstanceWithAnother(actor, result.actor) | ||
237 | |||
238 | if (result.avatarName !== undefined) { | ||
239 | await updateActorAvatarInstance(actor, result.avatarName, t) | ||
240 | } | ||
241 | |||
242 | // Force update | ||
243 | actor.setDataValue('updatedAt', new Date()) | ||
244 | await actor.save({ transaction: t }) | ||
245 | |||
246 | if (actor.Account) { | ||
247 | actor.Account.set('name', result.name) | ||
248 | actor.Account.set('description', result.summary) | ||
249 | |||
250 | await actor.Account.save({ transaction: t }) | ||
251 | } else if (actor.VideoChannel) { | ||
252 | actor.VideoChannel.set('name', result.name) | ||
253 | actor.VideoChannel.set('description', result.summary) | ||
254 | actor.VideoChannel.set('support', result.support) | ||
255 | |||
256 | await actor.VideoChannel.save({ transaction: t }) | ||
257 | } | ||
258 | |||
259 | return { refreshed: true, actor } | ||
260 | }) | ||
261 | } catch (err) { | ||
262 | logger.warn('Cannot refresh actor.', { err }) | ||
263 | return { actor, refreshed: false } | ||
264 | } | ||
265 | } | ||
266 | |||
204 | export { | 267 | export { |
205 | getOrCreateActorAndServerAndModel, | 268 | getOrCreateActorAndServerAndModel, |
206 | buildActorInstance, | 269 | buildActorInstance, |
@@ -208,6 +271,7 @@ export { | |||
208 | fetchActorTotalItems, | 271 | fetchActorTotalItems, |
209 | fetchAvatarIfExists, | 272 | fetchAvatarIfExists, |
210 | updateActorInstance, | 273 | updateActorInstance, |
274 | refreshActorIfNeeded, | ||
211 | updateActorAvatarInstance, | 275 | updateActorAvatarInstance, |
212 | addFetchOutboxJob | 276 | addFetchOutboxJob |
213 | } | 277 | } |
@@ -291,12 +355,12 @@ async function fetchRemoteActor (actorUrl: string): Promise<{ statusCode?: numbe | |||
291 | 355 | ||
292 | logger.info('Fetching remote actor %s.', actorUrl) | 356 | logger.info('Fetching remote actor %s.', actorUrl) |
293 | 357 | ||
294 | const requestResult = await doRequest(options) | 358 | const requestResult = await doRequest<ActivityPubActor>(options) |
295 | normalizeActor(requestResult.body) | 359 | normalizeActor(requestResult.body) |
296 | 360 | ||
297 | const actorJSON: ActivityPubActor = requestResult.body | 361 | const actorJSON = requestResult.body |
298 | if (isActorObjectValid(actorJSON) === false) { | 362 | if (isActorObjectValid(actorJSON) === false) { |
299 | logger.debug('Remote actor JSON is not valid.', { actorJSON: actorJSON }) | 363 | logger.debug('Remote actor JSON is not valid.', { actorJSON }) |
300 | return { result: undefined, statusCode: requestResult.response.statusCode } | 364 | return { result: undefined, statusCode: requestResult.response.statusCode } |
301 | } | 365 | } |
302 | 366 | ||
@@ -372,59 +436,3 @@ async function saveVideoChannel (actor: ActorModel, result: FetchRemoteActorResu | |||
372 | 436 | ||
373 | return videoChannelCreated | 437 | return videoChannelCreated |
374 | } | 438 | } |
375 | |||
376 | async function refreshActorIfNeeded ( | ||
377 | actorArg: ActorModel, | ||
378 | fetchedType: ActorFetchByUrlType | ||
379 | ): Promise<{ actor: ActorModel, refreshed: boolean }> { | ||
380 | if (!actorArg.isOutdated()) return { actor: actorArg, refreshed: false } | ||
381 | |||
382 | // We need more attributes | ||
383 | const actor = fetchedType === 'all' ? actorArg : await ActorModel.loadByUrlAndPopulateAccountAndChannel(actorArg.url) | ||
384 | |||
385 | try { | ||
386 | const actorUrl = await getUrlFromWebfinger(actor.preferredUsername + '@' + actor.getHost()) | ||
387 | const { result, statusCode } = await fetchRemoteActor(actorUrl) | ||
388 | |||
389 | if (statusCode === 404) { | ||
390 | logger.info('Deleting actor %s because there is a 404 in refresh actor.', actor.url) | ||
391 | actor.Account ? actor.Account.destroy() : actor.VideoChannel.destroy() | ||
392 | return { actor: undefined, refreshed: false } | ||
393 | } | ||
394 | |||
395 | if (result === undefined) { | ||
396 | logger.warn('Cannot fetch remote actor in refresh actor.') | ||
397 | return { actor, refreshed: false } | ||
398 | } | ||
399 | |||
400 | return sequelizeTypescript.transaction(async t => { | ||
401 | updateInstanceWithAnother(actor, result.actor) | ||
402 | |||
403 | if (result.avatarName !== undefined) { | ||
404 | await updateActorAvatarInstance(actor, result.avatarName, t) | ||
405 | } | ||
406 | |||
407 | // Force update | ||
408 | actor.setDataValue('updatedAt', new Date()) | ||
409 | await actor.save({ transaction: t }) | ||
410 | |||
411 | if (actor.Account) { | ||
412 | actor.Account.set('name', result.name) | ||
413 | actor.Account.set('description', result.summary) | ||
414 | |||
415 | await actor.Account.save({ transaction: t }) | ||
416 | } else if (actor.VideoChannel) { | ||
417 | actor.VideoChannel.set('name', result.name) | ||
418 | actor.VideoChannel.set('description', result.summary) | ||
419 | actor.VideoChannel.set('support', result.support) | ||
420 | |||
421 | await actor.VideoChannel.save({ transaction: t }) | ||
422 | } | ||
423 | |||
424 | return { refreshed: true, actor } | ||
425 | }) | ||
426 | } catch (err) { | ||
427 | logger.warn('Cannot refresh actor.', { err }) | ||
428 | return { actor, refreshed: false } | ||
429 | } | ||
430 | } | ||