X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=server%2Flib%2Factivitypub%2Factor.ts;h=04296864b96c88038ed4726ca166679a10558550;hb=5224c394b3bbac6ec1543e41fa0ec6db436e84fa;hp=a3f379b76938a29e6a587488611cbf468117346e;hpb=28f3d1b36a70426795240c9370e47b6c4ba847f8;p=github%2FChocobozzz%2FPeerTube.git diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index a3f379b76..04296864b 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts @@ -5,14 +5,14 @@ import * as uuidv4 from 'uuid/v4' import { ActivityPubActor, ActivityPubActorType } from '../../../shared/models/activitypub' import { ActivityPubAttributedTo } from '../../../shared/models/activitypub/objects' import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub' -import { isActorObjectValid, normalizeActor } from '../../helpers/custom-validators/activitypub/actor' +import { sanitizeAndCheckActorObject } 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, downloadImage } from '../../helpers/requests' import { getUrlFromWebfinger } from '../../helpers/webfinger' -import { AVATARS_SIZE, CONFIG, MIMETYPES, sequelizeTypescript } from '../../initializers' +import { AVATARS_SIZE, MIMETYPES, WEBSERVER } from '../../initializers/constants' import { AccountModel } from '../../models/account/account' import { ActorModel } from '../../models/activitypub/actor' import { AvatarModel } from '../../models/avatar/avatar' @@ -21,6 +21,8 @@ import { VideoChannelModel } from '../../models/video/video-channel' import { JobQueue } from '../job-queue' import { getServerActor } from '../../helpers/utils' import { ActorFetchByUrlType, fetchActorByUrl } from '../../helpers/actor' +import { CONFIG } from '../../initializers/config' +import { sequelizeTypescript } from '../../initializers/database' // Set account keys, this could be long so process after the account creation and do not block the client function setAsyncActorKeys (actor: ActorModel) { @@ -31,7 +33,7 @@ function setAsyncActorKeys (actor: ActorModel) { return actor.save() }) .catch(err => { - logger.error('Cannot set public/private keys of actor %d.', actor.uuid, { err }) + logger.error('Cannot set public/private keys of actor %d.', actor.url, { err }) return actor }) } @@ -44,6 +46,7 @@ async function getOrCreateActorAndServerAndModel ( ) { const actorUrl = getAPId(activityActor) let created = false + let accountPlaylistsUrl: string let actor = await fetchActorByUrl(actorUrl, fetchType) // Orphan actor (not associated to an account of channel) so recreate it @@ -70,7 +73,8 @@ async function getOrCreateActorAndServerAndModel ( try { // Don't recurse another time - ownerActor = await getOrCreateActorAndServerAndModel(accountAttributedTo.id, 'all', false) + const recurseIfNeeded = false + ownerActor = await getOrCreateActorAndServerAndModel(accountAttributedTo.id, 'all', recurseIfNeeded) } catch (err) { logger.error('Cannot get or create account attributed to video channel ' + actor.url) throw new Error(err) @@ -79,6 +83,7 @@ async function getOrCreateActorAndServerAndModel ( actor = await retryTransactionWrapper(saveActorAndServerAndModelIfNotExist, result, ownerActor) created = true + accountPlaylistsUrl = result.playlists } if (actor.Account) actor.Account.Actor = actor @@ -92,6 +97,12 @@ async function getOrCreateActorAndServerAndModel ( await JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload }) } + // We created a new account: fetch the playlists + if (created === true && actor.Account && accountPlaylistsUrl) { + const payload = { uri: accountPlaylistsUrl, accountId: actor.Account.id, type: 'account-playlists' as 'account-playlists' } + await JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload }) + } + return actorRefreshed } @@ -107,7 +118,7 @@ function buildActorInstance (type: ActivityPubActorType, url: string, preferredU followingCount: 0, inboxUrl: url + '/inbox', outboxUrl: url + '/outbox', - sharedInboxUrl: CONFIG.WEBSERVER.URL + '/inbox', + sharedInboxUrl: WEBSERVER.URL + '/inbox', followersUrl: url + '/followers', followingUrl: url + '/following' }) @@ -117,18 +128,17 @@ async function updateActorInstance (actorInstance: ActorModel, attributes: Activ const followersCount = await fetchActorTotalItems(attributes.followers) const followingCount = await fetchActorTotalItems(attributes.following) - actorInstance.set('type', attributes.type) - actorInstance.set('uuid', attributes.uuid) - actorInstance.set('preferredUsername', attributes.preferredUsername) - actorInstance.set('url', attributes.id) - actorInstance.set('publicKey', attributes.publicKey.publicKeyPem) - actorInstance.set('followersCount', followersCount) - actorInstance.set('followingCount', followingCount) - actorInstance.set('inboxUrl', attributes.inbox) - actorInstance.set('outboxUrl', attributes.outbox) - actorInstance.set('sharedInboxUrl', attributes.endpoints.sharedInbox) - actorInstance.set('followersUrl', attributes.followers) - actorInstance.set('followingUrl', attributes.following) + actorInstance.type = attributes.type + actorInstance.preferredUsername = attributes.preferredUsername + actorInstance.url = attributes.id + actorInstance.publicKey = attributes.publicKey.publicKeyPem + actorInstance.followersCount = followersCount + actorInstance.followingCount = followingCount + actorInstance.inboxUrl = attributes.inbox + actorInstance.outboxUrl = attributes.outbox + actorInstance.sharedInboxUrl = attributes.endpoints.sharedInbox + actorInstance.followersUrl = attributes.followers + actorInstance.followingUrl = attributes.following } async function updateActorAvatarInstance (actorInstance: ActorModel, avatarName: string, t: Transaction) { @@ -185,7 +195,7 @@ async function fetchAvatarIfExists (actorJSON: ActivityPubActor) { return undefined } -async function addFetchOutboxJob (actor: ActorModel) { +async function addFetchOutboxJob (actor: Pick) { // Don't fetch ourselves const serverActor = await getServerActor() if (serverActor.id === actor.id) { @@ -244,14 +254,14 @@ async function refreshActorIfNeeded ( await actor.save({ transaction: t }) if (actor.Account) { - actor.Account.set('name', result.name) - actor.Account.set('description', result.summary) + actor.Account.name = result.name + actor.Account.description = result.summary await actor.Account.save({ transaction: t }) } else if (actor.VideoChannel) { - actor.VideoChannel.set('name', result.name) - actor.VideoChannel.set('description', result.summary) - actor.VideoChannel.set('support', result.support) + actor.VideoChannel.name = result.name + actor.VideoChannel.description = result.summary + actor.VideoChannel.support = result.support await actor.VideoChannel.save({ transaction: t }) } @@ -259,7 +269,7 @@ async function refreshActorIfNeeded ( return { refreshed: true, actor } }) } catch (err) { - logger.warn('Cannot refresh actor.', { err }) + logger.warn('Cannot refresh actor %s.', actor.url, { err }) return { actor, refreshed: false } } } @@ -333,6 +343,8 @@ function saveActorAndServerAndModelIfNotExist ( actorCreated.VideoChannel.Account = ownerActor.Account } + actorCreated.Server = server + return actorCreated } } @@ -342,6 +354,7 @@ type FetchRemoteActorResult = { name: string summary: string support?: string + playlists?: string avatarName?: string attributedTo: ActivityPubAttributedTo[] } @@ -356,16 +369,16 @@ async function fetchRemoteActor (actorUrl: string): Promise<{ statusCode?: numbe logger.info('Fetching remote actor %s.', actorUrl) const requestResult = await doRequest(options) - normalizeActor(requestResult.body) - const actorJSON = requestResult.body - if (isActorObjectValid(actorJSON) === false) { + + if (sanitizeAndCheckActorObject(actorJSON) === false) { logger.debug('Remote actor JSON is not valid.', { actorJSON }) return { result: undefined, statusCode: requestResult.response.statusCode } } if (checkUrlsSameHost(actorJSON.id, actorUrl) !== true) { - throw new Error('Actor url ' + actorUrl + ' has not the same host than its AP id ' + actorJSON.id) + logger.warn('Actor url %s has not the same host than its AP id %s', actorUrl, actorJSON.id) + return { result: undefined, statusCode: requestResult.response.statusCode } } const followersCount = await fetchActorTotalItems(actorJSON.followers) @@ -373,7 +386,6 @@ async function fetchRemoteActor (actorUrl: string): Promise<{ statusCode?: numbe const actor = new ActorModel({ type: actorJSON.type, - uuid: actorJSON.uuid, preferredUsername: actorJSON.preferredUsername, url: actorJSON.id, publicKey: actorJSON.publicKey.publicKeyPem, @@ -398,6 +410,7 @@ async function fetchRemoteActor (actorUrl: string): Promise<{ statusCode?: numbe avatarName, summary: actorJSON.summary, support: actorJSON.support, + playlists: actorJSON.playlists, attributedTo: actorJSON.attributedTo } }