]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - server/lib/activitypub/send/utils.ts
Add ability for auth plugins to hook tokens validity
[github/Chocobozzz/PeerTube.git] / server / lib / activitypub / send / utils.ts
index da437292eef24543457f6d2b77793e49b9ceed70..44a8926e52b546dd7d4d59ddf59c684a55d1eacb 100644 (file)
@@ -1,18 +1,51 @@
 import { Transaction } from 'sequelize'
-import { Activity } from '../../../../shared/models/activitypub'
+import { Activity, ActivityAudience } from '../../../../shared/models/activitypub'
 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'
-import { getServerActor } from '../../../helpers/utils'
+import { getActorsInvolvedInVideo, getAudienceFromFollowersOf, getRemoteVideoAudience } from '../audience'
+import { afterCommitIfTransaction } from '../../../helpers/database-utils'
+import { MActor, MActorId, MActorLight, MActorWithInboxes, MVideoAccountLight, MVideoId, MVideoImmutable } from '../../../typings/models'
+import { getServerActor } from '@server/models/application/application'
+import { ContextType } from '@shared/models/activitypub/context'
+
+async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: {
+  byActor: MActorLight
+  video: MVideoImmutable | MVideoAccountLight
+  transaction?: Transaction
+  contextType?: ContextType
+}) {
+  const { byActor, video, transaction, contextType } = options
+
+  const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, transaction)
+
+  // Send to origin
+  if (video.isOwned() === false) {
+    const accountActor = (video as MVideoAccountLight).VideoChannel?.Account?.Actor || await ActorModel.loadAccountActorByVideoId(video.id)
+
+    const audience = getRemoteVideoAudience(accountActor, actorsInvolvedInVideo)
+    const activity = activityBuilder(audience)
+
+    return afterCommitIfTransaction(transaction, () => {
+      return unicastTo(activity, byActor, accountActor.getSharedInbox(), contextType)
+    })
+  }
+
+  // Send to followers
+  const audience = getAudienceFromFollowersOf(actorsInvolvedInVideo)
+  const activity = activityBuilder(audience)
+
+  const actorsException = [ byActor ]
+
+  return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, transaction, actorsException, contextType)
+}
 
 async function forwardVideoRelatedActivity (
   activity: Activity,
   t: Transaction,
-  followersException: ActorModel[] = [],
-  video: VideoModel
+  followersException: MActorWithInboxes[],
+  video: MVideoId
 ) {
   // Mastodon does not add our announces in audience, so we forward to them manually
   const additionalActors = await getActorsInvolvedInVideo(video, t)
@@ -24,7 +57,7 @@ async function forwardVideoRelatedActivity (
 async function forwardActivity (
   activity: Activity,
   t: Transaction,
-  followersException: ActorModel[] = [],
+  followersException: MActorWithInboxes[] = [],
   additionalFollowerUrls: string[] = []
 ) {
   logger.info('Forwarding activity %s.', activity.id)
@@ -53,31 +86,35 @@ async function forwardActivity (
     uris,
     body: activity
   }
-  return JobQueue.Instance.createJob({ type: 'activitypub-http-broadcast', payload })
+  return afterCommitIfTransaction(t, () => JobQueue.Instance.createJob({ type: 'activitypub-http-broadcast', payload }))
 }
 
 async function broadcastToFollowers (
   data: any,
-  byActor: ActorModel,
-  toActorFollowers: ActorModel[],
+  byActor: MActorId,
+  toFollowersOf: MActorId[],
   t: Transaction,
-  actorsException: ActorModel[] = []
+  actorsException: MActorWithInboxes[] = [],
+  contextType?: ContextType
 ) {
-  const uris = await computeFollowerUris(toActorFollowers, actorsException, t)
-  return broadcastTo(uris, data, byActor)
+  const uris = await computeFollowerUris(toFollowersOf, actorsException, t)
+
+  return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor, contextType))
 }
 
 async function broadcastToActors (
   data: any,
-  byActor: ActorModel,
-  toActors: ActorModel[],
-  actorsException: ActorModel[] = []
+  byActor: MActorId,
+  toActors: MActor[],
+  t?: Transaction,
+  actorsException: MActorWithInboxes[] = [],
+  contextType?: ContextType
 ) {
   const uris = await computeUris(toActors, actorsException)
-  return broadcastTo(uris, data, byActor)
+  return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor, contextType))
 }
 
