From 5c6d985faeef1d6793d3f44ca6374f1a9b722806 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 14 Nov 2018 15:01:28 +0100 Subject: Check activities host --- server/lib/activitypub/actor.ts | 13 ++++++-- server/lib/activitypub/crawl.ts | 5 +-- server/lib/activitypub/process/index.ts | 8 ----- server/lib/activitypub/process/process-create.ts | 5 ++- server/lib/activitypub/process/process-like.ts | 4 ++- server/lib/activitypub/process/process-undo.ts | 6 ++-- server/lib/activitypub/process/process.ts | 25 ++++++++++----- server/lib/activitypub/send/send-create.ts | 10 +++--- server/lib/activitypub/send/send-like.ts | 2 +- server/lib/activitypub/send/send-undo.ts | 2 +- server/lib/activitypub/share.ts | 15 ++++++--- server/lib/activitypub/url.ts | 12 ++++---- server/lib/activitypub/video-comments.ts | 17 ++++++++++ server/lib/activitypub/video-rates.ts | 36 +++++++++++++++++++--- server/lib/activitypub/videos.ts | 7 ++++- .../job-queue/handlers/activitypub-http-fetcher.ts | 2 +- 16 files changed, 122 insertions(+), 47 deletions(-) (limited to 'server/lib') diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index 45dd4443d..b16a00669 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts @@ -5,7 +5,7 @@ import * as url from 'url' 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 { checkUrlsSameHost, getActorUrl } from '../../helpers/activitypub' import { isActorObjectValid, normalizeActor } from '../../helpers/custom-validators/activitypub/actor' import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' import { retryTransactionWrapper, updateInstanceWithAnother } from '../../helpers/database-utils' @@ -65,8 +65,12 @@ async function getOrCreateActorAndServerAndModel ( const accountAttributedTo = result.attributedTo.find(a => a.type === 'Person') if (!accountAttributedTo) throw new Error('Cannot find account attributed to video channel ' + actor.url) + if (checkUrlsSameHost(accountAttributedTo.id, actorUrl) !== true) { + throw new Error(`Account attributed to ${accountAttributedTo.id} does not have the same host than actor url ${actorUrl}`) + } + try { - // Assert we don't recurse another time + // Don't recurse another time ownerActor = await getOrCreateActorAndServerAndModel(accountAttributedTo.id, 'all', false) } catch (err) { logger.error('Cannot get or create account attributed to video channel ' + actor.url) @@ -297,12 +301,15 @@ async function fetchRemoteActor (actorUrl: string): Promise<{ statusCode?: numbe normalizeActor(requestResult.body) const actorJSON: ActivityPubActor = requestResult.body - if (isActorObjectValid(actorJSON) === false) { logger.debug('Remote actor JSON is not valid.', { actorJSON: 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) + } + const followersCount = await fetchActorTotalItems(actorJSON.followers) const followingCount = await fetchActorTotalItems(actorJSON.following) diff --git a/server/lib/activitypub/crawl.ts b/server/lib/activitypub/crawl.ts index db9ce3293..1b9b14c2e 100644 --- a/server/lib/activitypub/crawl.ts +++ b/server/lib/activitypub/crawl.ts @@ -2,6 +2,7 @@ import { ACTIVITY_PUB, JOB_REQUEST_TIMEOUT } from '../../initializers' import { doRequest } from '../../helpers/requests' import { logger } from '../../helpers/logger' import * as Bluebird from 'bluebird' +import { ActivityPubOrderedCollection } from '../../../shared/models/activitypub' async function crawlCollectionPage (uri: string, handler: (items: T[]) => Promise | Bluebird) { logger.info('Crawling ActivityPub data on %s.', uri) @@ -14,7 +15,7 @@ async function crawlCollectionPage (uri: string, handler: (items: T[]) => Pr timeout: JOB_REQUEST_TIMEOUT } - const response = await doRequest(options) + const response = await doRequest>(options) const firstBody = response.body let limit = ACTIVITY_PUB.FETCH_PAGE_LIMIT @@ -23,7 +24,7 @@ async function crawlCollectionPage (uri: string, handler: (items: T[]) => Pr while (nextLink && i < limit) { options.uri = nextLink - const { body } = await doRequest(options) + const { body } = await doRequest>(options) nextLink = body.next i++ diff --git a/server/lib/activitypub/process/index.ts b/server/lib/activitypub/process/index.ts index db4980a72..5466739c1 100644 --- a/server/lib/activitypub/process/index.ts +++ b/server/lib/activitypub/process/index.ts @@ -1,9 +1 @@ export * from './process' -export * from './process-accept' -export * from './process-announce' -export * from './process-create' -export * from './process-delete' -export * from './process-follow' -export * from './process-like' -export * from './process-undo' -export * from './process-update' diff --git a/server/lib/activitypub/process/process-create.ts b/server/lib/activitypub/process/process-create.ts index cefe89db0..920d02cd2 100644 --- a/server/lib/activitypub/process/process-create.ts +++ b/server/lib/activitypub/process/process-create.ts @@ -12,6 +12,8 @@ import { getOrCreateVideoAndAccountAndChannel } from '../videos' import { forwardVideoRelatedActivity } from '../send/utils' import { Redis } from '../../redis' import { createOrUpdateCacheFile } from '../cache-file' +import { immutableAssign } from '../../../tests/utils' +import { getVideoDislikeActivityPubUrl, getVideoLikeActivityPubUrl } from '../url' async function processCreateActivity (activity: ActivityCreate, byActor: ActorModel) { const activityObject = activity.object @@ -65,9 +67,10 @@ async function processCreateDislike (byActor: ActorModel, activity: ActivityCrea videoId: video.id, accountId: byAccount.id } + const [ , created ] = await AccountVideoRateModel.findOrCreate({ where: rate, - defaults: rate, + defaults: immutableAssign(rate, { url: getVideoDislikeActivityPubUrl(byActor, video) }), transaction: t }) if (created === true) await video.increment('dislikes', { transaction: t }) diff --git a/server/lib/activitypub/process/process-like.ts b/server/lib/activitypub/process/process-like.ts index f7200db61..0dca17551 100644 --- a/server/lib/activitypub/process/process-like.ts +++ b/server/lib/activitypub/process/process-like.ts @@ -5,6 +5,8 @@ import { AccountVideoRateModel } from '../../../models/account/account-video-rat import { ActorModel } from '../../../models/activitypub/actor' import { forwardVideoRelatedActivity } from '../send/utils' import { getOrCreateVideoAndAccountAndChannel } from '../videos' +import { immutableAssign } from '../../../tests/utils' +import { getVideoDislikeActivityPubUrl, getVideoLikeActivityPubUrl } from '../url' async function processLikeActivity (activity: ActivityLike, byActor: ActorModel) { return retryTransactionWrapper(processLikeVideo, byActor, activity) @@ -34,7 +36,7 @@ async function processLikeVideo (byActor: ActorModel, activity: ActivityLike) { } const [ , created ] = await AccountVideoRateModel.findOrCreate({ where: rate, - defaults: rate, + defaults: immutableAssign(rate, { url: getVideoLikeActivityPubUrl(byActor, video) }), transaction: t }) if (created === true) await video.increment('likes', { transaction: t }) diff --git a/server/lib/activitypub/process/process-undo.ts b/server/lib/activitypub/process/process-undo.ts index ff019cd8c..438a013b6 100644 --- a/server/lib/activitypub/process/process-undo.ts +++ b/server/lib/activitypub/process/process-undo.ts @@ -55,7 +55,8 @@ async function processUndoLike (byActor: ActorModel, activity: ActivityUndo) { return sequelizeTypescript.transaction(async t => { if (!byActor.Account) throw new Error('Unknown account ' + byActor.url) - const rate = await AccountVideoRateModel.load(byActor.Account.id, video.id, t) + let rate = await AccountVideoRateModel.loadByUrl(likeActivity.id, t) + if (!rate) rate = await AccountVideoRateModel.load(byActor.Account.id, video.id, t) if (!rate) throw new Error(`Unknown rate by account ${byActor.Account.id} for video ${video.id}.`) await rate.destroy({ transaction: t }) @@ -78,7 +79,8 @@ async function processUndoDislike (byActor: ActorModel, activity: ActivityUndo) return sequelizeTypescript.transaction(async t => { if (!byActor.Account) throw new Error('Unknown account ' + byActor.url) - const rate = await AccountVideoRateModel.load(byActor.Account.id, video.id, t) + let rate = await AccountVideoRateModel.loadByUrl(dislike.id, t) + if (!rate) rate = await AccountVideoRateModel.load(byActor.Account.id, video.id, t) if (!rate) throw new Error(`Unknown rate by account ${byActor.Account.id} for video ${video.id}.`) await rate.destroy({ transaction: t }) diff --git a/server/lib/activitypub/process/process.ts b/server/lib/activitypub/process/process.ts index b263f1ea2..b9b255ddf 100644 --- a/server/lib/activitypub/process/process.ts +++ b/server/lib/activitypub/process/process.ts @@ -1,5 +1,5 @@ import { Activity, ActivityType } from '../../../../shared/models/activitypub' -import { getActorUrl } from '../../../helpers/activitypub' +import { checkUrlsSameHost, getActorUrl } from '../../../helpers/activitypub' import { logger } from '../../../helpers/logger' import { ActorModel } from '../../../models/activitypub/actor' import { processAcceptActivity } from './process-accept' @@ -25,11 +25,17 @@ const processActivity: { [ P in ActivityType ]: (activity: Activity, byActor: Ac Like: processLikeActivity } -async function processActivities (activities: Activity[], signatureActor?: ActorModel, inboxActor?: ActorModel) { +async function processActivities ( + activities: Activity[], + options: { + signatureActor?: ActorModel + inboxActor?: ActorModel + outboxUrl?: string + } = {}) { const actorsCache: { [ url: string ]: ActorModel } = {} for (const activity of activities) { - if (!signatureActor && [ 'Create', 'Announce', 'Like' ].indexOf(activity.type) === -1) { + if (!options.signatureActor && [ 'Create', 'Announce', 'Like' ].indexOf(activity.type) === -1) { logger.error('Cannot process activity %s (type: %s) without the actor signature.', activity.id, activity.type) continue } @@ -37,12 +43,17 @@ async function processActivities (activities: Activity[], signatureActor?: Actor const actorUrl = getActorUrl(activity.actor) // When we fetch remote data, we don't have signature - if (signatureActor && actorUrl !== signatureActor.url) { - logger.warn('Signature mismatch between %s and %s.', actorUrl, signatureActor.url) + if (options.signatureActor && actorUrl !== options.signatureActor.url) { + logger.warn('Signature mismatch between %s and %s, skipping.', actorUrl, options.signatureActor.url) continue } - const byActor = signatureActor || actorsCache[actorUrl] || await getOrCreateActorAndServerAndModel(actorUrl) + if (options.outboxUrl && checkUrlsSameHost(options.outboxUrl, actorUrl) !== true) { + logger.warn('Host mismatch between outbox URL %s and actor URL %s, skipping.', options.outboxUrl, actorUrl) + continue + } + + const byActor = options.signatureActor || actorsCache[actorUrl] || await getOrCreateActorAndServerAndModel(actorUrl) actorsCache[actorUrl] = byActor const activityProcessor = processActivity[activity.type] @@ -52,7 +63,7 @@ async function processActivities (activities: Activity[], signatureActor?: Actor } try { - await activityProcessor(activity, byActor, inboxActor) + await activityProcessor(activity, byActor, options.inboxActor) } catch (err) { logger.warn('Cannot process activity %s.', activity.type, { err }) } diff --git a/server/lib/activitypub/send/send-create.ts b/server/lib/activitypub/send/send-create.ts index 285edba3b..e3fca0a17 100644 --- a/server/lib/activitypub/send/send-create.ts +++ b/server/lib/activitypub/send/send-create.ts @@ -95,7 +95,7 @@ async function sendCreateView (byActor: ActorModel, video: VideoModel, t: Transa logger.info('Creating job to send view of %s.', video.url) const url = getVideoViewActivityPubUrl(byActor, video) - const viewActivity = buildViewActivity(byActor, video) + const viewActivity = buildViewActivity(url, byActor, video) return sendVideoRelatedCreateActivity({ // Use the server actor to send the view @@ -111,7 +111,7 @@ async function sendCreateDislike (byActor: ActorModel, video: VideoModel, t: Tra logger.info('Creating job to dislike %s.', video.url) const url = getVideoDislikeActivityPubUrl(byActor, video) - const dislikeActivity = buildDislikeActivity(byActor, video) + const dislikeActivity = buildDislikeActivity(url, byActor, video) return sendVideoRelatedCreateActivity({ byActor, @@ -136,16 +136,18 @@ function buildCreateActivity (url: string, byActor: ActorModel, object: any, aud ) } -function buildDislikeActivity (byActor: ActorModel, video: VideoModel) { +function buildDislikeActivity (url: string, byActor: ActorModel, video: VideoModel) { return { + id: url, type: 'Dislike', actor: byActor.url, object: video.url } } -function buildViewActivity (byActor: ActorModel, video: VideoModel) { +function buildViewActivity (url: string, byActor: ActorModel, video: VideoModel) { return { + id: url, type: 'View', actor: byActor.url, object: video.url diff --git a/server/lib/activitypub/send/send-like.ts b/server/lib/activitypub/send/send-like.ts index 89307acc6..35227887a 100644 --- a/server/lib/activitypub/send/send-like.ts +++ b/server/lib/activitypub/send/send-like.ts @@ -24,8 +24,8 @@ function buildLikeActivity (url: string, byActor: ActorModel, video: VideoModel, return audiencify( { - type: 'Like' as 'Like', id: url, + type: 'Like' as 'Like', actor: byActor.url, object: video.url }, diff --git a/server/lib/activitypub/send/send-undo.ts b/server/lib/activitypub/send/send-undo.ts index 5236d2cb3..bf1b6e117 100644 --- a/server/lib/activitypub/send/send-undo.ts +++ b/server/lib/activitypub/send/send-undo.ts @@ -64,7 +64,7 @@ async function sendUndoDislike (byActor: ActorModel, video: VideoModel, t: Trans logger.info('Creating job to undo a dislike of video %s.', video.url) const dislikeUrl = getVideoDislikeActivityPubUrl(byActor, video) - const dislikeActivity = buildDislikeActivity(byActor, video) + const dislikeActivity = buildDislikeActivity(dislikeUrl, byActor, video) const createDislikeActivity = buildCreateActivity(dislikeUrl, byActor, dislikeActivity) return sendUndoVideoRelatedActivity({ byActor, video, url: dislikeUrl, activity: createDislikeActivity, transaction: t }) diff --git a/server/lib/activitypub/share.ts b/server/lib/activitypub/share.ts index 3ff60a97c..d2649e2d5 100644 --- a/server/lib/activitypub/share.ts +++ b/server/lib/activitypub/share.ts @@ -4,13 +4,14 @@ import { getServerActor } from '../../helpers/utils' import { VideoModel } from '../../models/video/video' import { VideoShareModel } from '../../models/video/video-share' import { sendUndoAnnounce, sendVideoAnnounce } from './send' -import { getAnnounceActivityPubUrl } from './url' +import { getVideoAnnounceActivityPubUrl } from './url' import { VideoChannelModel } from '../../models/video/video-channel' import * as Bluebird from 'bluebird' import { doRequest } from '../../helpers/requests' import { getOrCreateActorAndServerAndModel } from './actor' import { logger } from '../../helpers/logger' import { CRAWL_REQUEST_CONCURRENCY } from '../../initializers' +import { checkUrlsSameHost, getActorUrl } from '../../helpers/activitypub' async function shareVideoByServerAndChannel (video: VideoModel, t: Transaction) { if (video.privacy === VideoPrivacy.PRIVATE) return undefined @@ -38,9 +39,13 @@ async function addVideoShares (shareUrls: string[], instance: VideoModel) { json: true, activityPub: true }) - if (!body || !body.actor) throw new Error('Body of body actor is invalid') + if (!body || !body.actor) throw new Error('Body or body actor is invalid') + + const actorUrl = getActorUrl(body.actor) + if (checkUrlsSameHost(shareUrl, actorUrl) !== true) { + throw new Error(`Actor url ${actorUrl} has not the same host than the share url ${shareUrl}`) + } - const actorUrl = body.actor const actor = await getOrCreateActorAndServerAndModel(actorUrl) const entry = { @@ -72,7 +77,7 @@ export { async function shareByServer (video: VideoModel, t: Transaction) { const serverActor = await getServerActor() - const serverShareUrl = getAnnounceActivityPubUrl(video.url, serverActor) + const serverShareUrl = getVideoAnnounceActivityPubUrl(serverActor, video) return VideoShareModel.findOrCreate({ defaults: { actorId: serverActor.id, @@ -91,7 +96,7 @@ async function shareByServer (video: VideoModel, t: Transaction) { } async function shareByVideoChannel (video: VideoModel, t: Transaction) { - const videoChannelShareUrl = getAnnounceActivityPubUrl(video.url, video.VideoChannel.Actor) + const videoChannelShareUrl = getVideoAnnounceActivityPubUrl(video.VideoChannel.Actor, video) return VideoShareModel.findOrCreate({ defaults: { actorId: video.VideoChannel.actorId, diff --git a/server/lib/activitypub/url.ts b/server/lib/activitypub/url.ts index e792be698..38f15448c 100644 --- a/server/lib/activitypub/url.ts +++ b/server/lib/activitypub/url.ts @@ -33,14 +33,14 @@ function getVideoAbuseActivityPubUrl (videoAbuse: VideoAbuseModel) { } function getVideoViewActivityPubUrl (byActor: ActorModel, video: VideoModel) { - return video.url + '/views/' + byActor.uuid + '/' + new Date().toISOString() + return byActor.url + '/views/videos/' + video.id + '/' + new Date().toISOString() } -function getVideoLikeActivityPubUrl (byActor: ActorModel, video: VideoModel) { +function getVideoLikeActivityPubUrl (byActor: ActorModel, video: VideoModel | { id: number }) { return byActor.url + '/likes/' + video.id } -function getVideoDislikeActivityPubUrl (byActor: ActorModel, video: VideoModel) { +function getVideoDislikeActivityPubUrl (byActor: ActorModel, video: VideoModel | { id: number }) { return byActor.url + '/dislikes/' + video.id } @@ -74,8 +74,8 @@ function getActorFollowAcceptActivityPubUrl (actorFollow: ActorFollowModel) { return follower.url + '/accepts/follows/' + me.id } -function getAnnounceActivityPubUrl (originalUrl: string, byActor: ActorModel) { - return originalUrl + '/announces/' + byActor.id +function getVideoAnnounceActivityPubUrl (byActor: ActorModel, video: VideoModel) { + return video.url + '/announces/' + byActor.id } function getDeleteActivityPubUrl (originalUrl: string) { @@ -97,7 +97,7 @@ export { getVideoAbuseActivityPubUrl, getActorFollowActivityPubUrl, getActorFollowAcceptActivityPubUrl, - getAnnounceActivityPubUrl, + getVideoAnnounceActivityPubUrl, getUpdateActivityPubUrl, getUndoActivityPubUrl, getVideoViewActivityPubUrl, diff --git a/server/lib/activitypub/video-comments.ts b/server/lib/activitypub/video-comments.ts index c8c17f4c4..5868e7297 100644 --- a/server/lib/activitypub/video-comments.ts +++ b/server/lib/activitypub/video-comments.ts @@ -9,6 +9,7 @@ import { VideoCommentModel } from '../../models/video/video-comment' import { getOrCreateActorAndServerAndModel } from './actor' import { getOrCreateVideoAndAccountAndChannel } from './videos' import * as Bluebird from 'bluebird' +import { checkUrlsSameHost } from '../../helpers/activitypub' async function videoCommentActivityObjectToDBAttributes (video: VideoModel, actor: ActorModel, comment: VideoCommentObject) { let originCommentId: number = null @@ -61,6 +62,14 @@ async function addVideoComment (videoInstance: VideoModel, commentUrl: string) { const actorUrl = body.attributedTo if (!actorUrl) return { created: false } + if (checkUrlsSameHost(commentUrl, actorUrl) !== true) { + throw new Error(`Actor url ${actorUrl} has not the same host than the comment url ${commentUrl}`) + } + + if (checkUrlsSameHost(body.id, commentUrl) !== true) { + throw new Error(`Comment url ${commentUrl} host is different from the AP object id ${body.id}`) + } + const actor = await getOrCreateActorAndServerAndModel(actorUrl) const entry = await videoCommentActivityObjectToDBAttributes(videoInstance, actor, body) if (!entry) return { created: false } @@ -134,6 +143,14 @@ async function resolveThread (url: string, comments: VideoCommentModel[] = []) { const actorUrl = body.attributedTo if (!actorUrl) throw new Error('Miss attributed to in comment') + if (checkUrlsSameHost(url, actorUrl) !== true) { + throw new Error(`Actor url ${actorUrl} has not the same host than the comment url ${url}`) + } + + if (checkUrlsSameHost(body.id, url) !== true) { + throw new Error(`Comment url ${url} host is different from the AP object id ${body.id}`) + } + const actor = await getOrCreateActorAndServerAndModel(actorUrl) const comment = new VideoCommentModel({ url: body.id, diff --git a/server/lib/activitypub/video-rates.ts b/server/lib/activitypub/video-rates.ts index 1619251c3..1854b44c4 100644 --- a/server/lib/activitypub/video-rates.ts +++ b/server/lib/activitypub/video-rates.ts @@ -8,13 +8,35 @@ import { getOrCreateActorAndServerAndModel } from './actor' import { AccountVideoRateModel } from '../../models/account/account-video-rate' import { logger } from '../../helpers/logger' import { CRAWL_REQUEST_CONCURRENCY } from '../../initializers' +import { doRequest } from '../../helpers/requests' +import { checkUrlsSameHost, getActorUrl } from '../../helpers/activitypub' +import { ActorModel } from '../../models/activitypub/actor' +import { getVideoDislikeActivityPubUrl, getVideoLikeActivityPubUrl } from './url' -async function createRates (actorUrls: string[], video: VideoModel, rate: VideoRateType) { +async function createRates (ratesUrl: string[], video: VideoModel, rate: VideoRateType) { let rateCounts = 0 - await Bluebird.map(actorUrls, async actorUrl => { + await Bluebird.map(ratesUrl, async rateUrl => { try { + // Fetch url + const { body } = await doRequest({ + uri: rateUrl, + json: true, + activityPub: true + }) + if (!body || !body.actor) throw new Error('Body or body actor is invalid') + + const actorUrl = getActorUrl(body.actor) + if (checkUrlsSameHost(actorUrl, rateUrl) !== true) { + throw new Error(`Rate url ${rateUrl} has not the same host than actor url ${actorUrl}`) + } + + if (checkUrlsSameHost(body.id, rateUrl) !== true) { + throw new Error(`Rate url ${rateUrl} host is different from the AP object id ${body.id}`) + } + const actor = await getOrCreateActorAndServerAndModel(actorUrl) + const [ , created ] = await AccountVideoRateModel .findOrCreate({ where: { @@ -24,13 +46,14 @@ async function createRates (actorUrls: string[], video: VideoModel, rate: VideoR defaults: { videoId: video.id, accountId: actor.Account.id, - type: rate + type: rate, + url: body.id } }) if (created) rateCounts += 1 } catch (err) { - logger.warn('Cannot add rate %s for actor %s.', rate, actorUrl, { err }) + logger.warn('Cannot add rate %s.', rateUrl, { err }) } }, { concurrency: CRAWL_REQUEST_CONCURRENCY }) @@ -62,7 +85,12 @@ async function sendVideoRateChange (account: AccountModel, if (dislikes > 0) await sendCreateDislike(actor, video, t) } +function getRateUrl (rateType: VideoRateType, actor: ActorModel, video: VideoModel) { + return rateType === 'like' ? getVideoLikeActivityPubUrl(actor, video) : getVideoDislikeActivityPubUrl(actor, video) +} + export { + getRateUrl, createRates, sendVideoRateChange } diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts index 3da363c0a..5bd03c8c6 100644 --- a/server/lib/activitypub/videos.ts +++ b/server/lib/activitypub/videos.ts @@ -29,6 +29,7 @@ import { createRates } from './video-rates' import { addVideoShares, shareVideoByServerAndChannel } from './share' import { AccountModel } from '../../models/account/account' import { fetchVideoByUrl, VideoFetchByUrlType } from '../../helpers/video' +import { checkUrlsSameHost } from '../../helpers/activitypub' async function federateVideoIfNeeded (video: VideoModel, isNewVideo: boolean, transaction?: sequelize.Transaction) { // If the video is not private and published, we federate it @@ -63,7 +64,7 @@ async function fetchRemoteVideo (videoUrl: string): Promise<{ response: request. const { response, body } = await doRequest(options) - if (sanitizeAndCheckVideoTorrentObject(body) === false) { + if (sanitizeAndCheckVideoTorrentObject(body) === false || checkUrlsSameHost(body.id, videoUrl) !== true) { logger.debug('Remote video JSON is not valid.', { body }) return { response, videoObject: undefined } } @@ -107,6 +108,10 @@ function getOrCreateVideoChannelFromVideoObject (videoObject: VideoTorrentObject const channel = videoObject.attributedTo.find(a => a.type === 'Group') if (!channel) throw new Error('Cannot find associated video channel to video ' + videoObject.url) + if (checkUrlsSameHost(channel.id, videoObject.id) !== true) { + throw new Error(`Video channel url ${channel.id} does not have the same host than video object id ${videoObject.id}`) + } + return getOrCreateActorAndServerAndModel(channel.id, 'all') } diff --git a/server/lib/job-queue/handlers/activitypub-http-fetcher.ts b/server/lib/job-queue/handlers/activitypub-http-fetcher.ts index 42217c27c..67ccfa995 100644 --- a/server/lib/job-queue/handlers/activitypub-http-fetcher.ts +++ b/server/lib/job-queue/handlers/activitypub-http-fetcher.ts @@ -23,7 +23,7 @@ async function processActivityPubHttpFetcher (job: Bull.Job) { if (payload.videoId) video = await VideoModel.loadAndPopulateAccountAndServerAndTags(payload.videoId) const fetcherType: { [ id in FetchType ]: (items: any[]) => Promise } = { - 'activity': items => processActivities(items), + 'activity': items => processActivities(items, { outboxUrl: payload.uri }), 'video-likes': items => createRates(items, video, 'like'), 'video-dislikes': items => createRates(items, video, 'dislike'), 'video-shares': items => addVideoShares(items, video), -- cgit v1.2.3