From 7e98a7df7d04e19ba67163a86c7b876d78d76839 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 23 Mar 2022 14:24:50 +0100 Subject: Remove activitypub helper Put functions in lib/activitypub instead --- server/controllers/activitypub/client.ts | 9 +- server/controllers/activitypub/outbox.ts | 3 +- server/helpers/activitypub.ts | 229 --------------------- server/lib/activitypub/activity.ts | 21 ++ server/lib/activitypub/actors/get.ts | 4 +- .../lib/activitypub/actors/shared/url-to-object.ts | 3 +- server/lib/activitypub/collection.ts | 62 ++++++ server/lib/activitypub/context.ts | 137 ++++++++++++ server/lib/activitypub/playlists/create-update.ts | 4 +- server/lib/activitypub/playlists/get.ts | 2 +- .../activitypub/playlists/shared/url-to-object.ts | 2 +- server/lib/activitypub/process/process-announce.ts | 10 +- server/lib/activitypub/process/process-flag.ts | 2 +- server/lib/activitypub/process/process-follow.ts | 2 +- server/lib/activitypub/process/process-like.ts | 2 +- server/lib/activitypub/process/process.ts | 3 +- server/lib/activitypub/share.ts | 4 +- server/lib/activitypub/url.ts | 31 ++- server/lib/activitypub/video-comments.ts | 2 +- server/lib/activitypub/videos/get.ts | 2 +- .../activitypub/videos/shared/abstract-builder.ts | 2 +- server/lib/activitypub/videos/shared/trackers.ts | 2 +- .../lib/activitypub/videos/shared/url-to-object.ts | 2 +- .../lib/job-queue/handlers/activitypub-cleaner.ts | 2 +- .../handlers/utils/activitypub-http-utils.ts | 2 +- server/middlewares/activitypub.ts | 2 +- server/models/actor/actor.ts | 2 +- server/models/video/video-file.ts | 2 +- server/models/video/video-playlist.ts | 2 +- server/tests/api/activitypub/helpers.ts | 2 +- server/tests/api/activitypub/security.ts | 3 +- server/tests/shared/requests.ts | 2 +- 32 files changed, 289 insertions(+), 270 deletions(-) delete mode 100644 server/helpers/activitypub.ts create mode 100644 server/lib/activitypub/activity.ts create mode 100644 server/lib/activitypub/collection.ts create mode 100644 server/lib/activitypub/context.ts diff --git a/server/controllers/activitypub/client.ts b/server/controllers/activitypub/client.ts index fc27ebbe8..99637dbab 100644 --- a/server/controllers/activitypub/client.ts +++ b/server/controllers/activitypub/client.ts @@ -1,10 +1,11 @@ import cors from 'cors' import express from 'express' +import { activityPubCollectionPagination } from '@server/lib/activitypub/collection' +import { activityPubContextify } from '@server/lib/activitypub/context' import { getServerActor } from '@server/models/application/application' import { MAccountId, MActorId, MChannelId, MVideoId } from '@server/types/models' import { VideoPrivacy, VideoRateType } from '../../../shared/models/videos' import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model' -import { activityPubCollectionPagination, activityPubContextify } from '../../helpers/activitypub' import { ROUTE_CACHE_LIFETIME, WEBSERVER } from '../../initializers/constants' import { audiencify, getAudience } from '../../lib/activitypub/audience' import { buildAnnounceWithVideoAudience, buildLikeActivity } from '../../lib/activitypub/send' @@ -400,7 +401,7 @@ function videoPlaylistElementController (req: express.Request, res: express.Resp // --------------------------------------------------------------------------- -async function actorFollowing (req: express.Request, actor: MActorId) { +function actorFollowing (req: express.Request, actor: MActorId) { const handler = (start: number, count: number) => { return ActorFollowModel.listAcceptedFollowingUrlsForApi([ actor.id ], undefined, start, count) } @@ -408,7 +409,7 @@ async function actorFollowing (req: express.Request, actor: MActorId) { return activityPubCollectionPagination(WEBSERVER.URL + req.path, handler, req.query.page) } -async function actorFollowers (req: express.Request, actor: MActorId) { +function actorFollowers (req: express.Request, actor: MActorId) { const handler = (start: number, count: number) => { return ActorFollowModel.listAcceptedFollowerUrlsForAP([ actor.id ], undefined, start, count) } @@ -416,7 +417,7 @@ async function actorFollowers (req: express.Request, actor: MActorId) { return activityPubCollectionPagination(WEBSERVER.URL + req.path, handler, req.query.page) } -async function actorPlaylists (req: express.Request, options: { account: MAccountId } | { channel: MChannelId }) { +function actorPlaylists (req: express.Request, options: { account: MAccountId } | { channel: MChannelId }) { const handler = (start: number, count: number) => { return VideoPlaylistModel.listPublicUrlsOfForAP(options, start, count) } diff --git a/server/controllers/activitypub/outbox.ts b/server/controllers/activitypub/outbox.ts index cdef8e969..4e7a3afeb 100644 --- a/server/controllers/activitypub/outbox.ts +++ b/server/controllers/activitypub/outbox.ts @@ -1,8 +1,9 @@ import express from 'express' +import { activityPubCollectionPagination } from '@server/lib/activitypub/collection' +import { activityPubContextify } from '@server/lib/activitypub/context' import { MActorLight } from '@server/types/models' import { Activity } from '../../../shared/models/activitypub/activity' import { VideoPrivacy } from '../../../shared/models/videos' -import { activityPubCollectionPagination, activityPubContextify } from '../../helpers/activitypub' import { logger } from '../../helpers/logger' import { buildAudience } from '../../lib/activitypub/audience' import { buildAnnounceActivity, buildCreateActivity } from '../../lib/activitypub/send' diff --git a/server/helpers/activitypub.ts b/server/helpers/activitypub.ts deleted file mode 100644 index 9d6d8b2fa..000000000 --- a/server/helpers/activitypub.ts +++ /dev/null @@ -1,229 +0,0 @@ -import Bluebird from 'bluebird' -import { URL } from 'url' -import validator from 'validator' -import { ContextType } from '@shared/models/activitypub/context' -import { ResultList } from '../../shared/models' -import { ACTIVITY_PUB, REMOTE_SCHEME } from '../initializers/constants' -import { MActor, MVideoWithHost } from '../types/models' -import { pageToStartAndCount } from './core-utils' -import { signJsonLDObject } from './peertube-crypto' - -function getContextData (type: ContextType) { - const context: any[] = [ - 'https://www.w3.org/ns/activitystreams', - 'https://w3id.org/security/v1', - { - RsaSignature2017: 'https://w3id.org/security#RsaSignature2017' - } - ] - - if (type !== 'View' && type !== 'Announce') { - const additional = { - pt: 'https://joinpeertube.org/ns#', - sc: 'http://schema.org#' - } - - if (type === 'CacheFile') { - Object.assign(additional, { - expires: 'sc:expires', - CacheFile: 'pt:CacheFile' - }) - } else { - Object.assign(additional, { - Hashtag: 'as:Hashtag', - uuid: 'sc:identifier', - category: 'sc:category', - licence: 'sc:license', - subtitleLanguage: 'sc:subtitleLanguage', - sensitive: 'as:sensitive', - language: 'sc:inLanguage', - - // TODO: remove in a few versions, introduced in 4.2 - icons: 'as:icon', - - isLiveBroadcast: 'sc:isLiveBroadcast', - liveSaveReplay: { - '@type': 'sc:Boolean', - '@id': 'pt:liveSaveReplay' - }, - permanentLive: { - '@type': 'sc:Boolean', - '@id': 'pt:permanentLive' - }, - latencyMode: { - '@type': 'sc:Number', - '@id': 'pt:latencyMode' - }, - - Infohash: 'pt:Infohash', - Playlist: 'pt:Playlist', - PlaylistElement: 'pt:PlaylistElement', - - originallyPublishedAt: 'sc:datePublished', - views: { - '@type': 'sc:Number', - '@id': 'pt:views' - }, - state: { - '@type': 'sc:Number', - '@id': 'pt:state' - }, - size: { - '@type': 'sc:Number', - '@id': 'pt:size' - }, - fps: { - '@type': 'sc:Number', - '@id': 'pt:fps' - }, - startTimestamp: { - '@type': 'sc:Number', - '@id': 'pt:startTimestamp' - }, - stopTimestamp: { - '@type': 'sc:Number', - '@id': 'pt:stopTimestamp' - }, - position: { - '@type': 'sc:Number', - '@id': 'pt:position' - }, - commentsEnabled: { - '@type': 'sc:Boolean', - '@id': 'pt:commentsEnabled' - }, - downloadEnabled: { - '@type': 'sc:Boolean', - '@id': 'pt:downloadEnabled' - }, - waitTranscoding: { - '@type': 'sc:Boolean', - '@id': 'pt:waitTranscoding' - }, - support: { - '@type': 'sc:Text', - '@id': 'pt:support' - }, - likes: { - '@id': 'as:likes', - '@type': '@id' - }, - dislikes: { - '@id': 'as:dislikes', - '@type': '@id' - }, - playlists: { - '@id': 'pt:playlists', - '@type': '@id' - }, - shares: { - '@id': 'as:shares', - '@type': '@id' - }, - comments: { - '@id': 'as:comments', - '@type': '@id' - } - }) - } - - context.push(additional) - } - - return { - '@context': context - } -} - -function activityPubContextify (data: T, type: ContextType = 'All') { - return Object.assign({}, data, getContextData(type)) -} - -type ActivityPubCollectionPaginationHandler = (start: number, count: number) => Bluebird> | Promise> -async function activityPubCollectionPagination ( - baseUrl: string, - handler: ActivityPubCollectionPaginationHandler, - page?: any, - size = ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE -) { - if (!page || !validator.isInt(page)) { - // We just display the first page URL, we only need the total items - const result = await handler(0, 1) - - return { - id: baseUrl, - type: 'OrderedCollectionPage', - totalItems: result.total, - first: result.data.length === 0 - ? undefined - : baseUrl + '?page=1' - } - } - - const { start, count } = pageToStartAndCount(page, size) - const result = await handler(start, count) - - let next: string | undefined - let prev: string | undefined - - // Assert page is a number - page = parseInt(page, 10) - - // There are more results - if (result.total > page * size) { - next = baseUrl + '?page=' + (page + 1) - } - - if (page > 1) { - prev = baseUrl + '?page=' + (page - 1) - } - - return { - id: baseUrl + '?page=' + page, - type: 'OrderedCollectionPage', - prev, - next, - partOf: baseUrl, - orderedItems: result.data, - totalItems: result.total - } - -} - -function buildSignedActivity (byActor: MActor, data: T, contextType?: ContextType) { - const activity = activityPubContextify(data, contextType) - - return signJsonLDObject(byActor, activity) -} - -function getAPId (object: string | { id: string }) { - if (typeof object === 'string') return object - - return object.id -} - -function checkUrlsSameHost (url1: string, url2: string) { - const idHost = new URL(url1).host - const actorHost = new URL(url2).host - - return idHost && actorHost && idHost.toLowerCase() === actorHost.toLowerCase() -} - -function buildRemoteVideoBaseUrl (video: MVideoWithHost, path: string, scheme?: string) { - if (!scheme) scheme = REMOTE_SCHEME.HTTP - - const host = video.VideoChannel.Actor.Server.host - - return scheme + '://' + host + path -} - -// --------------------------------------------------------------------------- - -export { - checkUrlsSameHost, - getAPId, - activityPubContextify, - activityPubCollectionPagination, - buildSignedActivity, - buildRemoteVideoBaseUrl -} diff --git a/server/lib/activitypub/activity.ts b/server/lib/activitypub/activity.ts new file mode 100644 index 000000000..215b50b69 --- /dev/null +++ b/server/lib/activitypub/activity.ts @@ -0,0 +1,21 @@ +import { signJsonLDObject } from '@server/helpers/peertube-crypto' +import { MActor } from '@server/types/models' +import { ContextType } from '@shared/models' +import { activityPubContextify } from './context' + +function buildSignedActivity (byActor: MActor, data: T, contextType?: ContextType) { + const activity = activityPubContextify(data, contextType) + + return signJsonLDObject(byActor, activity) +} + +function getAPId (object: string | { id: string }) { + if (typeof object === 'string') return object + + return object.id +} + +export { + buildSignedActivity, + getAPId +} diff --git a/server/lib/activitypub/actors/get.ts b/server/lib/activitypub/actors/get.ts index 4200ddb4d..d2b651082 100644 --- a/server/lib/activitypub/actors/get.ts +++ b/server/lib/activitypub/actors/get.ts @@ -1,11 +1,11 @@ - -import { checkUrlsSameHost, getAPId } from '@server/helpers/activitypub' import { retryTransactionWrapper } from '@server/helpers/database-utils' import { logger } from '@server/helpers/logger' import { JobQueue } from '@server/lib/job-queue' import { ActorLoadByUrlType, loadActorByUrl } from '@server/lib/model-loaders' import { MActor, MActorAccountChannelId, MActorAccountChannelIdActor, MActorAccountId, MActorFullActor } from '@server/types/models' import { ActivityPubActor } from '@shared/models' +import { getAPId } from '../activity' +import { checkUrlsSameHost } from '../url' import { refreshActorIfNeeded } from './refresh' import { APActorCreator, fetchRemoteActor } from './shared' diff --git a/server/lib/activitypub/actors/shared/url-to-object.ts b/server/lib/activitypub/actors/shared/url-to-object.ts index f4f16b044..982d52b79 100644 --- a/server/lib/activitypub/actors/shared/url-to-object.ts +++ b/server/lib/activitypub/actors/shared/url-to-object.ts @@ -1,9 +1,8 @@ - -import { checkUrlsSameHost } from '@server/helpers/activitypub' import { sanitizeAndCheckActorObject } from '@server/helpers/custom-validators/activitypub/actor' import { logger } from '@server/helpers/logger' import { doJSONRequest } from '@server/helpers/requests' import { ActivityPubActor, ActivityPubOrderedCollection } from '@shared/models' +import { checkUrlsSameHost } from '../../url' async function fetchRemoteActor (actorUrl: string): Promise<{ statusCode: number, actorObject: ActivityPubActor }> { logger.info('Fetching remote actor %s.', actorUrl) diff --git a/server/lib/activitypub/collection.ts b/server/lib/activitypub/collection.ts new file mode 100644 index 000000000..43a704aa4 --- /dev/null +++ b/server/lib/activitypub/collection.ts @@ -0,0 +1,62 @@ +import Bluebird from 'bluebird' +import validator from 'validator' +import { pageToStartAndCount } from '@server/helpers/core-utils' +import { ACTIVITY_PUB } from '@server/initializers/constants' +import { ResultList } from '@shared/models' + +type ActivityPubCollectionPaginationHandler = (start: number, count: number) => Bluebird> | Promise> + +async function activityPubCollectionPagination ( + baseUrl: string, + handler: ActivityPubCollectionPaginationHandler, + page?: any, + size = ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE +) { + if (!page || !validator.isInt(page)) { + // We just display the first page URL, we only need the total items + const result = await handler(0, 1) + + return { + id: baseUrl, + type: 'OrderedCollectionPage', + totalItems: result.total, + first: result.data.length === 0 + ? undefined + : baseUrl + '?page=1' + } + } + + const { start, count } = pageToStartAndCount(page, size) + const result = await handler(start, count) + + let next: string | undefined + let prev: string | undefined + + // Assert page is a number + page = parseInt(page, 10) + + // There are more results + if (result.total > page * size) { + next = baseUrl + '?page=' + (page + 1) + } + + if (page > 1) { + prev = baseUrl + '?page=' + (page - 1) + } + + return { + id: baseUrl + '?page=' + page, + type: 'OrderedCollectionPage', + prev, + next, + partOf: baseUrl, + orderedItems: result.data, + totalItems: result.total + } +} + +// --------------------------------------------------------------------------- + +export { + activityPubCollectionPagination +} diff --git a/server/lib/activitypub/context.ts b/server/lib/activitypub/context.ts new file mode 100644 index 000000000..71f08da80 --- /dev/null +++ b/server/lib/activitypub/context.ts @@ -0,0 +1,137 @@ +import { ContextType } from '@shared/models' + +function getContextData (type: ContextType) { + const context: any[] = [ + 'https://www.w3.org/ns/activitystreams', + 'https://w3id.org/security/v1', + { + RsaSignature2017: 'https://w3id.org/security#RsaSignature2017' + } + ] + + if (type !== 'View' && type !== 'Announce') { + const additional = { + pt: 'https://joinpeertube.org/ns#', + sc: 'http://schema.org#' + } + + if (type === 'CacheFile') { + Object.assign(additional, { + expires: 'sc:expires', + CacheFile: 'pt:CacheFile' + }) + } else { + Object.assign(additional, { + Hashtag: 'as:Hashtag', + uuid: 'sc:identifier', + category: 'sc:category', + licence: 'sc:license', + subtitleLanguage: 'sc:subtitleLanguage', + sensitive: 'as:sensitive', + language: 'sc:inLanguage', + + // TODO: remove in a few versions, introduced in 4.2 + icons: 'as:icon', + + isLiveBroadcast: 'sc:isLiveBroadcast', + liveSaveReplay: { + '@type': 'sc:Boolean', + '@id': 'pt:liveSaveReplay' + }, + permanentLive: { + '@type': 'sc:Boolean', + '@id': 'pt:permanentLive' + }, + latencyMode: { + '@type': 'sc:Number', + '@id': 'pt:latencyMode' + }, + + Infohash: 'pt:Infohash', + Playlist: 'pt:Playlist', + PlaylistElement: 'pt:PlaylistElement', + + originallyPublishedAt: 'sc:datePublished', + views: { + '@type': 'sc:Number', + '@id': 'pt:views' + }, + state: { + '@type': 'sc:Number', + '@id': 'pt:state' + }, + size: { + '@type': 'sc:Number', + '@id': 'pt:size' + }, + fps: { + '@type': 'sc:Number', + '@id': 'pt:fps' + }, + startTimestamp: { + '@type': 'sc:Number', + '@id': 'pt:startTimestamp' + }, + stopTimestamp: { + '@type': 'sc:Number', + '@id': 'pt:stopTimestamp' + }, + position: { + '@type': 'sc:Number', + '@id': 'pt:position' + }, + commentsEnabled: { + '@type': 'sc:Boolean', + '@id': 'pt:commentsEnabled' + }, + downloadEnabled: { + '@type': 'sc:Boolean', + '@id': 'pt:downloadEnabled' + }, + waitTranscoding: { + '@type': 'sc:Boolean', + '@id': 'pt:waitTranscoding' + }, + support: { + '@type': 'sc:Text', + '@id': 'pt:support' + }, + likes: { + '@id': 'as:likes', + '@type': '@id' + }, + dislikes: { + '@id': 'as:dislikes', + '@type': '@id' + }, + playlists: { + '@id': 'pt:playlists', + '@type': '@id' + }, + shares: { + '@id': 'as:shares', + '@type': '@id' + }, + comments: { + '@id': 'as:comments', + '@type': '@id' + } + }) + } + + context.push(additional) + } + + return { + '@context': context + } +} + +function activityPubContextify (data: T, type: ContextType = 'All') { + return Object.assign({}, data, getContextData(type)) +} + +export { + getContextData, + activityPubContextify +} diff --git a/server/lib/activitypub/playlists/create-update.ts b/server/lib/activitypub/playlists/create-update.ts index ef572c803..c28700be6 100644 --- a/server/lib/activitypub/playlists/create-update.ts +++ b/server/lib/activitypub/playlists/create-update.ts @@ -1,5 +1,4 @@ import { map } from 'bluebird' -import { getAPId } from '@server/helpers/activitypub' import { isArray } from '@server/helpers/custom-validators/misc' import { logger, loggerTagsFactory } from '@server/helpers/logger' import { CRAWL_REQUEST_CONCURRENCY } from '@server/initializers/constants' @@ -9,8 +8,9 @@ import { VideoPlaylistModel } from '@server/models/video/video-playlist' import { VideoPlaylistElementModel } from '@server/models/video/video-playlist-element' import { FilteredModelAttributes } from '@server/types' import { MThumbnail, MVideoPlaylist, MVideoPlaylistFull, MVideoPlaylistVideosLength } from '@server/types/models' -import { AttributesOnly } from '@shared/typescript-utils' import { PlaylistObject } from '@shared/models' +import { AttributesOnly } from '@shared/typescript-utils' +import { getAPId } from '../activity' import { getOrCreateAPActor } from '../actors' import { crawlCollectionPage } from '../crawl' import { getOrCreateAPVideo } from '../videos' diff --git a/server/lib/activitypub/playlists/get.ts b/server/lib/activitypub/playlists/get.ts index be8456b19..bfaf52cc9 100644 --- a/server/lib/activitypub/playlists/get.ts +++ b/server/lib/activitypub/playlists/get.ts @@ -1,7 +1,7 @@ -import { getAPId } from '@server/helpers/activitypub' import { VideoPlaylistModel } from '@server/models/video/video-playlist' import { MVideoPlaylistFullSummary } from '@server/types/models' import { APObject } from '@shared/models' +import { getAPId } from '../activity' import { createOrUpdateVideoPlaylist } from './create-update' import { scheduleRefreshIfNeeded } from './refresh' import { fetchRemoteVideoPlaylist } from './shared' diff --git a/server/lib/activitypub/playlists/shared/url-to-object.ts b/server/lib/activitypub/playlists/shared/url-to-object.ts index ec8c01255..f895db587 100644 --- a/server/lib/activitypub/playlists/shared/url-to-object.ts +++ b/server/lib/activitypub/playlists/shared/url-to-object.ts @@ -1,9 +1,9 @@ import { isArray } from 'lodash' -import { checkUrlsSameHost } from '@server/helpers/activitypub' import { isPlaylistElementObjectValid, isPlaylistObjectValid } from '@server/helpers/custom-validators/activitypub/playlist' import { logger, loggerTagsFactory } from '@server/helpers/logger' import { doJSONRequest } from '@server/helpers/requests' import { PlaylistElementObject, PlaylistObject } from '@shared/models' +import { checkUrlsSameHost } from '../../url' async function fetchRemoteVideoPlaylist (playlistUrl: string): Promise<{ statusCode: number, playlistObject: PlaylistObject }> { const lTags = loggerTagsFactory('ap', 'video-playlist', playlistUrl) diff --git a/server/lib/activitypub/process/process-announce.ts b/server/lib/activitypub/process/process-announce.ts index 200f8ce11..9cc87ee27 100644 --- a/server/lib/activitypub/process/process-announce.ts +++ b/server/lib/activitypub/process/process-announce.ts @@ -1,14 +1,14 @@ +import { getAPId } from '@server/lib/activitypub/activity' import { ActivityAnnounce } from '../../../../shared/models/activitypub' import { retryTransactionWrapper } from '../../../helpers/database-utils' +import { logger } from '../../../helpers/logger' import { sequelizeTypescript } from '../../../initializers/database' import { VideoShareModel } from '../../../models/video/video-share' -import { forwardVideoRelatedActivity } from '../send/shared/send-utils' -import { getOrCreateAPVideo } from '../videos' -import { Notifier } from '../../notifier' -import { logger } from '../../../helpers/logger' import { APProcessorOptions } from '../../../types/activitypub-processor.model' import { MActorSignature, MVideoAccountLightBlacklistAllFiles } from '../../../types/models' -import { getAPId } from '@server/helpers/activitypub' +import { Notifier } from '../../notifier' +import { forwardVideoRelatedActivity } from '../send/shared/send-utils' +import { getOrCreateAPVideo } from '../videos' async function processAnnounceActivity (options: APProcessorOptions) { const { activity, byActor: actorAnnouncer } = options diff --git a/server/lib/activitypub/process/process-flag.ts b/server/lib/activitypub/process/process-flag.ts index a15d07a62..10f58ef27 100644 --- a/server/lib/activitypub/process/process-flag.ts +++ b/server/lib/activitypub/process/process-flag.ts @@ -4,10 +4,10 @@ import { VideoModel } from '@server/models/video/video' import { VideoCommentModel } from '@server/models/video/video-comment' import { abusePredefinedReasonsMap } from '@shared/core-utils/abuse' import { AbuseObject, AbuseState, ActivityCreate, ActivityFlag } from '@shared/models' -import { getAPId } from '../../../helpers/activitypub' import { retryTransactionWrapper } from '../../../helpers/database-utils' import { logger } from '../../../helpers/logger' import { sequelizeTypescript } from '../../../initializers/database' +import { getAPId } from '../../../lib/activitypub/activity' import { APProcessorOptions } from '../../../types/activitypub-processor.model' import { MAccountDefault, MActorSignature, MCommentOwnerVideo } from '../../../types/models' diff --git a/server/lib/activitypub/process/process-follow.ts b/server/lib/activitypub/process/process-follow.ts index e44590ffc..93df7e191 100644 --- a/server/lib/activitypub/process/process-follow.ts +++ b/server/lib/activitypub/process/process-follow.ts @@ -1,10 +1,10 @@ import { getServerActor } from '@server/models/application/application' import { ActivityFollow } from '../../../../shared/models/activitypub' -import { getAPId } from '../../../helpers/activitypub' import { retryTransactionWrapper } from '../../../helpers/database-utils' import { logger } from '../../../helpers/logger' import { CONFIG } from '../../../initializers/config' import { sequelizeTypescript } from '../../../initializers/database' +import { getAPId } from '../../../lib/activitypub/activity' import { ActorModel } from '../../../models/actor/actor' import { ActorFollowModel } from '../../../models/actor/actor-follow' import { APProcessorOptions } from '../../../types/activitypub-processor.model' diff --git a/server/lib/activitypub/process/process-like.ts b/server/lib/activitypub/process/process-like.ts index 93afb5edf..1aee756d8 100644 --- a/server/lib/activitypub/process/process-like.ts +++ b/server/lib/activitypub/process/process-like.ts @@ -1,8 +1,8 @@ import { VideoModel } from '@server/models/video/video' import { ActivityLike } from '../../../../shared/models/activitypub' -import { getAPId } from '../../../helpers/activitypub' import { retryTransactionWrapper } from '../../../helpers/database-utils' import { sequelizeTypescript } from '../../../initializers/database' +import { getAPId } from '../../../lib/activitypub/activity' import { AccountVideoRateModel } from '../../../models/account/account-video-rate' import { APProcessorOptions } from '../../../types/activitypub-processor.model' import { MActorSignature } from '../../../types/models' diff --git a/server/lib/activitypub/process/process.ts b/server/lib/activitypub/process/process.ts index 02a23d098..2bc3dce03 100644 --- a/server/lib/activitypub/process/process.ts +++ b/server/lib/activitypub/process/process.ts @@ -1,10 +1,11 @@ import { StatsManager } from '@server/lib/stat-manager' import { Activity, ActivityType } from '../../../../shared/models/activitypub' -import { checkUrlsSameHost, getAPId } from '../../../helpers/activitypub' import { logger } from '../../../helpers/logger' import { APProcessorOptions } from '../../../types/activitypub-processor.model' import { MActorDefault, MActorSignature } from '../../../types/models' +import { getAPId } from '../activity' import { getOrCreateAPActor } from '../actors' +import { checkUrlsSameHost } from '../url' import { processAcceptActivity } from './process-accept' import { processAnnounceActivity } from './process-announce' import { processCreateActivity } from './process-create' diff --git a/server/lib/activitypub/share.ts b/server/lib/activitypub/share.ts index b18761174..0fefcbbc5 100644 --- a/server/lib/activitypub/share.ts +++ b/server/lib/activitypub/share.ts @@ -1,15 +1,15 @@ import { map } from 'bluebird' import { Transaction } from 'sequelize' import { getServerActor } from '@server/models/application/application' -import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub' import { logger, loggerTagsFactory } from '../../helpers/logger' import { doJSONRequest } from '../../helpers/requests' import { CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants' import { VideoShareModel } from '../../models/video/video-share' import { MChannelActorLight, MVideo, MVideoAccountLight, MVideoId } from '../../types/models/video' +import { getAPId } from './activity' import { getOrCreateAPActor } from './actors' import { sendUndoAnnounce, sendVideoAnnounce } from './send' -import { getLocalVideoAnnounceActivityPubUrl } from './url' +import { checkUrlsSameHost, getLocalVideoAnnounceActivityPubUrl } from './url' const lTags = loggerTagsFactory('share') diff --git a/server/lib/activitypub/url.ts b/server/lib/activitypub/url.ts index 338398f2b..50be4fac9 100644 --- a/server/lib/activitypub/url.ts +++ b/server/lib/activitypub/url.ts @@ -1,4 +1,4 @@ -import { WEBSERVER } from '../../initializers/constants' +import { REMOTE_SCHEME, WEBSERVER } from '../../initializers/constants' import { MAbuseFull, MAbuseId, @@ -10,7 +10,8 @@ import { MVideoId, MVideoPlaylistElement, MVideoUrl, - MVideoUUID + MVideoUUID, + MVideoWithHost } from '../../types/models' import { MVideoFileVideoUUID } from '../../types/models/video/video-file' import { MVideoPlaylist, MVideoPlaylistUUID } from '../../types/models/video/video-playlist' @@ -121,6 +122,27 @@ function getAbuseTargetUrl (abuse: MAbuseFull) { abuse.FlaggedAccount.Actor.url } +// --------------------------------------------------------------------------- + +function buildRemoteVideoBaseUrl (video: MVideoWithHost, path: string, scheme?: string) { + if (!scheme) scheme = REMOTE_SCHEME.HTTP + + const host = video.VideoChannel.Actor.Server.host + + return scheme + '://' + host + path +} + +// --------------------------------------------------------------------------- + +function checkUrlsSameHost (url1: string, url2: string) { + const idHost = new URL(url1).host + const actorHost = new URL(url2).host + + return idHost && actorHost && idHost.toLowerCase() === actorHost.toLowerCase() +} + +// --------------------------------------------------------------------------- + export { getLocalVideoActivityPubUrl, getLocalVideoPlaylistActivityPubUrl, @@ -145,5 +167,8 @@ export { getLocalVideoCommentsActivityPubUrl, getLocalVideoLikesActivityPubUrl, getLocalVideoDislikesActivityPubUrl, - getAbuseTargetUrl + + getAbuseTargetUrl, + checkUrlsSameHost, + buildRemoteVideoBaseUrl } diff --git a/server/lib/activitypub/video-comments.ts b/server/lib/activitypub/video-comments.ts index 2c7da3e00..911c7cd30 100644 --- a/server/lib/activitypub/video-comments.ts +++ b/server/lib/activitypub/video-comments.ts @@ -1,5 +1,4 @@ import { map } from 'bluebird' -import { checkUrlsSameHost } from '../../helpers/activitypub' import { sanitizeAndCheckVideoCommentObject } from '../../helpers/custom-validators/activitypub/video-comments' import { logger } from '../../helpers/logger' import { doJSONRequest } from '../../helpers/requests' @@ -7,6 +6,7 @@ import { ACTIVITY_PUB, CRAWL_REQUEST_CONCURRENCY } from '../../initializers/cons import { VideoCommentModel } from '../../models/video/video-comment' import { MCommentOwner, MCommentOwnerVideo, MVideoAccountLightBlacklistAllFiles } from '../../types/models/video' import { getOrCreateAPActor } from './actors' +import { checkUrlsSameHost } from './url' import { getOrCreateAPVideo } from './videos' type ResolveThreadParams = { diff --git a/server/lib/activitypub/videos/get.ts b/server/lib/activitypub/videos/get.ts index b13c6ceeb..d7500c71a 100644 --- a/server/lib/activitypub/videos/get.ts +++ b/server/lib/activitypub/videos/get.ts @@ -1,9 +1,9 @@ -import { getAPId } from '@server/helpers/activitypub' import { retryTransactionWrapper } from '@server/helpers/database-utils' import { JobQueue } from '@server/lib/job-queue' import { loadVideoByUrl, VideoLoadByUrlType } from '@server/lib/model-loaders' import { MVideoAccountLightBlacklistAllFiles, MVideoImmutable, MVideoThumbnail } from '@server/types/models' import { APObject } from '@shared/models' +import { getAPId } from '../activity' import { refreshVideoIfNeeded } from './refresh' import { APVideoCreator, fetchRemoteVideo, SyncParam, syncVideoExternalAttributes } from './shared' diff --git a/server/lib/activitypub/videos/shared/abstract-builder.ts b/server/lib/activitypub/videos/shared/abstract-builder.ts index 788223b48..f299ba4fd 100644 --- a/server/lib/activitypub/videos/shared/abstract-builder.ts +++ b/server/lib/activitypub/videos/shared/abstract-builder.ts @@ -1,5 +1,4 @@ import { Transaction } from 'sequelize/types' -import { checkUrlsSameHost } from '@server/helpers/activitypub' import { deleteAllModels, filterNonExistingModels } from '@server/helpers/database-utils' import { logger, LoggerTagsFn } from '@server/helpers/logger' import { updatePlaceholderThumbnail, updateVideoMiniatureFromUrl } from '@server/lib/thumbnail' @@ -11,6 +10,7 @@ import { VideoStreamingPlaylistModel } from '@server/models/video/video-streamin import { MStreamingPlaylistFilesVideo, MThumbnail, MVideoCaption, MVideoFile, MVideoFullLight, MVideoThumbnail } from '@server/types/models' import { ActivityTagObject, ThumbnailType, VideoObject, VideoStreamingPlaylistType } from '@shared/models' import { getOrCreateAPActor } from '../../actors' +import { checkUrlsSameHost } from '../../url' import { getCaptionAttributesFromObject, getFileAttributesFromUrl, diff --git a/server/lib/activitypub/videos/shared/trackers.ts b/server/lib/activitypub/videos/shared/trackers.ts index 1c5fc4f84..2418f45c2 100644 --- a/server/lib/activitypub/videos/shared/trackers.ts +++ b/server/lib/activitypub/videos/shared/trackers.ts @@ -1,11 +1,11 @@ import { Transaction } from 'sequelize/types' -import { buildRemoteVideoBaseUrl } from '@server/helpers/activitypub' import { isAPVideoTrackerUrlObject } from '@server/helpers/custom-validators/activitypub/videos' import { isArray } from '@server/helpers/custom-validators/misc' import { REMOTE_SCHEME } from '@server/initializers/constants' import { TrackerModel } from '@server/models/server/tracker' import { MVideo, MVideoWithHost } from '@server/types/models' import { ActivityTrackerUrlObject, VideoObject } from '@shared/models' +import { buildRemoteVideoBaseUrl } from '../../url' function getTrackerUrls (object: VideoObject, video: MVideoWithHost) { let wsFound = false diff --git a/server/lib/activitypub/videos/shared/url-to-object.ts b/server/lib/activitypub/videos/shared/url-to-object.ts index dba3e9480..5b7007530 100644 --- a/server/lib/activitypub/videos/shared/url-to-object.ts +++ b/server/lib/activitypub/videos/shared/url-to-object.ts @@ -1,8 +1,8 @@ -import { checkUrlsSameHost } from '@server/helpers/activitypub' import { sanitizeAndCheckVideoTorrentObject } from '@server/helpers/custom-validators/activitypub/videos' import { logger, loggerTagsFactory } from '@server/helpers/logger' import { doJSONRequest } from '@server/helpers/requests' import { VideoObject } from '@shared/models' +import { checkUrlsSameHost } from '../../url' const lTags = loggerTagsFactory('ap', 'video') diff --git a/server/lib/job-queue/handlers/activitypub-cleaner.ts b/server/lib/job-queue/handlers/activitypub-cleaner.ts index 07dd908cd..123aeac03 100644 --- a/server/lib/job-queue/handlers/activitypub-cleaner.ts +++ b/server/lib/job-queue/handlers/activitypub-cleaner.ts @@ -1,6 +1,5 @@ import { map } from 'bluebird' import { Job } from 'bull' -import { checkUrlsSameHost } from '@server/helpers/activitypub' import { isAnnounceActivityValid, isDislikeActivityValid, @@ -9,6 +8,7 @@ import { import { sanitizeAndCheckVideoCommentObject } from '@server/helpers/custom-validators/activitypub/video-comments' import { doJSONRequest, PeerTubeRequestError } from '@server/helpers/requests' import { AP_CLEANER } from '@server/initializers/constants' +import { checkUrlsSameHost } from '@server/lib/activitypub/url' import { Redis } from '@server/lib/redis' import { VideoModel } from '@server/models/video/video' import { VideoCommentModel } from '@server/models/video/video-comment' diff --git a/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts b/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts index 37e7c1fad..2a03325b7 100644 --- a/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts +++ b/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts @@ -1,7 +1,7 @@ import { buildDigest } from '@server/helpers/peertube-crypto' +import { buildSignedActivity } from '@server/lib/activitypub/activity' import { getServerActor } from '@server/models/application/application' import { ContextType } from '@shared/models/activitypub/context' -import { buildSignedActivity } from '../../../../helpers/activitypub' import { ACTIVITY_PUB, HTTP_SIGNATURE } from '../../../../initializers/constants' import { ActorModel } from '../../../../models/actor/actor' import { MActor } from '../../../../types/models' diff --git a/server/middlewares/activitypub.ts b/server/middlewares/activitypub.ts index 86d3c1d6c..2a2d86a24 100644 --- a/server/middlewares/activitypub.ts +++ b/server/middlewares/activitypub.ts @@ -1,6 +1,6 @@ import { NextFunction, Request, Response } from 'express' -import { getAPId } from '@server/helpers/activitypub' import { isActorDeleteActivityValid } from '@server/helpers/custom-validators/activitypub/actor' +import { getAPId } from '@server/lib/activitypub/activity' import { ActivityDelete, ActivityPubSignature, HttpStatusCode } from '@shared/models' import { logger } from '../helpers/logger' import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../helpers/peertube-crypto' diff --git a/server/models/actor/actor.ts b/server/models/actor/actor.ts index 08cb2fd24..fad2070ea 100644 --- a/server/models/actor/actor.ts +++ b/server/models/actor/actor.ts @@ -16,12 +16,12 @@ import { Table, UpdatedAt } from 'sequelize-typescript' +import { activityPubContextify } from '@server/lib/activitypub/context' import { getBiggestActorImage } from '@server/lib/actor-image' import { ModelCache } from '@server/models/model-cache' import { getLowercaseExtension } from '@shared/core-utils' import { ActivityIconObject, ActivityPubActorType, ActorImageType } from '@shared/models' import { AttributesOnly } from '@shared/typescript-utils' -import { activityPubContextify } from '../../helpers/activitypub' import { isActorFollowersCountValid, isActorFollowingCountValid, diff --git a/server/models/video/video-file.ts b/server/models/video/video-file.ts index fae76c6f2..4aaee1ffa 100644 --- a/server/models/video/video-file.ts +++ b/server/models/video/video-file.ts @@ -19,9 +19,9 @@ import { UpdatedAt } from 'sequelize-typescript' import validator from 'validator' -import { buildRemoteVideoBaseUrl } from '@server/helpers/activitypub' import { logger } from '@server/helpers/logger' import { extractVideo } from '@server/helpers/video' +import { buildRemoteVideoBaseUrl } from '@server/lib/activitypub/url' import { getHLSPublicFileUrl, getWebTorrentPublicFileUrl } from '@server/lib/object-storage' import { getFSTorrentFilePath } from '@server/lib/paths' import { isStreamingPlaylist, MStreamingPlaylistVideo, MVideo, MVideoWithHost } from '@server/types/models' diff --git a/server/models/video/video-playlist.ts b/server/models/video/video-playlist.ts index ae5e237ec..8fb3d5f15 100644 --- a/server/models/video/video-playlist.ts +++ b/server/models/video/video-playlist.ts @@ -17,6 +17,7 @@ import { Table, UpdatedAt } from 'sequelize-typescript' +import { activityPubCollectionPagination } from '@server/lib/activitypub/collection' import { MAccountId, MChannelId } from '@server/types/models' import { buildPlaylistEmbedPath, buildPlaylistWatchPath, pick } from '@shared/core-utils' import { buildUUID, uuidToShort } from '@shared/extra-utils' @@ -26,7 +27,6 @@ import { PlaylistObject } from '../../../shared/models/activitypub/objects/playl import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model' import { VideoPlaylistType } from '../../../shared/models/videos/playlist/video-playlist-type.model' import { VideoPlaylist } from '../../../shared/models/videos/playlist/video-playlist.model' -import { activityPubCollectionPagination } from '../../helpers/activitypub' import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' import { isVideoPlaylistDescriptionValid, diff --git a/server/tests/api/activitypub/helpers.ts b/server/tests/api/activitypub/helpers.ts index 25e1d9823..e516cf49e 100644 --- a/server/tests/api/activitypub/helpers.ts +++ b/server/tests/api/activitypub/helpers.ts @@ -5,8 +5,8 @@ import { expect } from 'chai' import { cloneDeep } from 'lodash' import { buildRequestStub } from '@server/tests/shared' import { buildAbsoluteFixturePath } from '@shared/core-utils' -import { buildSignedActivity } from '../../../helpers/activitypub' import { isHTTPSignatureVerified, isJsonLDSignatureVerified, parseHTTPSignature } from '../../../helpers/peertube-crypto' +import { buildSignedActivity } from '../../../lib/activitypub/activity' describe('Test activity pub helpers', function () { describe('When checking the Linked Signature', function () { diff --git a/server/tests/api/activitypub/security.ts b/server/tests/api/activitypub/security.ts index c4cb5ea0d..da9880d7d 100644 --- a/server/tests/api/activitypub/security.ts +++ b/server/tests/api/activitypub/security.ts @@ -2,9 +2,10 @@ import 'mocha' import * as chai from 'chai' -import { activityPubContextify, buildSignedActivity } from '@server/helpers/activitypub' import { buildDigest } from '@server/helpers/peertube-crypto' import { HTTP_SIGNATURE } from '@server/initializers/constants' +import { buildSignedActivity } from '@server/lib/activitypub/activity' +import { activityPubContextify } from '@server/lib/activitypub/context' import { buildGlobalHeaders } from '@server/lib/job-queue/handlers/utils/activitypub-http-utils' import { makeFollowRequest, makePOSTAPRequest } from '@server/tests/shared' import { buildAbsoluteFixturePath, wait } from '@shared/core-utils' diff --git a/server/tests/shared/requests.ts b/server/tests/shared/requests.ts index 7f1acc0e1..d7aedf82f 100644 --- a/server/tests/shared/requests.ts +++ b/server/tests/shared/requests.ts @@ -1,7 +1,7 @@ -import { activityPubContextify } from '@server/helpers/activitypub' import { buildDigest } from '@server/helpers/peertube-crypto' import { doRequest } from '@server/helpers/requests' import { ACTIVITY_PUB, HTTP_SIGNATURE } from '@server/initializers/constants' +import { activityPubContextify } from '@server/lib/activitypub/context' export function makePOSTAPRequest (url: string, body: any, httpSignature: any, headers: any) { const options = { -- cgit v1.2.3