aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--server/controllers/activitypub/inbox.ts3
-rw-r--r--server/lib/activitypub/actor.ts2
-rw-r--r--server/lib/activitypub/audience.ts3
-rw-r--r--server/lib/activitypub/playlist.ts5
-rw-r--r--server/lib/activitypub/process/process-accept.ts3
-rw-r--r--server/lib/activitypub/process/process-announce.ts4
-rw-r--r--server/lib/activitypub/process/process-create.ts8
-rw-r--r--server/lib/activitypub/process/process-delete.ts3
-rw-r--r--server/lib/activitypub/process/process-dislike.ts4
-rw-r--r--server/lib/activitypub/process/process-flag.ts4
-rw-r--r--server/lib/activitypub/process/process-follow.ts16
-rw-r--r--server/lib/activitypub/process/process-like.ts4
-rw-r--r--server/lib/activitypub/process/process-reject.ts4
-rw-r--r--server/lib/activitypub/process/process-undo.ts11
-rw-r--r--server/lib/activitypub/process/process-update.ts7
-rw-r--r--server/lib/activitypub/process/process-view.ts4
-rw-r--r--server/lib/activitypub/process/process.ts5
-rw-r--r--server/lib/activitypub/send/send-accept.ts8
-rw-r--r--server/lib/activitypub/send/send-announce.ts17
-rw-r--r--server/lib/activitypub/send/send-follow.ts4
-rw-r--r--server/lib/activitypub/send/send-reject.ts3
-rw-r--r--server/lib/activitypub/send/utils.ts45
-rw-r--r--server/lib/activitypub/url.ts18
-rw-r--r--server/lib/activitypub/videos.ts9
-rw-r--r--server/typings/activitypub-processor.model.ts3
-rw-r--r--server/typings/express.ts3
-rw-r--r--server/typings/models/actor-follow.ts8
-rw-r--r--server/typings/models/actor.ts22
-rw-r--r--server/typings/models/index.d.ts1
-rw-r--r--server/typings/models/video-share.ts3
-rw-r--r--server/typings/utils.ts3
31 files changed, 147 insertions, 90 deletions
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
7import { activityPubValidator } from '../../middlewares/validators/activitypub/activity' 7import { activityPubValidator } from '../../middlewares/validators/activitypub/activity'
8import { queue } from 'async' 8import { queue } from 'async'
9import { ActorModel } from '../../models/activitypub/actor' 9import { ActorModel } from '../../models/activitypub/actor'
10import { SignatureActorModel } from '../../typings/models'
10 11
11const inboxRouter = express.Router() 12const inboxRouter = express.Router()
12 13
@@ -40,7 +41,7 @@ export {
40 41
41// --------------------------------------------------------------------------- 42// ---------------------------------------------------------------------------
42 43
43const inboxQueue = queue<{ activities: Activity[], signatureActor?: ActorModel, inboxActor?: ActorModel }, Error>((task, cb) => { 44const inboxQueue = queue<{ activities: Activity[], signatureActor?: SignatureActorModel, inboxActor?: ActorModel }, Error>((task, cb) => {
44 const options = { signatureActor: task.signatureActor, inboxActor: task.inboxActor } 45 const options = { signatureActor: task.signatureActor, inboxActor: task.inboxActor }
45 46
46 processActivities(task.activities, options) 47 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) {
195 return undefined 195 return undefined
196} 196}
197 197
198async function addFetchOutboxJob (actor: ActorModel) { 198async function addFetchOutboxJob (actor: Pick<ActorModel, 'id' | 'outboxUrl'>) {
199 // Don't fetch ourselves 199 // Don't fetch ourselves
200 const serverActor = await getServerActor() 200 const serverActor = await getServerActor()
201 if (serverActor.id === actor.id) { 201 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'
5import { VideoModel } from '../../models/video/video' 5import { VideoModel } from '../../models/video/video'
6import { VideoCommentModel } from '../../models/video/video-comment' 6import { VideoCommentModel } from '../../models/video/video-comment'
7import { VideoShareModel } from '../../models/video/video-share' 7import { VideoShareModel } from '../../models/video/video-share'
8import { ActorModelOnly } from '../../typings/models'
8 9
9function getRemoteVideoAudience (video: VideoModel, actorsInvolvedInVideo: ActorModel[]): ActivityAudience { 10function getRemoteVideoAudience (video: VideoModel, actorsInvolvedInVideo: ActorModel[]): ActivityAudience {
10 return { 11 return {
@@ -60,7 +61,7 @@ async function getActorsInvolvedInVideo (video: VideoModel, t: Transaction) {
60 return actors 61 return actors
61} 62}
62 63
63function getAudience (actorSender: ActorModel, isPublic = true) { 64function getAudience (actorSender: ActorModelOnly, isPublic = true) {
64 return buildAudience([ actorSender.followersUrl ], isPublic) 65 return buildAudience([ actorSender.followersUrl ], isPublic)
65} 66}
66 67
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
18import { sequelizeTypescript } from '../../initializers/database' 18import { sequelizeTypescript } from '../../initializers/database'
19import { createPlaylistMiniatureFromUrl } from '../thumbnail' 19import { createPlaylistMiniatureFromUrl } from '../thumbnail'
20import { FilteredModelAttributes } from '../../typings/sequelize' 20import { FilteredModelAttributes } from '../../typings/sequelize'
21import { AccountModelId } from '../../typings/models'
21 22
22function playlistObjectToDBAttributes (playlistObject: PlaylistObject, byAccount: AccountModel, to: string[]) { 23function playlistObjectToDBAttributes (playlistObject: PlaylistObject, byAccount: AccountModelId, to: string[]) {
23 const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPlaylistPrivacy.PUBLIC : VideoPlaylistPrivacy.UNLISTED 24 const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPlaylistPrivacy.PUBLIC : VideoPlaylistPrivacy.UNLISTED
24 25
25 return { 26 return {
@@ -74,7 +75,7 @@ async function createAccountPlaylists (playlistUrls: string[], account: AccountM
74 }, { concurrency: CRAWL_REQUEST_CONCURRENCY }) 75 }, { concurrency: CRAWL_REQUEST_CONCURRENCY })
75} 76}
76 77
77async function createOrUpdateVideoPlaylist (playlistObject: PlaylistObject, byAccount: AccountModel, to: string[]) { 78async function createOrUpdateVideoPlaylist (playlistObject: PlaylistObject, byAccount: AccountModelId, to: string[]) {
78 const playlistAttributes = playlistObjectToDBAttributes(playlistObject, byAccount, to) 79 const playlistAttributes = playlistObjectToDBAttributes(playlistObject, byAccount, to)
79 80
80 if (isArray(playlistObject.attributedTo) && playlistObject.attributedTo.length === 1) { 81 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'
3import { ActorFollowModel } from '../../../models/activitypub/actor-follow' 3import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
4import { addFetchOutboxJob } from '../actor' 4import { addFetchOutboxJob } from '../actor'
5import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 5import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
6import { SignatureActorModel } from '../../../typings/models'
6 7
7async function processAcceptActivity (options: APProcessorOptions<ActivityAccept>) { 8async function processAcceptActivity (options: APProcessorOptions<ActivityAccept>) {
8 const { byActor: targetActor, inboxActor } = options 9 const { byActor: targetActor, inboxActor } = options
@@ -19,7 +20,7 @@ export {
19 20
20// --------------------------------------------------------------------------- 21// ---------------------------------------------------------------------------
21 22
22async function processAccept (actor: ActorModel, targetActor: ActorModel) { 23async function processAccept (actor: ActorModel, targetActor: SignatureActorModel) {
23 const follow = await ActorFollowModel.loadByActorAndTarget(actor.id, targetActor.id) 24 const follow = await ActorFollowModel.loadByActorAndTarget(actor.id, targetActor.id)
24 if (!follow) throw new Error('Cannot find associated follow.') 25 if (!follow) throw new Error('Cannot find associated follow.')
25 26
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 @@
1import { ActivityAnnounce } from '../../../../shared/models/activitypub' 1import { ActivityAnnounce } from '../../../../shared/models/activitypub'
2import { retryTransactionWrapper } from '../../../helpers/database-utils' 2import { retryTransactionWrapper } from '../../../helpers/database-utils'
3import { sequelizeTypescript } from '../../../initializers' 3import { sequelizeTypescript } from '../../../initializers'
4import { ActorModel } from '../../../models/activitypub/actor'
5import { VideoShareModel } from '../../../models/video/video-share' 4import { VideoShareModel } from '../../../models/video/video-share'
6import { forwardVideoRelatedActivity } from '../send/utils' 5import { forwardVideoRelatedActivity } from '../send/utils'
7import { getOrCreateVideoAndAccountAndChannel } from '../videos' 6import { getOrCreateVideoAndAccountAndChannel } from '../videos'
@@ -9,6 +8,7 @@ import { Notifier } from '../../notifier'
9import { VideoModel } from '../../../models/video/video' 8import { VideoModel } from '../../../models/video/video'
10import { logger } from '../../../helpers/logger' 9import { logger } from '../../../helpers/logger'
11import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 10import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
11import { SignatureActorModel } from '../../../typings/models'
12 12
13async function processAnnounceActivity (options: APProcessorOptions<ActivityAnnounce>) { 13async function processAnnounceActivity (options: APProcessorOptions<ActivityAnnounce>) {
14 const { activity, byActor: actorAnnouncer } = options 14 const { activity, byActor: actorAnnouncer } = options
@@ -26,7 +26,7 @@ export {
26 26
27// --------------------------------------------------------------------------- 27// ---------------------------------------------------------------------------
28 28
29async function processVideoShare (actorAnnouncer: ActorModel, activity: ActivityAnnounce, notify: boolean) { 29async function processVideoShare (actorAnnouncer: SignatureActorModel, activity: ActivityAnnounce, notify: boolean) {
30 const objectUri = typeof activity.object === 'string' ? activity.object : activity.object.id 30 const objectUri = typeof activity.object === 'string' ? activity.object : activity.object.id
31 31
32 let video: VideoModel 32 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
3import { retryTransactionWrapper } from '../../../helpers/database-utils' 3import { retryTransactionWrapper } from '../../../helpers/database-utils'
4import { logger } from '../../../helpers/logger' 4import { logger } from '../../../helpers/logger'
5import { sequelizeTypescript } from '../../../initializers' 5import { sequelizeTypescript } from '../../../initializers'
6import { ActorModel } from '../../../models/activitypub/actor'
7import { resolveThread } from '../video-comments' 6import { resolveThread } from '../video-comments'
8import { getOrCreateVideoAndAccountAndChannel } from '../videos' 7import { getOrCreateVideoAndAccountAndChannel } from '../videos'
9import { forwardVideoRelatedActivity } from '../send/utils' 8import { forwardVideoRelatedActivity } from '../send/utils'
@@ -14,6 +13,7 @@ import { createOrUpdateVideoPlaylist } from '../playlist'
14import { VideoModel } from '../../../models/video/video' 13import { VideoModel } from '../../../models/video/video'
15import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 14import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
16import { VideoCommentModel } from '../../../models/video/video-comment' 15import { VideoCommentModel } from '../../../models/video/video-comment'
16import { SignatureActorModel } from '../../../typings/models'
17 17
18async function processCreateActivity (options: APProcessorOptions<ActivityCreate>) { 18async function processCreateActivity (options: APProcessorOptions<ActivityCreate>) {
19 const { activity, byActor } = options 19 const { activity, byActor } = options
@@ -61,7 +61,7 @@ async function processCreateVideo (activity: ActivityCreate, notify: boolean) {
61 return video 61 return video
62} 62}
63 63
64async function processCreateCacheFile (activity: ActivityCreate, byActor: ActorModel) { 64async function processCreateCacheFile (activity: ActivityCreate, byActor: SignatureActorModel) {
65 const cacheFile = activity.object as CacheFileObject 65 const cacheFile = activity.object as CacheFileObject
66 66
67 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: cacheFile.object }) 67 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: cacheFile.object })
@@ -77,7 +77,7 @@ async function processCreateCacheFile (activity: ActivityCreate, byActor: ActorM
77 } 77 }
78} 78}
79 79
80async function processCreateVideoComment (activity: ActivityCreate, byActor: ActorModel, notify: boolean) { 80async function processCreateVideoComment (activity: ActivityCreate, byActor: SignatureActorModel, notify: boolean) {
81 const commentObject = activity.object as VideoCommentObject 81 const commentObject = activity.object as VideoCommentObject
82 const byAccount = byActor.Account 82 const byAccount = byActor.Account
83 83
@@ -110,7 +110,7 @@ async function processCreateVideoComment (activity: ActivityCreate, byActor: Act
110 if (created && notify) Notifier.Instance.notifyOnNewComment(comment) 110 if (created && notify) Notifier.Instance.notifyOnNewComment(comment)
111} 111}
112 112
113async function processCreatePlaylist (activity: ActivityCreate, byActor: ActorModel) { 113async function processCreatePlaylist (activity: ActivityCreate, byActor: SignatureActorModel) {
114 const playlistObject = activity.object as PlaylistObject 114 const playlistObject = activity.object as PlaylistObject
115 const byAccount = byActor.Account 115 const byAccount = byActor.Account
116 116
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'
10import { forwardVideoRelatedActivity } from '../send/utils' 10import { forwardVideoRelatedActivity } from '../send/utils'
11import { VideoPlaylistModel } from '../../../models/video/video-playlist' 11import { VideoPlaylistModel } from '../../../models/video/video-playlist'
12import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 12import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
13import { SignatureActorModel } from '../../../typings/models'
13 14
14async function processDeleteActivity (options: APProcessorOptions<ActivityDelete>) { 15async function processDeleteActivity (options: APProcessorOptions<ActivityDelete>) {
15 const { activity, byActor } = options 16 const { activity, byActor } = options
@@ -117,7 +118,7 @@ async function processDeleteVideoChannel (videoChannelToRemove: VideoChannelMode
117 logger.info('Remote video channel %s removed.', videoChannelToRemove.Actor.url) 118 logger.info('Remote video channel %s removed.', videoChannelToRemove.Actor.url)
118} 119}
119 120
120function processDeleteVideoComment (byActor: ActorModel, videoComment: VideoCommentModel, activity: ActivityDelete) { 121function processDeleteVideoComment (byActor: SignatureActorModel, videoComment: VideoCommentModel, activity: ActivityDelete) {
121 logger.debug('Removing remote video comment "%s".', videoComment.url) 122 logger.debug('Removing remote video comment "%s".', videoComment.url)
122 123
123 return sequelizeTypescript.transaction(async t => { 124 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'
3import { retryTransactionWrapper } from '../../../helpers/database-utils' 3import { retryTransactionWrapper } from '../../../helpers/database-utils'
4import { sequelizeTypescript } from '../../../initializers' 4import { sequelizeTypescript } from '../../../initializers'
5import { AccountVideoRateModel } from '../../../models/account/account-video-rate' 5import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
6import { ActorModel } from '../../../models/activitypub/actor'
7import { getOrCreateVideoAndAccountAndChannel } from '../videos' 6import { getOrCreateVideoAndAccountAndChannel } from '../videos'
8import { forwardVideoRelatedActivity } from '../send/utils' 7import { forwardVideoRelatedActivity } from '../send/utils'
9import { getVideoDislikeActivityPubUrl } from '../url' 8import { getVideoDislikeActivityPubUrl } from '../url'
10import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 9import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
10import { SignatureActorModel } from '../../../typings/models'
11 11
12async function processDislikeActivity (options: APProcessorOptions<ActivityCreate | ActivityDislike>) { 12async function processDislikeActivity (options: APProcessorOptions<ActivityCreate | ActivityDislike>) {
13 const { activity, byActor } = options 13 const { activity, byActor } = options
@@ -22,7 +22,7 @@ export {
22 22
23// --------------------------------------------------------------------------- 23// ---------------------------------------------------------------------------
24 24
25async function processDislike (activity: ActivityCreate | ActivityDislike, byActor: ActorModel) { 25async function processDislike (activity: ActivityCreate | ActivityDislike, byActor: SignatureActorModel) {
26 const dislikeObject = activity.type === 'Dislike' ? activity.object : (activity.object as DislikeObject).object 26 const dislikeObject = activity.type === 'Dislike' ? activity.object : (activity.object as DislikeObject).object
27 const byAccount = byActor.Account 27 const byAccount = byActor.Account
28 28
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'
3import { retryTransactionWrapper } from '../../../helpers/database-utils' 3import { retryTransactionWrapper } from '../../../helpers/database-utils'
4import { logger } from '../../../helpers/logger' 4import { logger } from '../../../helpers/logger'
5import { sequelizeTypescript } from '../../../initializers' 5import { sequelizeTypescript } from '../../../initializers'
6import { ActorModel } from '../../../models/activitypub/actor'
7import { VideoAbuseModel } from '../../../models/video/video-abuse' 6import { VideoAbuseModel } from '../../../models/video/video-abuse'
8import { getOrCreateVideoAndAccountAndChannel } from '../videos' 7import { getOrCreateVideoAndAccountAndChannel } from '../videos'
9import { Notifier } from '../../notifier' 8import { Notifier } from '../../notifier'
10import { getAPId } from '../../../helpers/activitypub' 9import { getAPId } from '../../../helpers/activitypub'
11import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 10import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
11import { SignatureActorModel } from '../../../typings/models'
12 12
13async function processFlagActivity (options: APProcessorOptions<ActivityCreate | ActivityFlag>) { 13async function processFlagActivity (options: APProcessorOptions<ActivityCreate | ActivityFlag>) {
14 const { activity, byActor } = options 14 const { activity, byActor } = options
@@ -23,7 +23,7 @@ export {
23 23
24// --------------------------------------------------------------------------- 24// ---------------------------------------------------------------------------
25 25
26async function processCreateVideoAbuse (activity: ActivityCreate | ActivityFlag, byActor: ActorModel) { 26async function processCreateVideoAbuse (activity: ActivityCreate | ActivityFlag, byActor: SignatureActorModel) {
27 const flag = activity.type === 'Flag' ? activity : (activity.object as VideoAbuseObject) 27 const flag = activity.type === 'Flag' ? activity : (activity.object as VideoAbuseObject)
28 28
29 logger.debug('Reporting remote abuse for video %s.', getAPId(flag.object)) 29 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'
10import { getServerActor } from '../../../helpers/utils' 10import { getServerActor } from '../../../helpers/utils'
11import { CONFIG } from '../../../initializers/config' 11import { CONFIG } from '../../../initializers/config'
12import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 12import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
13import { SignatureActorModel } from '../../../typings/models'
14import { ActorFollowModelLight } from '../../../typings/models/actor-follow'
13 15
14async function processFollowActivity (options: APProcessorOptions<ActivityFollow>) { 16async function processFollowActivity (options: APProcessorOptions<ActivityFollow>) {
15 const { activity, byActor } = options 17 const { activity, byActor } = options
@@ -26,7 +28,7 @@ export {
26 28
27// --------------------------------------------------------------------------- 29// ---------------------------------------------------------------------------
28 30
29async function processFollow (actor: ActorModel, targetActorURL: string) { 31async function processFollow (byActor: SignatureActorModel, targetActorURL: string) {
30 const { actorFollow, created, isFollowingInstance } = await sequelizeTypescript.transaction(async t => { 32 const { actorFollow, created, isFollowingInstance } = await sequelizeTypescript.transaction(async t => {
31 const targetActor = await ActorModel.loadByUrlAndPopulateAccountAndChannel(targetActorURL, t) 33 const targetActor = await ActorModel.loadByUrlAndPopulateAccountAndChannel(targetActorURL, t)
32 34
@@ -39,30 +41,30 @@ async function processFollow (actor: ActorModel, targetActorURL: string) {
39 if (isFollowingInstance && CONFIG.FOLLOWERS.INSTANCE.ENABLED === false) { 41 if (isFollowingInstance && CONFIG.FOLLOWERS.INSTANCE.ENABLED === false) {
40 logger.info('Rejecting %s because instance followers are disabled.', targetActor.url) 42 logger.info('Rejecting %s because instance followers are disabled.', targetActor.url)
41 43
42 await sendReject(actor, targetActor) 44 await sendReject(byActor, targetActor)
43 45
44 return { actorFollow: undefined } 46 return { actorFollow: undefined }
45 } 47 }
46 48
47 const [ actorFollow, created ] = await ActorFollowModel.findOrCreate({ 49 const [ actorFollow, created ] = await ActorFollowModel.findOrCreate({
48 where: { 50 where: {
49 actorId: actor.id, 51 actorId: byActor.id,
50 targetActorId: targetActor.id 52 targetActorId: targetActor.id
51 }, 53 },
52 defaults: { 54 defaults: {
53 actorId: actor.id, 55 actorId: byActor.id,
54 targetActorId: targetActor.id, 56 targetActorId: targetActor.id,
55 state: CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL ? 'pending' : 'accepted' 57 state: CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL ? 'pending' : 'accepted'
56 }, 58 },
57 transaction: t 59 transaction: t
58 }) 60 }) as [ ActorFollowModelLight, boolean ]
59 61
60 if (actorFollow.state !== 'accepted' && CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL === false) { 62 if (actorFollow.state !== 'accepted' && CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL === false) {
61 actorFollow.state = 'accepted' 63 actorFollow.state = 'accepted'
62 await actorFollow.save({ transaction: t }) 64 await actorFollow.save({ transaction: t })
63 } 65 }
64 66
65 actorFollow.ActorFollower = actor 67 actorFollow.ActorFollower = byActor
66 actorFollow.ActorFollowing = targetActor 68 actorFollow.ActorFollowing = targetActor
67 69
68 // Target sends to actor he accepted the follow request 70 // Target sends to actor he accepted the follow request
@@ -79,5 +81,5 @@ async function processFollow (actor: ActorModel, targetActorURL: string) {
79 else Notifier.Instance.notifyOfNewUserFollow(actorFollow) 81 else Notifier.Instance.notifyOfNewUserFollow(actorFollow)
80 } 82 }
81 83
82 logger.info('Actor %s is followed by actor %s.', targetActorURL, actor.url) 84 logger.info('Actor %s is followed by actor %s.', targetActorURL, byActor.url)
83} 85}
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'
2import { retryTransactionWrapper } from '../../../helpers/database-utils' 2import { retryTransactionWrapper } from '../../../helpers/database-utils'
3import { sequelizeTypescript } from '../../../initializers' 3import { sequelizeTypescript } from '../../../initializers'
4import { AccountVideoRateModel } from '../../../models/account/account-video-rate' 4import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
5import { ActorModel } from '../../../models/activitypub/actor'
6import { forwardVideoRelatedActivity } from '../send/utils' 5import { forwardVideoRelatedActivity } from '../send/utils'
7import { getOrCreateVideoAndAccountAndChannel } from '../videos' 6import { getOrCreateVideoAndAccountAndChannel } from '../videos'
8import { getVideoLikeActivityPubUrl } from '../url' 7import { getVideoLikeActivityPubUrl } from '../url'
9import { getAPId } from '../../../helpers/activitypub' 8import { getAPId } from '../../../helpers/activitypub'
10import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 9import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
10import { SignatureActorModel } from '../../../typings/models'
11 11
12async function processLikeActivity (options: APProcessorOptions<ActivityLike>) { 12async function processLikeActivity (options: APProcessorOptions<ActivityLike>) {
13 const { activity, byActor } = options 13 const { activity, byActor } = options
@@ -22,7 +22,7 @@ export {
22 22
23// --------------------------------------------------------------------------- 23// ---------------------------------------------------------------------------
24 24
25async function processLikeVideo (byActor: ActorModel, activity: ActivityLike) { 25async function processLikeVideo (byActor: SignatureActorModel, activity: ActivityLike) {
26 const videoUrl = getAPId(activity.object) 26 const videoUrl = getAPId(activity.object)
27 27
28 const byAccount = byActor.Account 28 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 @@
1import { ActivityReject } from '../../../../shared/models/activitypub/activity' 1import { ActivityReject } from '../../../../shared/models/activitypub/activity'
2import { sequelizeTypescript } from '../../../initializers' 2import { sequelizeTypescript } from '../../../initializers'
3import { ActorModel } from '../../../models/activitypub/actor'
4import { ActorFollowModel } from '../../../models/activitypub/actor-follow' 3import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
5import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 4import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
5import { ActorModelOnly } from '../../../typings/models'
6 6
7async function processRejectActivity (options: APProcessorOptions<ActivityReject>) { 7async function processRejectActivity (options: APProcessorOptions<ActivityReject>) {
8 const { byActor: targetActor, inboxActor } = options 8 const { byActor: targetActor, inboxActor } = options
@@ -19,7 +19,7 @@ export {
19 19
20// --------------------------------------------------------------------------- 20// ---------------------------------------------------------------------------
21 21
22async function processReject (follower: ActorModel, targetActor: ActorModel) { 22async function processReject (follower: ActorModelOnly, targetActor: ActorModelOnly) {
23 return sequelizeTypescript.transaction(async t => { 23 return sequelizeTypescript.transaction(async t => {
24 const actorFollow = await ActorFollowModel.loadByActorAndTarget(follower.id, targetActor.id, t) 24 const actorFollow = await ActorFollowModel.loadByActorAndTarget(follower.id, targetActor.id, t)
25 25
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'
11import { VideoShareModel } from '../../../models/video/video-share' 11import { VideoShareModel } from '../../../models/video/video-share'
12import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy' 12import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy'
13import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 13import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
14import { SignatureActorModel } from '../../../typings/models'
14 15
15async function processUndoActivity (options: APProcessorOptions<ActivityUndo>) { 16async function processUndoActivity (options: APProcessorOptions<ActivityUndo>) {
16 const { activity, byActor } = options 17 const { activity, byActor } = options
@@ -53,7 +54,7 @@ export {
53 54
54// --------------------------------------------------------------------------- 55// ---------------------------------------------------------------------------
55 56
56async function processUndoLike (byActor: ActorModel, activity: ActivityUndo) { 57async function processUndoLike (byActor: SignatureActorModel, activity: ActivityUndo) {
57 const likeActivity = activity.object as ActivityLike 58 const likeActivity = activity.object as ActivityLike
58 59
59 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: likeActivity.object }) 60 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: likeActivity.object })
@@ -76,7 +77,7 @@ async function processUndoLike (byActor: ActorModel, activity: ActivityUndo) {
76 }) 77 })
77} 78}
78 79
79async function processUndoDislike (byActor: ActorModel, activity: ActivityUndo) { 80async function processUndoDislike (byActor: SignatureActorModel, activity: ActivityUndo) {
80 const dislike = activity.object.type === 'Dislike' 81 const dislike = activity.object.type === 'Dislike'
81 ? activity.object 82 ? activity.object
82 : activity.object.object as DislikeObject 83 : activity.object.object as DislikeObject
@@ -101,7 +102,7 @@ async function processUndoDislike (byActor: ActorModel, activity: ActivityUndo)
101 }) 102 })
102} 103}
103 104
104async function processUndoCacheFile (byActor: ActorModel, activity: ActivityUndo) { 105async function processUndoCacheFile (byActor: SignatureActorModel, activity: ActivityUndo) {
105 const cacheFileObject = activity.object.object as CacheFileObject 106 const cacheFileObject = activity.object.object as CacheFileObject
106 107
107 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: cacheFileObject.object }) 108 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: cacheFileObject.object })
@@ -126,7 +127,7 @@ async function processUndoCacheFile (byActor: ActorModel, activity: ActivityUndo
126 }) 127 })
127} 128}
128 129
129function processUndoFollow (follower: ActorModel, followActivity: ActivityFollow) { 130function processUndoFollow (follower: SignatureActorModel, followActivity: ActivityFollow) {
130 return sequelizeTypescript.transaction(async t => { 131 return sequelizeTypescript.transaction(async t => {
131 const following = await ActorModel.loadByUrlAndPopulateAccountAndChannel(followActivity.object, t) 132 const following = await ActorModel.loadByUrlAndPopulateAccountAndChannel(followActivity.object, t)
132 const actorFollow = await ActorFollowModel.loadByActorAndTarget(follower.id, following.id, t) 133 const actorFollow = await ActorFollowModel.loadByActorAndTarget(follower.id, following.id, t)
@@ -139,7 +140,7 @@ function processUndoFollow (follower: ActorModel, followActivity: ActivityFollow
139 }) 140 })
140} 141}
141 142
142function processUndoAnnounce (byActor: ActorModel, announceActivity: ActivityAnnounce) { 143function processUndoAnnounce (byActor: SignatureActorModel, announceActivity: ActivityAnnounce) {
143 return sequelizeTypescript.transaction(async t => { 144 return sequelizeTypescript.transaction(async t => {
144 const share = await VideoShareModel.loadByUrl(announceActivity.id, t) 145 const share = await VideoShareModel.loadByUrl(announceActivity.id, t)
145 if (!share) throw new Error(`Unknown video share ${announceActivity.id}.`) 146 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'
15import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object' 15import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object'
16import { createOrUpdateVideoPlaylist } from '../playlist' 16import { createOrUpdateVideoPlaylist } from '../playlist'
17import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 17import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
18import { SignatureActorModel } from '../../../typings/models'
18 19
19async function processUpdateActivity (options: APProcessorOptions<ActivityUpdate>) { 20async function processUpdateActivity (options: APProcessorOptions<ActivityUpdate>) {
20 const { activity, byActor } = options 21 const { activity, byActor } = options
@@ -52,7 +53,7 @@ export {
52 53
53// --------------------------------------------------------------------------- 54// ---------------------------------------------------------------------------
54 55
55async function processUpdateVideo (actor: ActorModel, activity: ActivityUpdate) { 56async function processUpdateVideo (actor: SignatureActorModel, activity: ActivityUpdate) {
56 const videoObject = activity.object as VideoTorrentObject 57 const videoObject = activity.object as VideoTorrentObject
57 58
58 if (sanitizeAndCheckVideoTorrentObject(videoObject) === false) { 59 if (sanitizeAndCheckVideoTorrentObject(videoObject) === false) {
@@ -73,7 +74,7 @@ async function processUpdateVideo (actor: ActorModel, activity: ActivityUpdate)
73 return updateVideoFromAP(updateOptions) 74 return updateVideoFromAP(updateOptions)
74} 75}
75 76
76async function processUpdateCacheFile (byActor: ActorModel, activity: ActivityUpdate) { 77async function processUpdateCacheFile (byActor: SignatureActorModel, activity: ActivityUpdate) {
77 const cacheFileObject = activity.object as CacheFileObject 78 const cacheFileObject = activity.object as CacheFileObject
78 79
79 if (!isCacheFileObjectValid(cacheFileObject)) { 80 if (!isCacheFileObjectValid(cacheFileObject)) {
@@ -147,7 +148,7 @@ async function processUpdateActor (actor: ActorModel, activity: ActivityUpdate)
147 } 148 }
148} 149}
149 150
150async function processUpdatePlaylist (byActor: ActorModel, activity: ActivityUpdate) { 151async function processUpdatePlaylist (byActor: SignatureActorModel, activity: ActivityUpdate) {
151 const playlistObject = activity.object as PlaylistObject 152 const playlistObject = activity.object as PlaylistObject
152 const byAccount = byActor.Account 153 const byAccount = byActor.Account
153 154
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 @@
1import { ActorModel } from '../../../models/activitypub/actor'
2import { getOrCreateVideoAndAccountAndChannel } from '../videos' 1import { getOrCreateVideoAndAccountAndChannel } from '../videos'
3import { forwardVideoRelatedActivity } from '../send/utils' 2import { forwardVideoRelatedActivity } from '../send/utils'
4import { Redis } from '../../redis' 3import { Redis } from '../../redis'
5import { ActivityCreate, ActivityView, ViewObject } from '../../../../shared/models/activitypub' 4import { ActivityCreate, ActivityView, ViewObject } from '../../../../shared/models/activitypub'
6import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 5import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
6import { SignatureActorModel } from '../../../typings/models'
7 7
8async function processViewActivity (options: APProcessorOptions<ActivityCreate | ActivityView>) { 8async function processViewActivity (options: APProcessorOptions<ActivityCreate | ActivityView>) {
9 const { activity, byActor } = options 9 const { activity, byActor } = options
@@ -18,7 +18,7 @@ export {
18 18
19// --------------------------------------------------------------------------- 19// ---------------------------------------------------------------------------
20 20
21async function processCreateView (activity: ActivityView | ActivityCreate, byActor: ActorModel) { 21async function processCreateView (activity: ActivityView | ActivityCreate, byActor: SignatureActorModel) {
22 const videoObject = activity.type === 'View' ? activity.object : (activity.object as ViewObject).object 22 const videoObject = activity.type === 'View' ? activity.object : (activity.object as ViewObject).object
23 23
24 const options = { 24 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'
16import { processFlagActivity } from './process-flag' 16import { processFlagActivity } from './process-flag'
17import { processViewActivity } from './process-view' 17import { processViewActivity } from './process-view'
18import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 18import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
19import { SignatureActorModel } from '../../../typings/models'
19 20
20const processActivity: { [ P in ActivityType ]: (options: APProcessorOptions<Activity>) => Promise<any> } = { 21const processActivity: { [ P in ActivityType ]: (options: APProcessorOptions<Activity>) => Promise<any> } = {
21 Create: processCreateActivity, 22 Create: processCreateActivity,
@@ -35,7 +36,7 @@ const processActivity: { [ P in ActivityType ]: (options: APProcessorOptions<Act
35async function processActivities ( 36async function processActivities (
36 activities: Activity[], 37 activities: Activity[],
37 options: { 38 options: {
38 signatureActor?: ActorModel 39 signatureActor?: SignatureActorModel
39 inboxActor?: ActorModel 40 inboxActor?: ActorModel
40 outboxUrl?: string 41 outboxUrl?: string
41 fromFetch?: boolean 42 fromFetch?: boolean
@@ -43,7 +44,7 @@ async function processActivities (
43) { 44) {
44 const { outboxUrl, signatureActor, inboxActor, fromFetch = false } = options 45 const { outboxUrl, signatureActor, inboxActor, fromFetch = false } = options
45 46
46 const actorsCache: { [ url: string ]: ActorModel } = {} 47 const actorsCache: { [ url: string ]: SignatureActorModel } = {}
47 48
48 for (const activity of activities) { 49 for (const activity of activities) {
49 if (!signatureActor && [ 'Create', 'Announce', 'Like' ].includes(activity.type) === false) { 50 if (!signatureActor && [ 'Create', 'Announce', 'Like' ].includes(activity.type) === false) {
diff --git a/server/lib/activitypub/send/send-accept.ts b/server/lib/activitypub/send/send-accept.ts
index 388a9ed23..813c42e15 100644
--- a/server/lib/activitypub/send/send-accept.ts
+++ b/server/lib/activitypub/send/send-accept.ts
@@ -1,12 +1,12 @@
1import { ActivityAccept, ActivityFollow } from '../../../../shared/models/activitypub' 1import { ActivityAccept, ActivityFollow } from '../../../../shared/models/activitypub'
2import { ActorModel } from '../../../models/activitypub/actor'
3import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
4import { getActorFollowAcceptActivityPubUrl, getActorFollowActivityPubUrl } from '../url' 2import { getActorFollowAcceptActivityPubUrl, getActorFollowActivityPubUrl } from '../url'
5import { unicastTo } from './utils' 3import { unicastTo } from './utils'
6import { buildFollowActivity } from './send-follow' 4import { buildFollowActivity } from './send-follow'
7import { logger } from '../../../helpers/logger' 5import { logger } from '../../../helpers/logger'
6import { ActorFollowModelLight } from '../../../typings/models/actor-follow'
7import { ActorModelOnly } from '../../../typings/models'
8 8
9async function sendAccept (actorFollow: ActorFollowModel) { 9async function sendAccept (actorFollow: ActorFollowModelLight) {
10 const follower = actorFollow.ActorFollower 10 const follower = actorFollow.ActorFollower
11 const me = actorFollow.ActorFollowing 11 const me = actorFollow.ActorFollowing
12 12
@@ -34,7 +34,7 @@ export {
34 34
35// --------------------------------------------------------------------------- 35// ---------------------------------------------------------------------------
36 36
37function buildAcceptActivity (url: string, byActor: ActorModel, followActivityData: ActivityFollow): ActivityAccept { 37function buildAcceptActivity (url: string, byActor: ActorModelOnly, followActivityData: ActivityFollow): ActivityAccept {
38 return { 38 return {
39 type: 'Accept', 39 type: 'Accept',
40 id: url, 40 id: url,
diff --git a/server/lib/activitypub/send/send-announce.ts b/server/lib/activitypub/send/send-announce.ts
index cd0cab7ee..7fe4ca180 100644
--- a/server/lib/activitypub/send/send-announce.ts
+++ b/server/lib/activitypub/send/send-announce.ts
@@ -1,13 +1,18 @@
1import { Transaction } from 'sequelize' 1import { Transaction } from 'sequelize'
2import { ActivityAnnounce, ActivityAudience } from '../../../../shared/models/activitypub' 2import { ActivityAnnounce, ActivityAudience } from '../../../../shared/models/activitypub'
3import { ActorModel } from '../../../models/activitypub/actor'
4import { VideoModel } from '../../../models/video/video' 3import { VideoModel } from '../../../models/video/video'
5import { VideoShareModel } from '../../../models/video/video-share'
6import { broadcastToFollowers } from './utils' 4import { broadcastToFollowers } from './utils'
7import { audiencify, getActorsInvolvedInVideo, getAudience, getAudienceFromFollowersOf } from '../audience' 5import { audiencify, getActorsInvolvedInVideo, getAudience, getAudienceFromFollowersOf } from '../audience'
8import { logger } from '../../../helpers/logger' 6import { logger } from '../../../helpers/logger'
9 7import { ActorModelOnly } from '../../../typings/models'
10async function buildAnnounceWithVideoAudience (byActor: ActorModel, videoShare: VideoShareModel, video: VideoModel, t: Transaction) { 8import { VideoShareModelOnly } from '../../../typings/models/video-share'
9
10async function buildAnnounceWithVideoAudience (
11 byActor: ActorModelOnly,
12 videoShare: VideoShareModelOnly,
13 video: VideoModel,
14 t: Transaction
15) {
11 const announcedObject = video.url 16 const announcedObject = video.url
12 17
13 const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, t) 18 const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, t)
@@ -18,7 +23,7 @@ async function buildAnnounceWithVideoAudience (byActor: ActorModel, videoShare:
18 return { activity, actorsInvolvedInVideo } 23 return { activity, actorsInvolvedInVideo }
19} 24}
20 25
21async function sendVideoAnnounce (byActor: ActorModel, videoShare: VideoShareModel, video: VideoModel, t: Transaction) { 26async function sendVideoAnnounce (byActor: ActorModelOnly, videoShare: VideoShareModelOnly, video: VideoModel, t: Transaction) {
22 const { activity, actorsInvolvedInVideo } = await buildAnnounceWithVideoAudience(byActor, videoShare, video, t) 27 const { activity, actorsInvolvedInVideo } = await buildAnnounceWithVideoAudience(byActor, videoShare, video, t)
23 28
24 logger.info('Creating job to send announce %s.', videoShare.url) 29 logger.info('Creating job to send announce %s.', videoShare.url)
@@ -27,7 +32,7 @@ async function sendVideoAnnounce (byActor: ActorModel, videoShare: VideoShareMod
27 return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, t, followersException) 32 return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, t, followersException)
28} 33}
29 34
30function buildAnnounceActivity (url: string, byActor: ActorModel, object: string, audience?: ActivityAudience): ActivityAnnounce { 35function buildAnnounceActivity (url: string, byActor: ActorModelOnly, object: string, audience?: ActivityAudience): ActivityAnnounce {
31 if (!audience) audience = getAudience(byActor) 36 if (!audience) audience = getAudience(byActor)
32 37
33 return audiencify({ 38 return audiencify({
diff --git a/server/lib/activitypub/send/send-follow.ts b/server/lib/activitypub/send/send-follow.ts
index c6e7fe83d..a59ed50cf 100644
--- a/server/lib/activitypub/send/send-follow.ts
+++ b/server/lib/activitypub/send/send-follow.ts
@@ -1,10 +1,10 @@
1import { ActivityFollow } from '../../../../shared/models/activitypub' 1import { ActivityFollow } from '../../../../shared/models/activitypub'
2import { ActorModel } from '../../../models/activitypub/actor'
3import { ActorFollowModel } from '../../../models/activitypub/actor-follow' 2import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
4import { getActorFollowActivityPubUrl } from '../url' 3import { getActorFollowActivityPubUrl } from '../url'
5import { unicastTo } from './utils' 4import { unicastTo } from './utils'
6import { logger } from '../../../helpers/logger' 5import { logger } from '../../../helpers/logger'
7import { Transaction } from 'sequelize' 6import { Transaction } from 'sequelize'
7import { ActorModelOnly } from '../../../typings/models'
8 8
9function sendFollow (actorFollow: ActorFollowModel, t: Transaction) { 9function sendFollow (actorFollow: ActorFollowModel, t: Transaction) {
10 const me = actorFollow.ActorFollower 10 const me = actorFollow.ActorFollower
@@ -21,7 +21,7 @@ function sendFollow (actorFollow: ActorFollowModel, t: Transaction) {
21 t.afterCommit(() => unicastTo(data, me, following.inboxUrl)) 21 t.afterCommit(() => unicastTo(data, me, following.inboxUrl))
22} 22}
23 23
24function buildFollowActivity (url: string, byActor: ActorModel, targetActor: ActorModel): ActivityFollow { 24function buildFollowActivity (url: string, byActor: ActorModelOnly, targetActor: ActorModelOnly): ActivityFollow {
25 return { 25 return {
26 type: 'Follow', 26 type: 'Follow',
27 id: url, 27 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
4import { unicastTo } from './utils' 4import { unicastTo } from './utils'
5import { buildFollowActivity } from './send-follow' 5import { buildFollowActivity } from './send-follow'
6import { logger } from '../../../helpers/logger' 6import { logger } from '../../../helpers/logger'
7import { SignatureActorModel } from '../../../typings/models'
7 8
8async function sendReject (follower: ActorModel, following: ActorModel) { 9async function sendReject (follower: SignatureActorModel, following: ActorModel) {
9 if (!follower.serverId) { // This should never happen 10 if (!follower.serverId) { // This should never happen
10 logger.warn('Do not sending reject to local follower.') 11 logger.warn('Do not sending reject to local follower.')
11 return 12 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'
8import { getActorsInvolvedInVideo, getAudienceFromFollowersOf, getRemoteVideoAudience } from '../audience' 8import { getActorsInvolvedInVideo, getAudienceFromFollowersOf, getRemoteVideoAudience } from '../audience'
9import { getServerActor } from '../../../helpers/utils' 9import { getServerActor } from '../../../helpers/utils'
10import { afterCommitIfTransaction } from '../../../helpers/database-utils' 10import { afterCommitIfTransaction } from '../../../helpers/database-utils'
11import { ActorFollowerException, ActorModelId, ActorModelOnly } from '../../../typings/models'
11 12
12async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: { 13async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: {
13 byActor: ActorModel, 14 byActor: ActorModelOnly,
14 video: VideoModel, 15 video: VideoModel,
15 transaction?: Transaction 16 transaction?: Transaction
16}) { 17}) {
17 const actorsInvolvedInVideo = await getActorsInvolvedInVideo(options.video, options.transaction) 18 const { byActor, video, transaction } = options
19
20 const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, transaction)
18 21
19 // Send to origin 22 // Send to origin
20 if (options.video.isOwned() === false) { 23 if (video.isOwned() === false) {
21 const audience = getRemoteVideoAudience(options.video, actorsInvolvedInVideo) 24 const audience = getRemoteVideoAudience(video, actorsInvolvedInVideo)
22 const activity = activityBuilder(audience) 25 const activity = activityBuilder(audience)
23 26
24 return afterCommitIfTransaction(options.transaction, () => { 27 return afterCommitIfTransaction(transaction, () => {
25 return unicastTo(activity, options.byActor, options.video.VideoChannel.Account.Actor.sharedInboxUrl) 28 return unicastTo(activity, byActor, video.VideoChannel.Account.Actor.sharedInboxUrl)
26 }) 29 })
27 } 30 }
28 31
@@ -30,15 +33,15 @@ async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAud
30 const audience = getAudienceFromFollowersOf(actorsInvolvedInVideo) 33 const audience = getAudienceFromFollowersOf(actorsInvolvedInVideo)
31 const activity = activityBuilder(audience) 34 const activity = activityBuilder(audience)
32 35
33 const actorsException = [ options.byActor ] 36 const actorsException = [ byActor ]
34 37
35 return broadcastToFollowers(activity, options.byActor, actorsInvolvedInVideo, options.transaction, actorsException) 38 return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, transaction, actorsException)
36} 39}
37 40
38async function forwardVideoRelatedActivity ( 41async function forwardVideoRelatedActivity (
39 activity: Activity, 42 activity: Activity,
40 t: Transaction, 43 t: Transaction,
41 followersException: ActorModel[] = [], 44 followersException: ActorFollowerException[] = [],
42 video: VideoModel 45 video: VideoModel
43) { 46) {
44 // Mastodon does not add our announces in audience, so we forward to them manually 47 // Mastodon does not add our announces in audience, so we forward to them manually
@@ -51,7 +54,7 @@ async function forwardVideoRelatedActivity (
51async function forwardActivity ( 54async function forwardActivity (
52 activity: Activity, 55 activity: Activity,
53 t: Transaction, 56 t: Transaction,
54 followersException: ActorModel[] = [], 57 followersException: ActorFollowerException[] = [],
55 additionalFollowerUrls: string[] = [] 58 additionalFollowerUrls: string[] = []
56) { 59) {
57 logger.info('Forwarding activity %s.', activity.id) 60 logger.info('Forwarding activity %s.', activity.id)
@@ -85,10 +88,10 @@ async function forwardActivity (
85 88
86async function broadcastToFollowers ( 89async function broadcastToFollowers (
87 data: any, 90 data: any,
88 byActor: ActorModel, 91 byActor: ActorModelId,
89 toFollowersOf: ActorModel[], 92 toFollowersOf: ActorModelId[],
90 t: Transaction, 93 t: Transaction,
91 actorsException: ActorModel[] = [] 94 actorsException: ActorFollowerException[] = []
92) { 95) {
93 const uris = await computeFollowerUris(toFollowersOf, actorsException, t) 96 const uris = await computeFollowerUris(toFollowersOf, actorsException, t)
94 97
@@ -97,16 +100,16 @@ async function broadcastToFollowers (
97 100
98async function broadcastToActors ( 101async function broadcastToActors (
99 data: any, 102 data: any,
100 byActor: ActorModel, 103 byActor: ActorModelId,
101 toActors: ActorModel[], 104 toActors: ActorModelOnly[],
102 t?: Transaction, 105 t?: Transaction,
103 actorsException: ActorModel[] = [] 106 actorsException: ActorFollowerException[] = []
104) { 107) {
105 const uris = await computeUris(toActors, actorsException) 108 const uris = await computeUris(toActors, actorsException)
106 return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor)) 109 return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor))
107} 110}
108 111
109function broadcastTo (uris: string[], data: any, byActor: ActorModel) { 112function broadcastTo (uris: string[], data: any, byActor: ActorModelId) {
110 if (uris.length === 0) return undefined 113 if (uris.length === 0) return undefined
111 114
112 logger.debug('Creating broadcast job.', { uris }) 115 logger.debug('Creating broadcast job.', { uris })
@@ -120,7 +123,7 @@ function broadcastTo (uris: string[], data: any, byActor: ActorModel) {
120 return JobQueue.Instance.createJob({ type: 'activitypub-http-broadcast', payload }) 123 return JobQueue.Instance.createJob({ type: 'activitypub-http-broadcast', payload })
121} 124}
122 125
123function unicastTo (data: any, byActor: ActorModel, toActorUrl: string) { 126function unicastTo (data: any, byActor: ActorModelId, toActorUrl: string) {
124 logger.debug('Creating unicast job.', { uri: toActorUrl }) 127 logger.debug('Creating unicast job.', { uri: toActorUrl })
125 128
126 const payload = { 129 const payload = {
@@ -145,7 +148,7 @@ export {
145 148
146// --------------------------------------------------------------------------- 149// ---------------------------------------------------------------------------
147 150
148async function computeFollowerUris (toFollowersOf: ActorModel[], actorsException: ActorModel[], t: Transaction) { 151async function computeFollowerUris (toFollowersOf: ActorModelId[], actorsException: ActorFollowerException[], t: Transaction) {
149 const toActorFollowerIds = toFollowersOf.map(a => a.id) 152 const toActorFollowerIds = toFollowersOf.map(a => a.id)
150 153
151 const result = await ActorFollowModel.listAcceptedFollowerSharedInboxUrls(toActorFollowerIds, t) 154 const result = await ActorFollowModel.listAcceptedFollowerSharedInboxUrls(toActorFollowerIds, t)
@@ -154,7 +157,7 @@ async function computeFollowerUris (toFollowersOf: ActorModel[], actorsException
154 return result.data.filter(sharedInbox => sharedInboxesException.indexOf(sharedInbox) === -1) 157 return result.data.filter(sharedInbox => sharedInboxesException.indexOf(sharedInbox) === -1)
155} 158}
156 159
157async function computeUris (toActors: ActorModel[], actorsException: ActorModel[] = []) { 160async function computeUris (toActors: ActorModelOnly[], actorsException: ActorFollowerException[] = []) {
158 const serverActor = await getServerActor() 161 const serverActor = await getServerActor()
159 const targetUrls = toActors 162 const targetUrls = toActors
160 .filter(a => a.id !== serverActor.id) // Don't send to ourselves 163 .filter(a => a.id !== serverActor.id) // Don't send to ourselves
@@ -167,7 +170,7 @@ async function computeUris (toActors: ActorModel[], actorsException: ActorModel[
167 .filter(sharedInbox => sharedInboxesException.indexOf(sharedInbox) === -1) 170 .filter(sharedInbox => sharedInboxesException.indexOf(sharedInbox) === -1)
168} 171}
169 172
170async function buildSharedInboxesException (actorsException: ActorModel[]) { 173async function buildSharedInboxesException (actorsException: ActorFollowerException[]) {
171 const serverActor = await getServerActor() 174 const serverActor = await getServerActor()
172 175
173 return actorsException 176 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 @@
1import { WEBSERVER } from '../../initializers/constants' 1import { WEBSERVER } from '../../initializers/constants'
2import { ActorModel } from '../../models/activitypub/actor'
3import { ActorFollowModel } from '../../models/activitypub/actor-follow'
4import { VideoModel } from '../../models/video/video' 2import { VideoModel } from '../../models/video/video'
5import { VideoAbuseModel } from '../../models/video/video-abuse' 3import { VideoAbuseModel } from '../../models/video/video-abuse'
6import { VideoCommentModel } from '../../models/video/video-comment' 4import { VideoCommentModel } from '../../models/video/video-comment'
7import { VideoFileModel } from '../../models/video/video-file' 5import { VideoFileModel } from '../../models/video/video-file'
8import { VideoStreamingPlaylistModel } from '../../models/video/video-streaming-playlist' 6import { VideoStreamingPlaylistModel } from '../../models/video/video-streaming-playlist'
9import { VideoPlaylistModel } from '../../models/video/video-playlist' 7import { VideoPlaylistModel } from '../../models/video/video-playlist'
8import { ActorModelOnly, ActorModelUrl } from '../../typings/models'
9import { ActorFollowModelLight } from '../../typings/models/actor-follow'
10 10
11function getVideoActivityPubUrl (video: VideoModel) { 11function getVideoActivityPubUrl (video: VideoModel) {
12 return WEBSERVER.URL + '/videos/watch/' + video.uuid 12 return WEBSERVER.URL + '/videos/watch/' + video.uuid
@@ -46,15 +46,15 @@ function getVideoAbuseActivityPubUrl (videoAbuse: VideoAbuseModel) {
46 return WEBSERVER.URL + '/admin/video-abuses/' + videoAbuse.id 46 return WEBSERVER.URL + '/admin/video-abuses/' + videoAbuse.id
47} 47}
48 48
49function getVideoViewActivityPubUrl (byActor: ActorModel, video: VideoModel) { 49function getVideoViewActivityPubUrl (byActor: ActorModelUrl, video: VideoModel) {
50 return byActor.url + '/views/videos/' + video.id + '/' + new Date().toISOString() 50 return byActor.url + '/views/videos/' + video.id + '/' + new Date().toISOString()
51} 51}
52 52
53function getVideoLikeActivityPubUrl (byActor: ActorModel, video: VideoModel | { id: number }) { 53function getVideoLikeActivityPubUrl (byActor: ActorModelUrl, video: VideoModel | { id: number }) {
54 return byActor.url + '/likes/' + video.id 54 return byActor.url + '/likes/' + video.id
55} 55}
56 56
57function getVideoDislikeActivityPubUrl (byActor: ActorModel, video: VideoModel | { id: number }) { 57function getVideoDislikeActivityPubUrl (byActor: ActorModelUrl, video: VideoModel | { id: number }) {
58 return byActor.url + '/dislikes/' + video.id 58 return byActor.url + '/dislikes/' + video.id
59} 59}
60 60
@@ -74,22 +74,22 @@ function getVideoDislikesActivityPubUrl (video: VideoModel) {
74 return video.url + '/dislikes' 74 return video.url + '/dislikes'
75} 75}
76 76
77function getActorFollowActivityPubUrl (follower: ActorModel, following: ActorModel) { 77function getActorFollowActivityPubUrl (follower: ActorModelOnly, following: ActorModelOnly) {
78 return follower.url + '/follows/' + following.id 78 return follower.url + '/follows/' + following.id
79} 79}
80 80
81function getActorFollowAcceptActivityPubUrl (actorFollow: ActorFollowModel) { 81function getActorFollowAcceptActivityPubUrl (actorFollow: ActorFollowModelLight) {
82 const follower = actorFollow.ActorFollower 82 const follower = actorFollow.ActorFollower
83 const me = actorFollow.ActorFollowing 83 const me = actorFollow.ActorFollowing
84 84
85 return follower.url + '/accepts/follows/' + me.id 85 return follower.url + '/accepts/follows/' + me.id
86} 86}
87 87
88function getActorFollowRejectActivityPubUrl (follower: ActorModel, following: ActorModel) { 88function getActorFollowRejectActivityPubUrl (follower: ActorModelOnly, following: ActorModelOnly) {
89 return follower.url + '/rejects/follows/' + following.id 89 return follower.url + '/rejects/follows/' + following.id
90} 90}
91 91
92function getVideoAnnounceActivityPubUrl (byActor: ActorModel, video: VideoModel) { 92function getVideoAnnounceActivityPubUrl (byActor: ActorModelOnly, video: VideoModel) {
93 return video.url + '/announces/' + byActor.id 93 return video.url + '/announces/' + byActor.id
94} 94}
95 95
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 {
27import { ActorModel } from '../../models/activitypub/actor' 27import { ActorModel } from '../../models/activitypub/actor'
28import { TagModel } from '../../models/video/tag' 28import { TagModel } from '../../models/video/tag'
29import { VideoModel } from '../../models/video/video' 29import { VideoModel } from '../../models/video/video'
30import { VideoChannelModel } from '../../models/video/video-channel'
31import { VideoFileModel } from '../../models/video/video-file' 30import { VideoFileModel } from '../../models/video/video-file'
32import { getOrCreateActorAndServerAndModel } from './actor' 31import { getOrCreateActorAndServerAndModel } from './actor'
33import { addVideoComments } from './video-comments' 32import { addVideoComments } from './video-comments'
@@ -54,9 +53,9 @@ import { ThumbnailModel } from '../../models/video/thumbnail'
54import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' 53import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type'
55import { join } from 'path' 54import { join } from 'path'
56import { FilteredModelAttributes } from '../../typings/sequelize' 55import { FilteredModelAttributes } from '../../typings/sequelize'
57import { Hooks } from '../plugins/hooks'
58import { autoBlacklistVideoIfNeeded } from '../video-blacklist' 56import { autoBlacklistVideoIfNeeded } from '../video-blacklist'
59import { ActorFollowScoreCache } from '../files-cache' 57import { ActorFollowScoreCache } from '../files-cache'
58import { AccountModelIdActor, VideoChannelModelId, VideoChannelModelIdActor } from '../../typings/models'
60 59
61async function federateVideoIfNeeded (video: VideoModel, isNewVideo: boolean, transaction?: sequelize.Transaction) { 60async function federateVideoIfNeeded (video: VideoModel, isNewVideo: boolean, transaction?: sequelize.Transaction) {
62 if ( 61 if (
@@ -239,8 +238,8 @@ async function getOrCreateVideoAndAccountAndChannel (options: {
239async function updateVideoFromAP (options: { 238async function updateVideoFromAP (options: {
240 video: VideoModel, 239 video: VideoModel,
241 videoObject: VideoTorrentObject, 240 videoObject: VideoTorrentObject,
242 account: AccountModel, 241 account: AccountModelIdActor,
243 channel: VideoChannelModel, 242 channel: VideoChannelModelIdActor,
244 overrideTo?: string[] 243 overrideTo?: string[]
245}) { 244}) {
246 const { video, videoObject, account, channel, overrideTo } = options 245 const { video, videoObject, account, channel, overrideTo } = options
@@ -550,7 +549,7 @@ async function createVideo (videoObject: VideoTorrentObject, channelActor: Actor
550} 549}
551 550
552async function videoActivityObjectToDBAttributes ( 551async function videoActivityObjectToDBAttributes (
553 videoChannel: VideoChannelModel, 552 videoChannel: VideoChannelModelId,
554 videoObject: VideoTorrentObject, 553 videoObject: VideoTorrentObject,
555 to: string[] = [] 554 to: string[] = []
556) { 555) {
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 @@
1import { Activity } from '../../shared/models/activitypub' 1import { Activity } from '../../shared/models/activitypub'
2import { ActorModel } from '../models/activitypub/actor' 2import { ActorModel } from '../models/activitypub/actor'
3import { SignatureActorModel } from './models'
3 4
4export type APProcessorOptions<T extends Activity> = { 5export type APProcessorOptions<T extends Activity> = {
5 activity: T 6 activity: T
6 byActor: ActorModel 7 byActor: SignatureActorModel
7 inboxActor?: ActorModel 8 inboxActor?: ActorModel
8 fromFetch?: boolean 9 fromFetch?: boolean
9} 10}
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'
22import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist' 22import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist'
23import { RegisteredPlugin } from '../lib/plugins/plugin-manager' 23import { RegisteredPlugin } from '../lib/plugins/plugin-manager'
24import { PluginModel } from '../models/server/plugin' 24import { PluginModel } from '../models/server/plugin'
25import { SignatureActorModel } from './models'
25 26
26declare module 'express' { 27declare module 'express' {
27 28
@@ -75,7 +76,7 @@ declare module 'express' {
75 } 76 }
76 77
77 signature?: { 78 signature?: {
78 actor: ActorModel 79 actor: SignatureActorModel
79 } 80 }
80 81
81 authenticated?: boolean 82 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 @@
1import { ActorFollowModel } from '../../models/activitypub/actor-follow'
2import { ActorModelOnly } from './actor'
3
4export type ActorFollowModelOnly = Omit<ActorFollowModel, 'ActorFollower' | 'ActorFollowing'>
5export type ActorFollowModelLight = ActorFollowModelOnly & {
6 ActorFollower: ActorModelOnly
7 ActorFollowing: ActorModelOnly
8}
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 @@
1import { ActorModel } from '../../models/activitypub/actor'
2import { VideoChannelModel } from '../../models/video/video-channel'
3import { AccountModel } from '../../models/account/account'
4import { FunctionProperties } from '../utils'
5
6export type VideoChannelModelId = FunctionProperties<VideoChannelModel>
7export type AccountModelId = FunctionProperties<AccountModel> | Pick<AccountModel, 'id'>
8
9export type VideoChannelModelIdActor = VideoChannelModelId & Pick<VideoChannelModel, 'Actor'>
10export type AccountModelIdActor = AccountModelId & Pick<AccountModel, 'Actor'>
11
12export type ActorModelUrl = Pick<ActorModel, 'url'>
13export type ActorModelOnly = Omit<ActorModel, 'Account' | 'VideoChannel' | 'ActorFollowing' | 'Avatar' | 'ActorFollowers' | 'Server'>
14export type ActorModelId = Pick<ActorModelOnly, 'id'>
15
16export type SignatureActorModel = ActorModelOnly & {
17 VideoChannel: VideoChannelModelIdActor
18
19 Account: AccountModelIdActor
20}
21
22export type ActorFollowerException = Pick<ActorModel, 'sharedInboxUrl' | 'inboxUrl'>
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 @@
1import { VideoShareModel } from '../../models/video/video-share'
2
3export type VideoShareModelOnly = Omit<VideoShareModel, 'Actor' | 'Video'>
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 @@
1export type FunctionPropertyNames<T> = { [K in keyof T]: T[K] extends Function ? K : never }[keyof T]
2
3export type FunctionProperties<T> = Pick<T, FunctionPropertyNames<T>>