-async function broadcastTo (uris: string[], data: any, byActor: ActorModel) {
+function broadcastTo (uris: string[], data: any, byActor: MActorId, contextType?: ContextType) {
   if (uris.length === 0) return undefined
 
   logger.debug('Creating broadcast job.', { uris })
@@ -85,22 +122,24 @@ async function broadcastTo (uris: string[], data: any, byActor: ActorModel) {
   const payload = {
     uris,
     signatureActorId: byActor.id,
-    body: data
+    body: data,
+    contextType
   }
 
   return JobQueue.Instance.createJob({ type: 'activitypub-http-broadcast', payload })
 }
 
-async function unicastTo (data: any, byActor: ActorModel, toActorUrl: string) {
+function unicastTo (data: any, byActor: MActorId, toActorUrl: string, contextType?: ContextType) {
   logger.debug('Creating unicast job.', { uri: toActorUrl })
 
   const payload = {
     uri: toActorUrl,
     signatureActorId: byActor.id,
-    body: data
+    body: data,
+    contextType
   }
 
-  return JobQueue.Instance.createJob({ type: 'activitypub-http-unicast', payload })
+  JobQueue.Instance.createJob({ type: 'activitypub-http-unicast', payload })
 }
 
 // ---------------------------------------------------------------------------
@@ -110,37 +149,38 @@ export {
   unicastTo,
   forwardActivity,
   broadcastToActors,
-  forwardVideoRelatedActivity
+  forwardVideoRelatedActivity,
+  sendVideoRelatedActivity
 }
 
 // ---------------------------------------------------------------------------
 
-async function computeFollowerUris (toActorFollower: ActorModel[], actorsException: ActorModel[], t: Transaction) {
-  const toActorFollowerIds = toActorFollower.map(a => a.id)
+async function computeFollowerUris (toFollowersOf: MActorId[], actorsException: MActorWithInboxes[], t: Transaction) {
+  const toActorFollowerIds = toFollowersOf.map(a => a.id)
 
   const result = await ActorFollowModel.listAcceptedFollowerSharedInboxUrls(toActorFollowerIds, t)
   const sharedInboxesException = await buildSharedInboxesException(actorsException)
 
-  return result.data.filter(sharedInbox => sharedInboxesException.indexOf(sharedInbox) === -1)
+  return result.data.filter(sharedInbox => sharedInboxesException.includes(sharedInbox) === false)
 }
 
-async function computeUris (toActors: ActorModel[], actorsException: ActorModel[] = []) {
+async function computeUris (toActors: MActor[], actorsException: MActorWithInboxes[] = []) {
   const serverActor = await getServerActor()
   const targetUrls = toActors
     .filter(a => a.id !== serverActor.id) // Don't send to ourselves
-    .map(a => a.sharedInboxUrl || a.inboxUrl)
+    .map(a => a.getSharedInbox())
 
   const toActorSharedInboxesSet = new Set(targetUrls)
 
   const sharedInboxesException = await buildSharedInboxesException(actorsException)
   return Array.from(toActorSharedInboxesSet)
-              .filter(sharedInbox => sharedInboxesException.indexOf(sharedInbox) === -1)
+              .filter(sharedInbox => sharedInboxesException.includes(sharedInbox) === false)
 }
 
-async function buildSharedInboxesException (actorsException: ActorModel[]) {
+async function buildSharedInboxesException (actorsException: MActorWithInboxes[]) {
   const serverActor = await getServerActor()
 
   return actorsException
-    .map(f => f.sharedInboxUrl || f.inboxUrl)
+    .map(f => f.getSharedInbox())
     .concat([ serverActor.sharedInboxUrl ])
 }