From 9588d4f49b7183631ddb97fa9c3cd79f9bfe2945 Mon Sep 17 00:00:00 2001
From: Chocobozzz <me@florianbigard.com>
Date: Thu, 31 May 2018 10:23:56 +0200
Subject: [PATCH] Correctly forward video related activities

---
 .../activitypub/process/process-announce.ts    |  5 +++--
 .../lib/activitypub/process/process-create.ts  | 12 ++++--------
 server/lib/activitypub/process/process-like.ts |  6 ++++--
 server/lib/activitypub/process/process-undo.ts | 18 ++++++++++++++----
 server/lib/activitypub/send/utils.ts           | 18 +++++++++++++++++-
 server/models/video/video-share.ts             |  2 +-
 6 files changed, 43 insertions(+), 18 deletions(-)

diff --git a/server/lib/activitypub/process/process-announce.ts b/server/lib/activitypub/process/process-announce.ts
index a6e1e2d470..4e50da8d2f 100644
--- a/server/lib/activitypub/process/process-announce.ts
+++ b/server/lib/activitypub/process/process-announce.ts
@@ -5,7 +5,7 @@ import { ActorModel } from '../../../models/activitypub/actor'
 import { VideoModel } from '../../../models/video/video'
 import { VideoShareModel } from '../../../models/video/video-share'
 import { getOrCreateActorAndServerAndModel } from '../actor'
-import { forwardActivity } from '../send/utils'
+import { forwardVideoRelatedActivity } from '../send/utils'
 import { getOrCreateAccountAndVideoAndChannel } from '../videos'
 
 async function processAnnounceActivity (activity: ActivityAnnounce) {
@@ -58,7 +58,8 @@ async function shareVideo (actorAnnouncer: ActorModel, activity: ActivityAnnounc
     if (video.isOwned() && created === true) {
       // Don't resend the activity to the sender
       const exceptions = [ actorAnnouncer ]
-      await forwardActivity(activity, t, exceptions)
+
+      await forwardVideoRelatedActivity(activity, t, exceptions, video)
     }
 
     return undefined
diff --git a/server/lib/activitypub/process/process-create.ts b/server/lib/activitypub/process/process-create.ts
index 99a5f6f9c0..38dacf772a 100644
--- a/server/lib/activitypub/process/process-create.ts
+++ b/server/lib/activitypub/process/process-create.ts
@@ -9,10 +9,9 @@ import { ActorModel } from '../../../models/activitypub/actor'
 import { VideoAbuseModel } from '../../../models/video/video-abuse'
 import { VideoCommentModel } from '../../../models/video/video-comment'
 import { getOrCreateActorAndServerAndModel } from '../actor'
-import { getActorsInvolvedInVideo } from '../audience'
 import { resolveThread } from '../video-comments'
 import { getOrCreateAccountAndVideoAndChannel } from '../videos'
-import { forwardActivity } from '../send/utils'
+import { forwardActivity, forwardVideoRelatedActivity } from '../send/utils'
 
 async function processCreateActivity (activity: ActivityCreate) {
   const activityObject = activity.object
@@ -87,7 +86,8 @@ async function createVideoDislike (byActor: ActorModel, activity: ActivityCreate
     if (video.isOwned() && created === true) {
       // Don't resend the activity to the sender
       const exceptions = [ byActor ]
-      await forwardActivity(activity, t, exceptions)
+
+      await forwardVideoRelatedActivity(activity, t, exceptions, video)
     }
   })
 }
@@ -190,11 +190,7 @@ async function createVideoComment (byActor: ActorModel, activity: ActivityCreate
       // Don't resend the activity to the sender
       const exceptions = [ byActor ]
 
-      // Mastodon does not add our announces in audience, so we forward to them manually
-      const additionalActors = await getActorsInvolvedInVideo(video, t)
-      const additionalFollowerUrls = additionalActors.map(a => a.followersUrl)
-
-      await forwardActivity(activity, t, exceptions, additionalFollowerUrls)
+      await forwardVideoRelatedActivity(activity, t, exceptions, video)
     }
   })
 }
diff --git a/server/lib/activitypub/process/process-like.ts b/server/lib/activitypub/process/process-like.ts
index d219e76eb2..f1642f038e 100644
--- a/server/lib/activitypub/process/process-like.ts
+++ b/server/lib/activitypub/process/process-like.ts
@@ -4,8 +4,9 @@ import { sequelizeTypescript } from '../../../initializers'
 import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
 import { ActorModel } from '../../../models/activitypub/actor'
 import { getOrCreateActorAndServerAndModel } from '../actor'
-import { forwardActivity } from '../send/utils'
+import { forwardActivity, forwardVideoRelatedActivity } from '../send/utils'
 import { getOrCreateAccountAndVideoAndChannel } from '../videos'
