X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Flib%2Factivitypub%2Factor.ts;h=22e1c9f1950059ba768613a99a78c150740297af;hb=f5b0af50c85e2f8b6b2b054ac1f47123cacbe08d;hp=b0cf9bb17b0c31652afad0b150add4e52f6474b1;hpb=d5b7d9110dd637a7f67ce9e430145314812a8df1;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index b0cf9bb17..22e1c9f19 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts @@ -6,20 +6,21 @@ import * as uuidv4 from 'uuid/v4' import { ActivityPubActor, ActivityPubActorType } from '../../../shared/models/activitypub' import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects' import { getActorUrl } from '../../helpers/activitypub' -import { isActorObjectValid } from '../../helpers/custom-validators/activitypub/actor' +import { isActorObjectValid, normalizeActor } from '../../helpers/custom-validators/activitypub/actor' import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' import { retryTransactionWrapper, updateInstanceWithAnother } from '../../helpers/database-utils' import { logger } from '../../helpers/logger' import { createPrivateAndPublicKeys } from '../../helpers/peertube-crypto' import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' import { getUrlFromWebfinger } from '../../helpers/webfinger' -import { IMAGE_MIMETYPE_EXT, CONFIG, sequelizeTypescript, CONSTRAINTS_FIELDS } from '../../initializers' +import { CONFIG, IMAGE_MIMETYPE_EXT, sequelizeTypescript } from '../../initializers' import { AccountModel } from '../../models/account/account' import { ActorModel } from '../../models/activitypub/actor' import { AvatarModel } from '../../models/avatar/avatar' import { ServerModel } from '../../models/server/server' import { VideoChannelModel } from '../../models/video/video-channel' -import { truncate } from 'lodash' +import { JobQueue } from '../job-queue' +import { getServerActor } from '../../helpers/utils' // Set account keys, this could be long so process after the account creation and do not block the client function setAsyncActorKeys (actor: ActorModel) { @@ -39,10 +40,15 @@ async function getOrCreateActorAndServerAndModel (activityActor: string | Activi const actorUrl = getActorUrl(activityActor) let actor = await ActorModel.loadByUrl(actorUrl) + // Orphan actor (not associated to an account of channel) so recreate it + if (actor && (!actor.Account && !actor.VideoChannel)) { + await actor.destroy() + actor = null + } // We don't have this actor in our database, fetch it on remote if (!actor) { - const result = await fetchRemoteActor(actorUrl) + const { result } = await fetchRemoteActor(actorUrl) if (result === undefined) throw new Error('Cannot fetch remote actor.') // Create the attributed to actor @@ -61,18 +67,16 @@ async function getOrCreateActorAndServerAndModel (activityActor: string | Activi } } - const options = { - arguments: [ result, ownerActor ], - errorMessage: 'Cannot save actor and server with many retries.' - } - actor = await retryTransactionWrapper(saveActorAndServerAndModelIfNotExist, options) + actor = await retryTransactionWrapper(saveActorAndServerAndModelIfNotExist, result, ownerActor) } - const options = { - arguments: [ actor ], - errorMessage: 'Cannot refresh actor if needed with many retries.' - } - return retryTransactionWrapper(refreshActorIfNeeded, options) + if (actor.Account) actor.Account.Actor = actor + if (actor.VideoChannel) actor.VideoChannel.Actor = actor + + actor = await retryTransactionWrapper(refreshActorIfNeeded, actor) + if (!actor) throw new Error('Actor ' + actor.url + ' does not exist anymore.') + + return actor } function buildActorInstance (type: ActivityPubActorType, url: string, preferredUsername: string, uuid?: string) { @@ -170,22 +174,20 @@ async function fetchAvatarIfExists (actorJSON: ActivityPubActor) { return undefined } -function normalizeActor (actor: any) { - if (!actor) return - - if (!actor.url || typeof actor.url !== 'string') { - actor.url = actor.url.href || actor.url.url +async function addFetchOutboxJob (actor: ActorModel) { + // Don't fetch ourselves + const serverActor = await getServerActor() + if (serverActor.id === actor.id) { + logger.error('Cannot fetch our own outbox!') + return undefined } - if (actor.summary && typeof actor.summary === 'string') { - actor.summary = truncate(actor.summary, { length: CONSTRAINTS_FIELDS.USERS.DESCRIPTION.max }) - - if (actor.summary.length < CONSTRAINTS_FIELDS.USERS.DESCRIPTION.min) { - actor.summary = null - } + const payload = { + uri: actor.outboxUrl, + type: 'activity' as 'activity' } - return + return JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload }) } export { @@ -196,7 +198,7 @@ export { fetchAvatarIfExists, updateActorInstance, updateActorAvatarInstance, - normalizeActor + addFetchOutboxJob } // --------------------------------------------------------------------------- @@ -253,6 +255,7 @@ function saveActorAndServerAndModelIfNotExist ( } else if (actorCreated.type === 'Group') { // Video channel actorCreated.VideoChannel = await saveVideoChannel(actorCreated, result, ownerActor, t) actorCreated.VideoChannel.Actor = actorCreated + actorCreated.VideoChannel.Account = ownerActor.Account } return actorCreated @@ -267,7 +270,7 @@ type FetchRemoteActorResult = { avatarName?: string attributedTo: ActivityPubAttributedTo[] } -async function fetchRemoteActor (actorUrl: string): Promise { +async function fetchRemoteActor (actorUrl: string): Promise<{ statusCode?: number, result: FetchRemoteActorResult }> { const options = { uri: actorUrl, method: 'GET', @@ -284,7 +287,7 @@ async function fetchRemoteActor (actorUrl: string): Promise { if (!actor.isOutdated()) return actor try { - const actorUrl = await getUrlFromWebfinger(actor.preferredUsername, actor.getHost()) - const result = await fetchRemoteActor(actorUrl) + const actorUrl = await getUrlFromWebfinger(actor.preferredUsername + '@' + actor.getHost()) + const { result, statusCode } = await fetchRemoteActor(actorUrl) + + if (statusCode === 404) { + logger.info('Deleting actor %s because there is a 404 in refresh actor.', actor.url) + actor.Account ? actor.Account.destroy() : actor.VideoChannel.destroy() + return undefined + } + if (result === undefined) { logger.warn('Cannot fetch remote actor in refresh actor.') return actor