From 5224c394b3bbac6ec1543e41fa0ec6db436e84fa Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 9 Aug 2019 08:17:16 +0200 Subject: [PATCH] Stronger actor association typing in AP functions --- server/controllers/activitypub/inbox.ts | 3 +- server/lib/activitypub/actor.ts | 2 +- server/lib/activitypub/audience.ts | 3 +- server/lib/activitypub/playlist.ts | 5 ++- .../lib/activitypub/process/process-accept.ts | 3 +- .../activitypub/process/process-announce.ts | 4 +- .../lib/activitypub/process/process-create.ts | 8 ++-- .../lib/activitypub/process/process-delete.ts | 3 +- .../activitypub/process/process-dislike.ts | 4 +- .../lib/activitypub/process/process-flag.ts | 4 +- .../lib/activitypub/process/process-follow.ts | 16 ++++--- .../lib/activitypub/process/process-like.ts | 4 +- .../lib/activitypub/process/process-reject.ts | 4 +- .../lib/activitypub/process/process-undo.ts | 11 ++--- .../lib/activitypub/process/process-update.ts | 7 +-- .../lib/activitypub/process/process-view.ts | 4 +- server/lib/activitypub/process/process.ts | 5 ++- server/lib/activitypub/send/send-accept.ts | 8 ++-- server/lib/activitypub/send/send-announce.ts | 17 ++++--- server/lib/activitypub/send/send-follow.ts | 4 +- server/lib/activitypub/send/send-reject.ts | 3 +- server/lib/activitypub/send/utils.ts | 45 ++++++++++--------- server/lib/activitypub/url.ts | 18 ++++---- server/lib/activitypub/videos.ts | 9 ++-- server/typings/activitypub-processor.model.ts | 3 +- server/typings/express.ts | 3 +- server/typings/models/actor-follow.ts | 8 ++++ server/typings/models/actor.ts | 22 +++++++++ server/typings/models/index.d.ts | 1 + server/typings/models/video-share.ts | 3 ++ server/typings/utils.ts | 3 ++ 31 files changed, 147 insertions(+), 90 deletions(-) create mode 100644 server/typings/models/actor-follow.ts create mode 100644 server/typings/models/actor.ts create mode 100644 server/typings/models/index.d.ts create mode 100644 server/typings/models/video-share.ts create mode 100644 server/typings/utils.ts diff --git a/server/controllers/activitypub/inbox.ts b/server/controllers/activitypub/inbox.ts index 38d5c51df..2d3eef222 100644 --- a/server/controllers/activitypub/inbox.ts +++ b/server/controllers/activitypub/inbox.ts @@ -7,6 +7,7 @@ import { asyncMiddleware, checkSignature, localAccountValidator, localVideoChann import { activityPubValidator } from '../../middlewares/validators/activitypub/activity' import { queue } from 'async' import { ActorModel } from '../../models/activitypub/actor' +import { SignatureActorModel } from '../../typings/models' const inboxRouter = express.Router() @@ -40,7 +41,7 @@ export { // --------------------------------------------------------------------------- -const inboxQueue = queue<{ activities: Activity[], signatureActor?: ActorModel, inboxActor?: ActorModel }, Error>((task, cb) => { +const inboxQueue = queue<{ activities: Activity[], signatureActor?: SignatureActorModel, inboxActor?: ActorModel }, Error>((task, cb) => { const options = { signatureActor: task.signatureActor, inboxActor: task.inboxActor } processActivities(task.activities, options) diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index 0e6596f10..04296864b 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts @@ -195,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) { diff --git a/server/lib/activitypub/audience.ts b/server/lib/activitypub/audience.ts index 771a01366..0e3d78590 100644 --- a/server/lib/activitypub/audience.ts +++ b/server/lib/activitypub/audience.ts @@ -5,6 +5,7 @@ import { ActorModel } from '../../models/activitypub/actor' import { VideoModel } from '../../models/video/video' import { VideoCommentModel } from '../../models/video/video-comment' import { VideoShareModel } from '../../models/video/video-share' +import { ActorModelOnly } from '../../typings/models' function getRemoteVideoAudience (video: VideoModel, actorsInvolvedInVideo: ActorModel[]): ActivityAudience { return { @@ -60,7 +61,7 @@ async function getActorsInvolvedInVideo (video: VideoModel, t: Transaction) { return actors } -function getAudience (actorSender: ActorModel, isPublic = true) { +function getAudience (actorSender: ActorModelOnly, isPublic = true) { return buildAudience([ actorSender.followersUrl ], isPublic) } diff --git a/server/lib/activitypub/playlist.ts b/server/lib/activitypub/playlist.ts index f569d881c..c2e2a3283 100644 --- a/server/lib/activitypub/playlist.ts +++ b/server/lib/activitypub/playlist.ts @@ -18,8 +18,9 @@ import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/vid import { sequelizeTypescript } from '../../initializers/database' import { createPlaylistMiniatureFromUrl } from '../thumbnail' import { FilteredModelAttributes } from '../../typings/sequelize' +import { AccountModelId } from '../../typings/models' -function playlistObjectToDBAttributes (playlistObject: PlaylistObject, byAccount: AccountModel, to: string[]) { +function playlistObjectToDBAttributes (playlistObject: PlaylistObject, byAccount: AccountModelId, to: string[]) { const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPlaylistPrivacy.PUBLIC : VideoPlaylistPrivacy.UNLISTED return { @@ -74,7 +75,7 @@ async function createAccountPlaylists (playlistUrls: string[], account: AccountM }, { concurrency: CRAWL_REQUEST_CONCURRENCY }) } -async function createOrUpdateVideoPlaylist (playlistObject: PlaylistObject, byAccount: AccountModel, to: string[]) { +async function createOrUpdateVideoPlaylist (playlistObject: PlaylistObject, byAccount: AccountModelId, to: string[]) { const playlistAttributes = playlistObjectToDBAttributes(playlistObject, byAccount, to) if (isArray(playlistObject.attributedTo) && playlistObject.attributedTo.length === 1) { diff --git a/server/lib/activitypub/process/process-accept.ts b/server/lib/activitypub/process/process-accept.ts index 72bb1975e..cf27e6c32 100644 --- a/server/lib/activitypub/process/process-accept.ts +++ b/server/lib/activitypub/process/process-accept.ts @@ -3,6 +3,7 @@ import { ActorModel } from '../../../models/activitypub/actor' import { ActorFollowModel } from '../../../models/activitypub/actor-follow' import { addFetchOutboxJob } from '../actor' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' +import { SignatureActorModel } from '../../../typings/models' async function processAcceptActivity (options: APProcessorOptions) { const { byActor: targetActor, inboxActor } = options @@ -19,7 +20,7 @@ export { // --------------------------------------------------------------------------- -async function processAccept (actor: ActorModel, targetActor: ActorModel) { +async function processAccept (actor: ActorModel, targetActor: SignatureActorModel) { const follow = await ActorFollowModel.loadByActorAndTarget(actor.id, targetActor.id) if (!follow) throw new Error('Cannot find associated follow.') diff --git a/server/lib/activitypub/process/process-announce.ts b/server/lib/activitypub/process/process-announce.ts index 7a59bb84d..b3cdc4441 100644 --- a/server/lib/activitypub/process/process-announce.ts +++ b/server/lib/activitypub/process/process-announce.ts @@ -1,7 +1,6 @@ import { ActivityAnnounce } from '../../../../shared/models/activitypub' import { retryTransactionWrapper } from '../../../helpers/database-utils' import { sequelizeTypescript } from '../../../initializers' -import { ActorModel } from '../../../models/activitypub/actor' import { VideoShareModel } from '../../../models/video/video-share' import { forwardVideoRelatedActivity } from '../send/utils' import { getOrCreateVideoAndAccountAndChannel } from '../videos' @@ -9,6 +8,7 @@ import { Notifier } from '../../notifier' import { VideoModel } from '../../../models/video/video' import { logger } from '../../../helpers/logger' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' +import { SignatureActorModel } from '../../../typings/models' async function processAnnounceActivity (options: APProcessorOptions) { const { activity, byActor: actorAnnouncer } = options @@ -26,7 +26,7 @@ export { // --------------------------------------------------------------------------- -async function processVideoShare (actorAnnouncer: ActorModel, activity: ActivityAnnounce, notify: boolean) { +async function processVideoShare (actorAnnouncer: SignatureActorModel, activity: ActivityAnnounce, notify: boolean) { const objectUri = typeof activity.object === 'string' ? activity.object : activity.object.id let video: VideoModel diff --git a/server/lib/activitypub/process/process-create.ts b/server/lib/activitypub/process/process-create.ts index b81021163..6815c6997 100644 --- a/server/lib/activitypub/process/process-create.ts +++ b/server/lib/activitypub/process/process-create.ts @@ -3,7 +3,6 @@ import { VideoCommentObject } from '../../../../shared/models/activitypub/object import { retryTransactionWrapper } from '../../../helpers/database-utils' import { logger } from '../../../helpers/logger' import { sequelizeTypescript } from '../../../initializers' -import { ActorModel } from '../../../models/activitypub/actor' import { resolveThread } from '../video-comments' import { getOrCreateVideoAndAccountAndChannel } from '../videos' import { forwardVideoRelatedActivity } from '../send/utils' @@ -14,6 +13,7 @@ import { createOrUpdateVideoPlaylist } from '../playlist' import { VideoModel } from '../../../models/video/video' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' import { VideoCommentModel } from '../../../models/video/video-comment' +import { SignatureActorModel } from '../../../typings/models' async function processCreateActivity (options: APProcessorOptions) { const { activity, byActor } = options @@ -61,7 +61,7 @@ async function processCreateVideo (activity: ActivityCreate, notify: boolean) { return video } -async function processCreateCacheFile (activity: ActivityCreate, byActor: ActorModel) { +async function processCreateCacheFile (activity: ActivityCreate, byActor: SignatureActorModel) { const cacheFile = activity.object as CacheFileObject const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: cacheFile.object }) @@ -77,7 +77,7 @@ async function processCreateCacheFile (activity: ActivityCreate, byActor: ActorM } } -async function processCreateVideoComment (activity: ActivityCreate, byActor: ActorModel, notify: boolean) { +async function processCreateVideoComment (activity: ActivityCreate, byActor: SignatureActorModel, notify: boolean) { const commentObject = activity.object as VideoCommentObject const byAccount = byActor.Account @@ -110,7 +110,7 @@ async function processCreateVideoComment (activity: ActivityCreate, byActor: Act if (created && notify) Notifier.Instance.notifyOnNewComment(comment) } -async function processCreatePlaylist (activity: ActivityCreate, byActor: ActorModel) { +async function processCreatePlaylist (activity: ActivityCreate, byActor: SignatureActorModel) { const playlistObject = activity.object as PlaylistObject const byAccount = byActor.Account diff --git a/server/lib/activitypub/process/process-delete.ts b/server/lib/activitypub/process/process-delete.ts index 9fcfd9e3a..344d14322 100644 --- a/server/lib/activitypub/process/process-delete.ts +++ b/server/lib/activitypub/process/process-delete.ts @@ -10,6 +10,7 @@ import { VideoCommentModel } from '../../../models/video/video-comment' import { forwardVideoRelatedActivity } from '../send/utils' import { VideoPlaylistModel } from '../../../models/video/video-playlist' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' +import { SignatureActorModel } from '../../../typings/models' async function processDeleteActivity (options: APProcessorOptions) { const { activity, byActor } = options @@ -117,7 +118,7 @@ async function processDeleteVideoChannel (videoChannelToRemove: VideoChannelMode logger.info('Remote video channel %s removed.', videoChannelToRemove.Actor.url) } -function processDeleteVideoComment (byActor: ActorModel, videoComment: VideoCommentModel, activity: ActivityDelete) { +function processDeleteVideoComment (byActor: SignatureActorModel, videoComment: VideoCommentModel, activity: ActivityDelete) { logger.debug('Removing remote video comment "%s".', videoComment.url) return sequelizeTypescript.transaction(async t => { diff --git a/server/lib/activitypub/process/process-dislike.ts b/server/lib/activitypub/process/process-dislike.ts index a457e5f17..727fcfee0 100644 --- a/server/lib/activitypub/process/process-dislike.ts +++ b/server/lib/activitypub/process/process-dislike.ts @@ -3,11 +3,11 @@ import { DislikeObject } from '../../../../shared/models/activitypub/objects' import { retryTransactionWrapper } from '../../../helpers/database-utils' import { sequelizeTypescript } from '../../../initializers' import { AccountVideoRateModel } from '../../../models/account/account-video-rate' -import { ActorModel } from '../../../models/activitypub/actor' import { getOrCreateVideoAndAccountAndChannel } from '../videos' import { forwardVideoRelatedActivity } from '../send/utils' import { getVideoDislikeActivityPubUrl } from '../url' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' +import { SignatureActorModel } from '../../../typings/models' async function processDislikeActivity (options: APProcessorOptions) { const { activity, byActor } = options @@ -22,7 +22,7 @@ export { // --------------------------------------------------------------------------- -async function processDislike (activity: ActivityCreate | ActivityDislike, byActor: ActorModel) { +async function processDislike (activity: ActivityCreate | ActivityDislike, byActor: SignatureActorModel) { const dislikeObject = activity.type === 'Dislike' ? activity.object : (activity.object as DislikeObject).object const byAccount = byActor.Account diff --git a/server/lib/activitypub/process/process-flag.ts b/server/lib/activitypub/process/process-flag.ts index 532545e58..1f8a80c14 100644 --- a/server/lib/activitypub/process/process-flag.ts +++ b/server/lib/activitypub/process/process-flag.ts @@ -3,12 +3,12 @@ import { VideoAbuseObject } from '../../../../shared/models/activitypub/objects' import { retryTransactionWrapper } from '../../../helpers/database-utils' import { logger } from '../../../helpers/logger' import { sequelizeTypescript } from '../../../initializers' -import { ActorModel } from '../../../models/activitypub/actor' import { VideoAbuseModel } from '../../../models/video/video-abuse' import { getOrCreateVideoAndAccountAndChannel } from '../videos' import { Notifier } from '../../notifier' import { getAPId } from '../../../helpers/activitypub' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' +import { SignatureActorModel } from '../../../typings/models' async function processFlagActivity (options: APProcessorOptions) { const { activity, byActor } = options @@ -23,7 +23,7 @@ export { // --------------------------------------------------------------------------- -async function processCreateVideoAbuse (activity: ActivityCreate | ActivityFlag, byActor: ActorModel) { +async function processCreateVideoAbuse (activity: ActivityCreate | ActivityFlag, byActor: SignatureActorModel) { const flag = activity.type === 'Flag' ? activity : (activity.object as VideoAbuseObject) logger.debug('Reporting remote abuse for video %s.', getAPId(flag.object)) diff --git a/server/lib/activitypub/process/process-follow.ts b/server/lib/activitypub/process/process-follow.ts index 8fe9975f6..240aa5799 100644 --- a/server/lib/activitypub/process/process-follow.ts +++ b/server/lib/activitypub/process/process-follow.ts @@ -10,6 +10,8 @@ import { getAPId } from '../../../helpers/activitypub' import { getServerActor } from '../../../helpers/utils' import { CONFIG } from '../../../initializers/config' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' +import { SignatureActorModel } from '../../../typings/models' +import { ActorFollowModelLight } from '../../../typings/models/actor-follow' async function processFollowActivity (options: APProcessorOptions) { const { activity, byActor } = options @@ -26,7 +28,7 @@ export { // --------------------------------------------------------------------------- -async function processFollow (actor: ActorModel, targetActorURL: string) { +async function processFollow (byActor: SignatureActorModel, targetActorURL: string) { const { actorFollow, created, isFollowingInstance } = await sequelizeTypescript.transaction(async t => { const targetActor = await ActorModel.loadByUrlAndPopulateAccountAndChannel(targetActorURL, t) @@ -39,30 +41,30 @@ async function processFollow (actor: ActorModel, targetActorURL: string) { if (isFollowingInstance && CONFIG.FOLLOWERS.INSTANCE.ENABLED === false) { logger.info('Rejecting %s because instance followers are disabled.', targetActor.url) - await sendReject(actor, targetActor) + await sendReject(byActor, targetActor) return { actorFollow: undefined } } const [ actorFollow, created ] = await ActorFollowModel.findOrCreate({ where: { - actorId: actor.id, + actorId: byActor.id, targetActorId: targetActor.id }, defaults: { - actorId: actor.id, + actorId: byActor.id, targetActorId: targetActor.id, state: CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL ? 'pending' : 'accepted' }, transaction: t - }) + }) as [ ActorFollowModelLight, boolean ] if (actorFollow.state !== 'accepted' && CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL === false) { actorFollow.state = 'accepted' await actorFollow.save({ transaction: t }) } - actorFollow.ActorFollower = actor + actorFollow.ActorFollower = byActor actorFollow.ActorFollowing = targetActor // Target sends to actor he accepted the follow request @@ -79,5 +81,5 @@ async function processFollow (actor: ActorModel, targetActorURL: string) { else Notifier.Instance.notifyOfNewUserFollow(actorFollow) } - logger.info('Actor %s is followed by actor %s.', targetActorURL, actor.url) + logger.info('Actor %s is followed by actor %s.', targetActorURL, byActor.url) } diff --git a/server/lib/activitypub/process/process-like.ts b/server/lib/activitypub/process/process-like.ts index 706e63c41..cf559af72 100644 --- a/server/lib/activitypub/process/process-like.ts +++ b/server/lib/activitypub/process/process-like.ts @@ -2,12 +2,12 @@ import { ActivityLike } from '../../../../shared/models/activitypub' import { retryTransactionWrapper } from '../../../helpers/database-utils' import { sequelizeTypescript } from '../../../initializers' import { AccountVideoRateModel } from '../../../models/account/account-video-rate' -import { ActorModel } from '../../../models/activitypub/actor' import { forwardVideoRelatedActivity } from '../send/utils' import { getOrCreateVideoAndAccountAndChannel } from '../videos' import { getVideoLikeActivityPubUrl } from '../url' import { getAPId } from '../../../helpers/activitypub' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' +import { SignatureActorModel } from '../../../typings/models' async function processLikeActivity (options: APProcessorOptions) { const { activity, byActor } = options @@ -22,7 +22,7 @@ export { // --------------------------------------------------------------------------- -async function processLikeVideo (byActor: ActorModel, activity: ActivityLike) { +async function processLikeVideo (byActor: SignatureActorModel, activity: ActivityLike) { const videoUrl = getAPId(activity.object) const byAccount = byActor.Account diff --git a/server/lib/activitypub/process/process-reject.ts b/server/lib/activitypub/process/process-reject.ts index 9181906b4..22e311ceb 100644 --- a/server/lib/activitypub/process/process-reject.ts +++ b/server/lib/activitypub/process/process-reject.ts @@ -1,8 +1,8 @@ import { ActivityReject } from '../../../../shared/models/activitypub/activity' import { sequelizeTypescript } from '../../../initializers' -import { ActorModel } from '../../../models/activitypub/actor' import { ActorFollowModel } from '../../../models/activitypub/actor-follow' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' +import { ActorModelOnly } from '../../../typings/models' async function processRejectActivity (options: APProcessorOptions) { const { byActor: targetActor, inboxActor } = options @@ -19,7 +19,7 @@ export { // --------------------------------------------------------------------------- -async function processReject (follower: ActorModel, targetActor: ActorModel) { +async function processReject (follower: ActorModelOnly, targetActor: ActorModelOnly) { return sequelizeTypescript.transaction(async t => { const actorFollow = await ActorFollowModel.loadByActorAndTarget(follower.id, targetActor.id, t) diff --git a/server/lib/activitypub/process/process-undo.ts b/server/lib/activitypub/process/process-undo.ts index 7a0f90adf..c37ee38bb 100644 --- a/server/lib/activitypub/process/process-undo.ts +++ b/server/lib/activitypub/process/process-undo.ts @@ -11,6 +11,7 @@ import { getOrCreateVideoAndAccountAndChannel } from '../videos' import { VideoShareModel } from '../../../models/video/video-share' import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' +import { SignatureActorModel } from '../../../typings/models' async function processUndoActivity (options: APProcessorOptions) { const { activity, byActor } = options @@ -53,7 +54,7 @@ export { // --------------------------------------------------------------------------- -async function processUndoLike (byActor: ActorModel, activity: ActivityUndo) { +async function processUndoLike (byActor: SignatureActorModel, activity: ActivityUndo) { const likeActivity = activity.object as ActivityLike const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: likeActivity.object }) @@ -76,7 +77,7 @@ async function processUndoLike (byActor: ActorModel, activity: ActivityUndo) { }) } -async function processUndoDislike (byActor: ActorModel, activity: ActivityUndo) { +async function processUndoDislike (byActor: SignatureActorModel, activity: ActivityUndo) { const dislike = activity.object.type === 'Dislike' ? activity.object : activity.object.object as DislikeObject @@ -101,7 +102,7 @@ async function processUndoDislike (byActor: ActorModel, activity: ActivityUndo) }) } -async function processUndoCacheFile (byActor: ActorModel, activity: ActivityUndo) { +async function processUndoCacheFile (byActor: SignatureActorModel, activity: ActivityUndo) { const cacheFileObject = activity.object.object as CacheFileObject const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: cacheFileObject.object }) @@ -126,7 +127,7 @@ async function processUndoCacheFile (byActor: ActorModel, activity: ActivityUndo }) } -function processUndoFollow (follower: ActorModel, followActivity: ActivityFollow) { +function processUndoFollow (follower: SignatureActorModel, followActivity: ActivityFollow) { return sequelizeTypescript.transaction(async t => { const following = await ActorModel.loadByUrlAndPopulateAccountAndChannel(followActivity.object, t) const actorFollow = await ActorFollowModel.loadByActorAndTarget(follower.id, following.id, t) @@ -139,7 +140,7 @@ function processUndoFollow (follower: ActorModel, followActivity: ActivityFollow }) } -function processUndoAnnounce (byActor: ActorModel, announceActivity: ActivityAnnounce) { +function processUndoAnnounce (byActor: SignatureActorModel, announceActivity: ActivityAnnounce) { return sequelizeTypescript.transaction(async t => { const share = await VideoShareModel.loadByUrl(announceActivity.id, t) if (!share) throw new Error(`Unknown video share ${announceActivity.id}.`) diff --git a/server/lib/activitypub/process/process-update.ts b/server/lib/activitypub/process/process-update.ts index 1e11dd1fd..e3c862221 100644 --- a/server/lib/activitypub/process/process-update.ts +++ b/server/lib/activitypub/process/process-update.ts @@ -15,6 +15,7 @@ import { forwardVideoRelatedActivity } from '../send/utils' import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object' import { createOrUpdateVideoPlaylist } from '../playlist' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' +import { SignatureActorModel } from '../../../typings/models' async function processUpdateActivity (options: APProcessorOptions) { const { activity, byActor } = options @@ -52,7 +53,7 @@ export { // --------------------------------------------------------------------------- -async function processUpdateVideo (actor: ActorModel, activity: ActivityUpdate) { +async function processUpdateVideo (actor: SignatureActorModel, activity: ActivityUpdate) { const videoObject = activity.object as VideoTorrentObject if (sanitizeAndCheckVideoTorrentObject(videoObject) === false) { @@ -73,7 +74,7 @@ async function processUpdateVideo (actor: ActorModel, activity: ActivityUpdate) return updateVideoFromAP(updateOptions) } -async function processUpdateCacheFile (byActor: ActorModel, activity: ActivityUpdate) { +async function processUpdateCacheFile (byActor: SignatureActorModel, activity: ActivityUpdate) { const cacheFileObject = activity.object as CacheFileObject if (!isCacheFileObjectValid(cacheFileObject)) { @@ -147,7 +148,7 @@ async function processUpdateActor (actor: ActorModel, activity: ActivityUpdate) } } -async function processUpdatePlaylist (byActor: ActorModel, activity: ActivityUpdate) { +async function processUpdatePlaylist (byActor: SignatureActorModel, activity: ActivityUpdate) { const playlistObject = activity.object as PlaylistObject const byAccount = byActor.Account diff --git a/server/lib/activitypub/process/process-view.ts b/server/lib/activitypub/process/process-view.ts index 0170b74f4..e4997b828 100644 --- a/server/lib/activitypub/process/process-view.ts +++ b/server/lib/activitypub/process/process-view.ts @@ -1,9 +1,9 @@ -import { ActorModel } from '../../../models/activitypub/actor' import { getOrCreateVideoAndAccountAndChannel } from '../videos' import { forwardVideoRelatedActivity } from '../send/utils' import { Redis } from '../../redis' import { ActivityCreate, ActivityView, ViewObject } from '../../../../shared/models/activitypub' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' +import { SignatureActorModel } from '../../../typings/models' async function processViewActivity (options: APProcessorOptions) { const { activity, byActor } = options @@ -18,7 +18,7 @@ export { // --------------------------------------------------------------------------- -async function processCreateView (activity: ActivityView | ActivityCreate, byActor: ActorModel) { +async function processCreateView (activity: ActivityView | ActivityCreate, byActor: SignatureActorModel) { const videoObject = activity.type === 'View' ? activity.object : (activity.object as ViewObject).object const options = { diff --git a/server/lib/activitypub/process/process.ts b/server/lib/activitypub/process/process.ts index f4a92e341..d108fe321 100644 --- a/server/lib/activitypub/process/process.ts +++ b/server/lib/activitypub/process/process.ts @@ -16,6 +16,7 @@ import { processDislikeActivity } from './process-dislike' import { processFlagActivity } from './process-flag' import { processViewActivity } from './process-view' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' +import { SignatureActorModel } from '../../../typings/models' const processActivity: { [ P in ActivityType ]: (options: APProcessorOptions) => Promise } = { Create: processCreateActivity, @@ -35,7 +36,7 @@ const processActivity: { [ P in ActivityType ]: (options: APProcessorOptions unicastTo(data, me, following.inboxUrl)) } -function buildFollowActivity (url: string, byActor: ActorModel, targetActor: ActorModel): ActivityFollow { +function buildFollowActivity (url: string, byActor: ActorModelOnly, targetActor: ActorModelOnly): ActivityFollow { return { type: 'Follow', id: url, diff --git a/server/lib/activitypub/send/send-reject.ts b/server/lib/activitypub/send/send-reject.ts index bac7ff556..63110b433 100644 --- a/server/lib/activitypub/send/send-reject.ts +++ b/server/lib/activitypub/send/send-reject.ts @@ -4,8 +4,9 @@ import { getActorFollowActivityPubUrl, getActorFollowRejectActivityPubUrl } from import { unicastTo } from './utils' import { buildFollowActivity } from './send-follow' import { logger } from '../../../helpers/logger' +import { SignatureActorModel } from '../../../typings/models' -async function sendReject (follower: ActorModel, following: ActorModel) { +async function sendReject (follower: SignatureActorModel, following: ActorModel) { if (!follower.serverId) { // This should never happen logger.warn('Do not sending reject to local follower.') return diff --git a/server/lib/activitypub/send/utils.ts b/server/lib/activitypub/send/utils.ts index 1faae1d84..4f69afb00 100644 --- a/server/lib/activitypub/send/utils.ts +++ b/server/lib/activitypub/send/utils.ts @@ -8,21 +8,24 @@ import { VideoModel } from '../../../models/video/video' import { getActorsInvolvedInVideo, getAudienceFromFollowersOf, getRemoteVideoAudience } from '../audience' import { getServerActor } from '../../../helpers/utils' import { afterCommitIfTransaction } from '../../../helpers/database-utils' +import { ActorFollowerException, ActorModelId, ActorModelOnly } from '../../../typings/models' async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: { - byActor: ActorModel, + byActor: ActorModelOnly, video: VideoModel, transaction?: Transaction }) { - const actorsInvolvedInVideo = await getActorsInvolvedInVideo(options.video, options.transaction) + const { byActor, video, transaction } = options + + const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, transaction) // Send to origin - if (options.video.isOwned() === false) { - const audience = getRemoteVideoAudience(options.video, actorsInvolvedInVideo) + if (video.isOwned() === false) { + const audience = getRemoteVideoAudience(video, actorsInvolvedInVideo) const activity = activityBuilder(audience) - return afterCommitIfTransaction(options.transaction, () => { - return unicastTo(activity, options.byActor, options.video.VideoChannel.Account.Actor.sharedInboxUrl) + return afterCommitIfTransaction(transaction, () => { + return unicastTo(activity, byActor, video.VideoChannel.Account.Actor.sharedInboxUrl) }) } @@ -30,15 +33,15 @@ async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAud const audience = getAudienceFromFollowersOf(actorsInvolvedInVideo) const activity = activityBuilder(audience) - const actorsException = [ options.byActor ] + const actorsException = [ byActor ] - return broadcastToFollowers(activity, options.byActor, actorsInvolvedInVideo, options.transaction, actorsException) + return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, transaction, actorsException) } async function forwardVideoRelatedActivity ( activity: Activity, t: Transaction, - followersException: ActorModel[] = [], + followersException: ActorFollowerException[] = [], video: VideoModel ) { // Mastodon does not add our announces in audience, so we forward to them manually @@ -51,7 +54,7 @@ async function forwardVideoRelatedActivity ( async function forwardActivity ( activity: Activity, t: Transaction, - followersException: ActorModel[] = [], + followersException: ActorFollowerException[] = [], additionalFollowerUrls: string[] = [] ) { logger.info('Forwarding activity %s.', activity.id) @@ -85,10 +88,10 @@ async function forwardActivity ( async function broadcastToFollowers ( data: any, - byActor: ActorModel, - toFollowersOf: ActorModel[], + byActor: ActorModelId, + toFollowersOf: ActorModelId[], t: Transaction, - actorsException: ActorModel[] = [] + actorsException: ActorFollowerException[] = [] ) { const uris = await computeFollowerUris(toFollowersOf, actorsException, t) @@ -97,16 +100,16 @@ async function broadcastToFollowers ( async function broadcastToActors ( data: any, - byActor: ActorModel, - toActors: ActorModel[], + byActor: ActorModelId, + toActors: ActorModelOnly[], t?: Transaction, - actorsException: ActorModel[] = [] + actorsException: ActorFollowerException[] = [] ) { const uris = await computeUris(toActors, actorsException) return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor)) } -function broadcastTo (uris: string[], data: any, byActor: ActorModel) { +function broadcastTo (uris: string[], data: any, byActor: ActorModelId) { if (uris.length === 0) return undefined logger.debug('Creating broadcast job.', { uris }) @@ -120,7 +123,7 @@ function broadcastTo (uris: string[], data: any, byActor: ActorModel) { return JobQueue.Instance.createJob({ type: 'activitypub-http-broadcast', payload }) } -function unicastTo (data: any, byActor: ActorModel, toActorUrl: string) { +function unicastTo (data: any, byActor: ActorModelId, toActorUrl: string) { logger.debug('Creating unicast job.', { uri: toActorUrl }) const payload = { @@ -145,7 +148,7 @@ export { // --------------------------------------------------------------------------- -async function computeFollowerUris (toFollowersOf: ActorModel[], actorsException: ActorModel[], t: Transaction) { +async function computeFollowerUris (toFollowersOf: ActorModelId[], actorsException: ActorFollowerException[], t: Transaction) { const toActorFollowerIds = toFollowersOf.map(a => a.id) const result = await ActorFollowModel.listAcceptedFollowerSharedInboxUrls(toActorFollowerIds, t) @@ -154,7 +157,7 @@ async function computeFollowerUris (toFollowersOf: ActorModel[], actorsException return result.data.filter(sharedInbox => sharedInboxesException.indexOf(sharedInbox) === -1) } -async function computeUris (toActors: ActorModel[], actorsException: ActorModel[] = []) { +async function computeUris (toActors: ActorModelOnly[], actorsException: ActorFollowerException[] = []) { const serverActor = await getServerActor() const targetUrls = toActors .filter(a => a.id !== serverActor.id) // Don't send to ourselves @@ -167,7 +170,7 @@ async function computeUris (toActors: ActorModel[], actorsException: ActorModel[ .filter(sharedInbox => sharedInboxesException.indexOf(sharedInbox) === -1) } -async function buildSharedInboxesException (actorsException: ActorModel[]) { +async function buildSharedInboxesException (actorsException: ActorFollowerException[]) { const serverActor = await getServerActor() return actorsException diff --git a/server/lib/activitypub/url.ts b/server/lib/activitypub/url.ts index bcb7a4ee2..dfcb3c668 100644 --- a/server/lib/activitypub/url.ts +++ b/server/lib/activitypub/url.ts @@ -1,12 +1,12 @@ import { WEBSERVER } from '../../initializers/constants' -import { ActorModel } from '../../models/activitypub/actor' -import { ActorFollowModel } from '../../models/activitypub/actor-follow' import { VideoModel } from '../../models/video/video' import { VideoAbuseModel } from '../../models/video/video-abuse' import { VideoCommentModel } from '../../models/video/video-comment' import { VideoFileModel } from '../../models/video/video-file' import { VideoStreamingPlaylistModel } from '../../models/video/video-streaming-playlist' import { VideoPlaylistModel } from '../../models/video/video-playlist' +import { ActorModelOnly, ActorModelUrl } from '../../typings/models' +import { ActorFollowModelLight } from '../../typings/models/actor-follow' function getVideoActivityPubUrl (video: VideoModel) { return WEBSERVER.URL + '/videos/watch/' + video.uuid @@ -46,15 +46,15 @@ function getVideoAbuseActivityPubUrl (videoAbuse: VideoAbuseModel) { return WEBSERVER.URL + '/admin/video-abuses/' + videoAbuse.id } -function getVideoViewActivityPubUrl (byActor: ActorModel, video: VideoModel) { +function getVideoViewActivityPubUrl (byActor: ActorModelUrl, video: VideoModel) { return byActor.url + '/views/videos/' + video.id + '/' + new Date().toISOString() } -function getVideoLikeActivityPubUrl (byActor: ActorModel, video: VideoModel | { id: number }) { +function getVideoLikeActivityPubUrl (byActor: ActorModelUrl, video: VideoModel | { id: number }) { return byActor.url + '/likes/' + video.id } -function getVideoDislikeActivityPubUrl (byActor: ActorModel, video: VideoModel | { id: number }) { +function getVideoDislikeActivityPubUrl (byActor: ActorModelUrl, video: VideoModel | { id: number }) { return byActor.url + '/dislikes/' + video.id } @@ -74,22 +74,22 @@ function getVideoDislikesActivityPubUrl (video: VideoModel) { return video.url + '/dislikes' } -function getActorFollowActivityPubUrl (follower: ActorModel, following: ActorModel) { +function getActorFollowActivityPubUrl (follower: ActorModelOnly, following: ActorModelOnly) { return follower.url + '/follows/' + following.id } -function getActorFollowAcceptActivityPubUrl (actorFollow: ActorFollowModel) { +function getActorFollowAcceptActivityPubUrl (actorFollow: ActorFollowModelLight) { const follower = actorFollow.ActorFollower const me = actorFollow.ActorFollowing return follower.url + '/accepts/follows/' + me.id } -function getActorFollowRejectActivityPubUrl (follower: ActorModel, following: ActorModel) { +function getActorFollowRejectActivityPubUrl (follower: ActorModelOnly, following: ActorModelOnly) { return follower.url + '/rejects/follows/' + following.id } -function getVideoAnnounceActivityPubUrl (byActor: ActorModel, video: VideoModel) { +function getVideoAnnounceActivityPubUrl (byActor: ActorModelOnly, video: VideoModel) { return video.url + '/announces/' + byActor.id } diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts index 2102702e1..3a8451a32 100644 --- a/server/lib/activitypub/videos.ts +++ b/server/lib/activitypub/videos.ts @@ -27,7 +27,6 @@ import { import { ActorModel } from '../../models/activitypub/actor' import { TagModel } from '../../models/video/tag' import { VideoModel } from '../../models/video/video' -import { VideoChannelModel } from '../../models/video/video-channel' import { VideoFileModel } from '../../models/video/video-file' import { getOrCreateActorAndServerAndModel } from './actor' import { addVideoComments } from './video-comments' @@ -54,9 +53,9 @@ import { ThumbnailModel } from '../../models/video/thumbnail' import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' import { join } from 'path' import { FilteredModelAttributes } from '../../typings/sequelize' -import { Hooks } from '../plugins/hooks' import { autoBlacklistVideoIfNeeded } from '../video-blacklist' import { ActorFollowScoreCache } from '../files-cache' +import { AccountModelIdActor, VideoChannelModelId, VideoChannelModelIdActor } from '../../typings/models' async function federateVideoIfNeeded (video: VideoModel, isNewVideo: boolean, transaction?: sequelize.Transaction) { if ( @@ -239,8 +238,8 @@ async function getOrCreateVideoAndAccountAndChannel (options: { async function updateVideoFromAP (options: { video: VideoModel, videoObject: VideoTorrentObject, - account: AccountModel, - channel: VideoChannelModel, + account: AccountModelIdActor, + channel: VideoChannelModelIdActor, overrideTo?: string[] }) { const { video, videoObject, account, channel, overrideTo } = options @@ -550,7 +549,7 @@ async function createVideo (videoObject: VideoTorrentObject, channelActor: Actor } async function videoActivityObjectToDBAttributes ( - videoChannel: VideoChannelModel, + videoChannel: VideoChannelModelId, videoObject: VideoTorrentObject, to: string[] = [] ) { diff --git a/server/typings/activitypub-processor.model.ts b/server/typings/activitypub-processor.model.ts index 7c70251ca..37b2859de 100644 --- a/server/typings/activitypub-processor.model.ts +++ b/server/typings/activitypub-processor.model.ts @@ -1,9 +1,10 @@ import { Activity } from '../../shared/models/activitypub' import { ActorModel } from '../models/activitypub/actor' +import { SignatureActorModel } from './models' export type APProcessorOptions = { activity: T - byActor: ActorModel + byActor: SignatureActorModel inboxActor?: ActorModel fromFetch?: boolean } diff --git a/server/typings/express.ts b/server/typings/express.ts index 3bffc1e9a..f7da55ab0 100644 --- a/server/typings/express.ts +++ b/server/typings/express.ts @@ -22,6 +22,7 @@ import { VideoCaptionModel } from '../models/video/video-caption' import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist' import { RegisteredPlugin } from '../lib/plugins/plugin-manager' import { PluginModel } from '../models/server/plugin' +import { SignatureActorModel } from './models' declare module 'express' { @@ -75,7 +76,7 @@ declare module 'express' { } signature?: { - actor: ActorModel + actor: SignatureActorModel } authenticated?: boolean diff --git a/server/typings/models/actor-follow.ts b/server/typings/models/actor-follow.ts new file mode 100644 index 000000000..952ef877b --- /dev/null +++ b/server/typings/models/actor-follow.ts @@ -0,0 +1,8 @@ +import { ActorFollowModel } from '../../models/activitypub/actor-follow' +import { ActorModelOnly } from './actor' + +export type ActorFollowModelOnly = Omit +export type ActorFollowModelLight = ActorFollowModelOnly & { + ActorFollower: ActorModelOnly + ActorFollowing: ActorModelOnly +} diff --git a/server/typings/models/actor.ts b/server/typings/models/actor.ts new file mode 100644 index 000000000..2656c7b66 --- /dev/null +++ b/server/typings/models/actor.ts @@ -0,0 +1,22 @@ +import { ActorModel } from '../../models/activitypub/actor' +import { VideoChannelModel } from '../../models/video/video-channel' +import { AccountModel } from '../../models/account/account' +import { FunctionProperties } from '../utils' + +export type VideoChannelModelId = FunctionProperties +export type AccountModelId = FunctionProperties | Pick + +export type VideoChannelModelIdActor = VideoChannelModelId & Pick +export type AccountModelIdActor = AccountModelId & Pick + +export type ActorModelUrl = Pick +export type ActorModelOnly = Omit +export type ActorModelId = Pick + +export type SignatureActorModel = ActorModelOnly & { + VideoChannel: VideoChannelModelIdActor + + Account: AccountModelIdActor +} + +export type ActorFollowerException = Pick diff --git a/server/typings/models/index.d.ts b/server/typings/models/index.d.ts new file mode 100644 index 000000000..c90656965 --- /dev/null +++ b/server/typings/models/index.d.ts @@ -0,0 +1 @@ +export * from './actor' diff --git a/server/typings/models/video-share.ts b/server/typings/models/video-share.ts new file mode 100644 index 000000000..1406749d2 --- /dev/null +++ b/server/typings/models/video-share.ts @@ -0,0 +1,3 @@ +import { VideoShareModel } from '../../models/video/video-share' + +export type VideoShareModelOnly = Omit diff --git a/server/typings/utils.ts b/server/typings/utils.ts new file mode 100644 index 000000000..a86b05be2 --- /dev/null +++ b/server/typings/utils.ts @@ -0,0 +1,3 @@ +export type FunctionPropertyNames = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T] + +export type FunctionProperties = Pick> -- 2.41.0