+import { getActorsInvolvedInVideo } from '../audience'
 
 async function processLikeActivity (activity: ActivityLike) {
   const actor = await getOrCreateActorAndServerAndModel(activity.actor)
@@ -54,7 +55,8 @@ async function createVideoLike (byActor: ActorModel, activity: ActivityLike) {
     if (video.isOwned() && created === true) {
       // Don't resend the activity to the sender
       const exceptions = [ byActor ]
-      await forwardActivity(activity, t, exceptions)
+
+      await forwardVideoRelatedActivity(activity, t, exceptions, video)
     }
   })
 }
diff --git a/server/lib/activitypub/process/process-undo.ts b/server/lib/activitypub/process/process-undo.ts
index d023f7029e..37db58e1a0 100644
--- a/server/lib/activitypub/process/process-undo.ts
+++ b/server/lib/activitypub/process/process-undo.ts
@@ -8,7 +8,7 @@ import { AccountModel } from '../../../models/account/account'
 import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
 import { ActorModel } from '../../../models/activitypub/actor'
 import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
-import { forwardActivity } from '../send/utils'
+import { forwardVideoRelatedActivity } from '../send/utils'
 import { getOrCreateAccountAndVideoAndChannel } from '../videos'
 import { VideoShareModel } from '../../../models/video/video-share'
 
@@ -67,7 +67,8 @@ async function undoLike (actorUrl: string, activity: ActivityUndo) {
     if (video.isOwned()) {
       // Don't resend the activity to the sender
       const exceptions = [ byAccount.Actor ]
-      await forwardActivity(activity, t, exceptions)
+
+      await forwardVideoRelatedActivity(activity, t, exceptions, video)
     }
   })
 }
@@ -99,7 +100,8 @@ async function undoDislike (actorUrl: string, activity: ActivityUndo) {
     if (video.isOwned()) {
       // Don't resend the activity to the sender
       const exceptions = [ byAccount.Actor ]
-      await forwardActivity(activity, t, exceptions)
+
+      await forwardVideoRelatedActivity(activity, t, exceptions, video)
     }
   })
 }
@@ -138,11 +140,19 @@ function processUndoAnnounce (actorUrl: string, announceActivity: ActivityAnnoun
 
 function undoAnnounce (actorUrl: string, announceActivity: ActivityAnnounce) {
   return sequelizeTypescript.transaction(async t => {
+    const byAccount = await AccountModel.loadByUrl(actorUrl, t)
+    if (!byAccount) throw new Error('Unknown account ' + actorUrl)
+
     const share = await VideoShareModel.loadByUrl(announceActivity.id, t)
     if (!share) throw new Error(`'Unknown video share ${announceActivity.id}.`)
 
     await share.destroy({ transaction: t })
 
-    return undefined
+    if (share.Video.isOwned()) {
+      // Don't resend the activity to the sender
+      const exceptions = [ byAccount.Actor ]
+
+      await forwardVideoRelatedActivity(announceActivity, t, exceptions, share.Video)
+    }
   })
 }
diff --git a/server/lib/activitypub/send/utils.ts b/server/lib/activitypub/send/utils.ts
index 80d4463ffb..241db6c8cf 100644
--- a/server/lib/activitypub/send/utils.ts
+++ b/server/lib/activitypub/send/utils.ts
@@ -4,6 +4,21 @@ import { logger } from '../../../helpers/logger'
 import { ActorModel } from '../../../models/activitypub/actor'
 import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
 import { JobQueue } from '../../job-queue'
+import { VideoModel } from '../../../models/video/video'
+import { getActorsInvolvedInVideo } from '../audience'
+
+async function forwardVideoRelatedActivity (
+  activity: Activity,
+  t: Transaction,
+  followersException: ActorModel[] = [],
+  video: VideoModel
+) {
+  // Mastodon does not add our announces in audience, so we forward to them manually
+  const additionalActors = await getActorsInvolvedInVideo(video, t)
+  const additionalFollowerUrls = additionalActors.map(a => a.followersUrl)
+
+  return forwardActivity(activity, t, followersException, additionalFollowerUrls)
+}
 
 async function forwardActivity (
   activity: Activity,
@@ -91,7 +106,8 @@ export {
   broadcastToFollowers,
   unicastTo,
   forwardActivity,
-  broadcastToActors
+  broadcastToActors,
+  forwardVideoRelatedActivity
 }
 
 // ---------------------------------------------------------------------------
diff --git a/server/models/video/video-share.ts b/server/models/video/video-share.ts
index adadf5dea0..15dba3f7d9 100644
--- a/server/models/video/video-share.ts
+++ b/server/models/video/video-share.ts
@@ -99,7 +99,7 @@ export class VideoShareModel extends Model<VideoShareModel> {
   }
 
   static loadByUrl (url: string, t: Sequelize.Transaction) {
-    return VideoShareModel.scope(ScopeNames.WITH_ACTOR).findOne({
+    return VideoShareModel.scope(ScopeNames.FULL).findOne({
       where: {
         url
       },
-- 
GitLab