aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib/activitypub/send
diff options
context:
space:
mode:
Diffstat (limited to 'server/lib/activitypub/send')
-rw-r--r--server/lib/activitypub/send/misc.ts83
-rw-r--r--server/lib/activitypub/send/send-create.ts26
-rw-r--r--server/lib/activitypub/send/send-like.ts14
-rw-r--r--server/lib/activitypub/send/send-undo.ts38
4 files changed, 111 insertions, 50 deletions
diff --git a/server/lib/activitypub/send/misc.ts b/server/lib/activitypub/send/misc.ts
index 41a039b19..fe137464e 100644
--- a/server/lib/activitypub/send/misc.ts
+++ b/server/lib/activitypub/send/misc.ts
@@ -2,8 +2,45 @@ import { Transaction } from 'sequelize'
2import { logger } from '../../../helpers/logger' 2import { logger } from '../../../helpers/logger'
3import { ACTIVITY_PUB, database as db } from '../../../initializers' 3import { ACTIVITY_PUB, database as db } from '../../../initializers'
4import { AccountInstance } from '../../../models/account/account-interface' 4import { AccountInstance } from '../../../models/account/account-interface'
5import { activitypubHttpJobScheduler } from '../../jobs/activitypub-http-job-scheduler/activitypub-http-job-scheduler' 5import {
6 activitypubHttpJobScheduler,
7 ActivityPubHttpPayload
8} from '../../jobs/activitypub-http-job-scheduler/activitypub-http-job-scheduler'
6import { VideoInstance } from '../../../models/video/video-interface' 9import { VideoInstance } from '../../../models/video/video-interface'
10import { Activity } from '../../../../shared/models/activitypub/activity'
11
12async function forwardActivity (
13 activity: Activity,
14 t: Transaction,
15 followersException: AccountInstance[] = []
16) {
17 const to = activity.to || []
18 const cc = activity.cc || []
19
20 const followersUrls: string[] = []
21 for (const dest of to.concat(cc)) {
22 if (dest.endsWith('/followers')) {
23 followersUrls.push(dest)
24 }
25 }
26
27 const toAccountFollowers = await db.Account.listByFollowersUrls(followersUrls)
28 const uris = await computeFollowerUris(toAccountFollowers, followersException)
29
30 if (uris.length === 0) {
31 logger.info('0 followers for %s, no forwarding.', toAccountFollowers.map(a => a.id).join(', '))
32 return
33 }
34
35 logger.debug('Creating forwarding job.', { uris })
36
37 const jobPayload: ActivityPubHttpPayload = {
38 uris,
39 body: activity
40 }
41
42 return activitypubHttpJobScheduler.createJob(t, 'activitypubHttpBroadcastHandler', jobPayload)
43}
7 44
8async function broadcastToFollowers ( 45async function broadcastToFollowers (
9 data: any, 46 data: any,
@@ -12,18 +49,15 @@ async function broadcastToFollowers (
12 t: Transaction, 49 t: Transaction,
13 followersException: AccountInstance[] = [] 50 followersException: AccountInstance[] = []
14) { 51) {
15 const toAccountFollowerIds = toAccountFollowers.map(a => a.id) 52 const uris = await computeFollowerUris(toAccountFollowers, followersException)
16 53 if (uris.length === 0) {
17 const result = await db.AccountFollow.listAcceptedFollowerSharedInboxUrls(toAccountFollowerIds) 54 logger.info('0 followers for %s, no broadcasting.', toAccountFollowers.map(a => a.id).join(', '))
18 if (result.data.length === 0) { 55 return
19 logger.info('Not broadcast because of 0 followers for %s.', toAccountFollowerIds.join(', '))
20 return undefined
21 } 56 }
22 57
23 const followersSharedInboxException = followersException.map(f => f.sharedInboxUrl) 58 logger.debug('Creating broadcast job.', { uris })
24 const uris = result.data.filter(sharedInbox => followersSharedInboxException.indexOf(sharedInbox) === -1)
25 59
26 const jobPayload = { 60 const jobPayload: ActivityPubHttpPayload = {
27 uris, 61 uris,
28 signatureAccountId: byAccount.id, 62 signatureAccountId: byAccount.id,
29 body: data 63 body: data
@@ -33,7 +67,9 @@ async function broadcastToFollowers (
33} 67}
34 68
35async function unicastTo (data: any, byAccount: AccountInstance, toAccountUrl: string, t: Transaction) { 69async function unicastTo (data: any, byAccount: AccountInstance, toAccountUrl: string, t: Transaction) {
36 const jobPayload = { 70 logger.debug('Creating unicast job.', { uri: toAccountUrl })
71
72 const jobPayload: ActivityPubHttpPayload = {
37 uris: [ toAccountUrl ], 73 uris: [ toAccountUrl ],
38 signatureAccountId: byAccount.id, 74 signatureAccountId: byAccount.id,
39 body: data 75 body: data
@@ -42,21 +78,21 @@ async function unicastTo (data: any, byAccount: AccountInstance, toAccountUrl: s
42 return activitypubHttpJobScheduler.createJob(t, 'activitypubHttpUnicastHandler', jobPayload) 78 return activitypubHttpJobScheduler.createJob(t, 'activitypubHttpUnicastHandler', jobPayload)
43} 79}
44 80
45function getOriginVideoAudience (video: VideoInstance) { 81function getOriginVideoAudience (video: VideoInstance, accountsInvolvedInVideo: AccountInstance[]) {
46 return { 82 return {
47 to: [ video.VideoChannel.Account.url ], 83 to: [ video.VideoChannel.Account.url ],
48 cc: [ video.VideoChannel.Account.url + '/followers' ] 84 cc: accountsInvolvedInVideo.map(a => a.followersUrl)
49 } 85 }
50} 86}
51 87
52function getVideoFollowersAudience (video: VideoInstance) { 88function getVideoFollowersAudience (accountsInvolvedInVideo: AccountInstance[]) {
53 return { 89 return {
54 to: [ video.VideoChannel.Account.url + '/followers' ], 90 to: accountsInvolvedInVideo.map(a => a.followersUrl),
55 cc: [] 91 cc: []
56 } 92 }
57} 93}
58 94
59async function getAccountsToForwardVideoAction (byAccount: AccountInstance, video: VideoInstance) { 95async function getAccountsInvolvedInVideo (video: VideoInstance) {
60 const accountsToForwardView = await db.VideoShare.loadAccountsByShare(video.id) 96 const accountsToForwardView = await db.VideoShare.loadAccountsByShare(video.id)
61 accountsToForwardView.push(video.VideoChannel.Account) 97 accountsToForwardView.push(video.VideoChannel.Account)
62 98
@@ -81,6 +117,16 @@ async function getAudience (accountSender: AccountInstance, isPublic = true) {
81 return { to, cc } 117 return { to, cc }
82} 118}
83 119
120async function computeFollowerUris (toAccountFollower: AccountInstance[], followersException: AccountInstance[]) {
121 const toAccountFollowerIds = toAccountFollower.map(a => a.id)
122
123 const result = await db.AccountFollow.listAcceptedFollowerSharedInboxUrls(toAccountFollowerIds)
124 const followersSharedInboxException = followersException.map(f => f.sharedInboxUrl)
125 const uris = result.data.filter(sharedInbox => followersSharedInboxException.indexOf(sharedInbox) === -1)
126
127 return uris
128}
129
84// --------------------------------------------------------------------------- 130// ---------------------------------------------------------------------------
85 131
86export { 132export {
@@ -88,6 +134,7 @@ export {
88 unicastTo, 134 unicastTo,
89 getAudience, 135 getAudience,
90 getOriginVideoAudience, 136 getOriginVideoAudience,
91 getAccountsToForwardVideoAction, 137 getAccountsInvolvedInVideo,
92 getVideoFollowersAudience 138 getVideoFollowersAudience,
139 forwardActivity
93} 140}
diff --git a/server/lib/activitypub/send/send-create.ts b/server/lib/activitypub/send/send-create.ts
index 6afe67ee6..113d89233 100644
--- a/server/lib/activitypub/send/send-create.ts
+++ b/server/lib/activitypub/send/send-create.ts
@@ -1,12 +1,12 @@
1import { Transaction } from 'sequelize' 1import { Transaction } from 'sequelize'
2import { ActivityCreate } from '../../../../shared/models/activitypub/activity' 2import { ActivityAudience, ActivityCreate } from '../../../../shared/models/activitypub/activity'
3import { getServerAccount } from '../../../helpers/utils' 3import { getServerAccount } from '../../../helpers/utils'
4import { AccountInstance, VideoChannelInstance, VideoInstance } from '../../../models' 4import { AccountInstance, VideoChannelInstance, VideoInstance } from '../../../models'
5import { VideoAbuseInstance } from '../../../models/video/video-abuse-interface' 5import { VideoAbuseInstance } from '../../../models/video/video-abuse-interface'
6import { getVideoAbuseActivityPubUrl, getVideoDislikeActivityPubUrl, getVideoViewActivityPubUrl } from '../url' 6import { getVideoAbuseActivityPubUrl, getVideoDislikeActivityPubUrl, getVideoViewActivityPubUrl } from '../url'
7import { 7import {
8 broadcastToFollowers, 8 broadcastToFollowers,
9 getAccountsToForwardVideoAction, 9 getAccountsInvolvedInVideo,
10 getAudience, 10 getAudience,
11 getOriginVideoAudience, 11 getOriginVideoAudience,
12 getVideoFollowersAudience, 12 getVideoFollowersAudience,
@@ -35,7 +35,8 @@ async function sendCreateViewToOrigin (byAccount: AccountInstance, video: VideoI
35 const url = getVideoViewActivityPubUrl(byAccount, video) 35 const url = getVideoViewActivityPubUrl(byAccount, video)
36 const viewActivity = createViewActivityData(byAccount, video) 36 const viewActivity = createViewActivityData(byAccount, video)
37 37
38 const audience = getOriginVideoAudience(video) 38 const accountsInvolvedInVideo = await getAccountsInvolvedInVideo(video)
39 const audience = getOriginVideoAudience(video, accountsInvolvedInVideo)
39 const data = await createActivityData(url, byAccount, viewActivity, audience) 40 const data = await createActivityData(url, byAccount, viewActivity, audience)
40 41
41 return unicastTo(data, byAccount, video.VideoChannel.Account.sharedInboxUrl, t) 42 return unicastTo(data, byAccount, video.VideoChannel.Account.sharedInboxUrl, t)
@@ -45,12 +46,12 @@ async function sendCreateViewToVideoFollowers (byAccount: AccountInstance, video
45 const url = getVideoViewActivityPubUrl(byAccount, video) 46 const url = getVideoViewActivityPubUrl(byAccount, video)
46 const viewActivity = createViewActivityData(byAccount, video) 47 const viewActivity = createViewActivityData(byAccount, video)
47 48
48 const audience = getVideoFollowersAudience(video) 49 const accountsToForwardView = await getAccountsInvolvedInVideo(video)
50 const audience = getVideoFollowersAudience(accountsToForwardView)
49 const data = await createActivityData(url, byAccount, viewActivity, audience) 51 const data = await createActivityData(url, byAccount, viewActivity, audience)
50 52
53 // Use the server account to send the view, because it could be an unregistered account
51 const serverAccount = await getServerAccount() 54 const serverAccount = await getServerAccount()
52 const accountsToForwardView = await getAccountsToForwardVideoAction(byAccount, video)
53
54 const followersException = [ byAccount ] 55 const followersException = [ byAccount ]
55 return broadcastToFollowers(data, serverAccount, accountsToForwardView, t, followersException) 56 return broadcastToFollowers(data, serverAccount, accountsToForwardView, t, followersException)
56} 57}
@@ -59,7 +60,8 @@ async function sendCreateDislikeToOrigin (byAccount: AccountInstance, video: Vid
59 const url = getVideoDislikeActivityPubUrl(byAccount, video) 60 const url = getVideoDislikeActivityPubUrl(byAccount, video)
60 const dislikeActivity = createDislikeActivityData(byAccount, video) 61 const dislikeActivity = createDislikeActivityData(byAccount, video)
61 62
62 const audience = getOriginVideoAudience(video) 63 const accountsInvolvedInVideo = await getAccountsInvolvedInVideo(video)
64 const audience = getOriginVideoAudience(video, accountsInvolvedInVideo)
63 const data = await createActivityData(url, byAccount, dislikeActivity, audience) 65 const data = await createActivityData(url, byAccount, dislikeActivity, audience)
64 66
65 return unicastTo(data, byAccount, video.VideoChannel.Account.sharedInboxUrl, t) 67 return unicastTo(data, byAccount, video.VideoChannel.Account.sharedInboxUrl, t)
@@ -69,17 +71,15 @@ async function sendCreateDislikeToVideoFollowers (byAccount: AccountInstance, vi
69 const url = getVideoDislikeActivityPubUrl(byAccount, video) 71 const url = getVideoDislikeActivityPubUrl(byAccount, video)
70 const dislikeActivity = createDislikeActivityData(byAccount, video) 72 const dislikeActivity = createDislikeActivityData(byAccount, video)
71 73
72 const audience = getVideoFollowersAudience(video) 74 const accountsToForwardView = await getAccountsInvolvedInVideo(video)
75 const audience = getVideoFollowersAudience(accountsToForwardView)
73 const data = await createActivityData(url, byAccount, dislikeActivity, audience) 76 const data = await createActivityData(url, byAccount, dislikeActivity, audience)
74 77
75 const accountsToForwardView = await getAccountsToForwardVideoAction(byAccount, video)
76 const serverAccount = await getServerAccount()
77
78 const followersException = [ byAccount ] 78 const followersException = [ byAccount ]
79 return broadcastToFollowers(data, serverAccount, accountsToForwardView, t, followersException) 79 return broadcastToFollowers(data, byAccount, accountsToForwardView, t, followersException)
80} 80}
81 81
82async function createActivityData (url: string, byAccount: AccountInstance, object: any, audience?: { to: string[], cc: string[] }) { 82async function createActivityData (url: string, byAccount: AccountInstance, object: any, audience?: ActivityAudience) {
83 if (!audience) { 83 if (!audience) {
84 audience = await getAudience(byAccount) 84 audience = await getAudience(byAccount)
85 } 85 }
diff --git a/server/lib/activitypub/send/send-like.ts b/server/lib/activitypub/send/send-like.ts
index 70a7d886f..8ca775bf3 100644
--- a/server/lib/activitypub/send/send-like.ts
+++ b/server/lib/activitypub/send/send-like.ts
@@ -1,11 +1,10 @@
1import { Transaction } from 'sequelize' 1import { Transaction } from 'sequelize'
2import { ActivityLike } from '../../../../shared/models/activitypub/activity' 2import { ActivityLike } from '../../../../shared/models/activitypub/activity'
3import { getServerAccount } from '../../../helpers/utils'
4import { AccountInstance, VideoInstance } from '../../../models' 3import { AccountInstance, VideoInstance } from '../../../models'
5import { getVideoLikeActivityPubUrl } from '../url' 4import { getVideoLikeActivityPubUrl } from '../url'
6import { 5import {
7 broadcastToFollowers, 6 broadcastToFollowers,
8 getAccountsToForwardVideoAction, 7 getAccountsInvolvedInVideo,
9 getAudience, 8 getAudience,
10 getOriginVideoAudience, 9 getOriginVideoAudience,
11 getVideoFollowersAudience, 10 getVideoFollowersAudience,
@@ -15,7 +14,8 @@ import {
15async function sendLikeToOrigin (byAccount: AccountInstance, video: VideoInstance, t: Transaction) { 14async function sendLikeToOrigin (byAccount: AccountInstance, video: VideoInstance, t: Transaction) {
16 const url = getVideoLikeActivityPubUrl(byAccount, video) 15 const url = getVideoLikeActivityPubUrl(byAccount, video)
17 16
18 const audience = getOriginVideoAudience(video) 17 const accountsInvolvedInVideo = await getAccountsInvolvedInVideo(video)
18 const audience = getOriginVideoAudience(video, accountsInvolvedInVideo)
19 const data = await likeActivityData(url, byAccount, video, audience) 19 const data = await likeActivityData(url, byAccount, video, audience)
20 20
21 return unicastTo(data, byAccount, video.VideoChannel.Account.sharedInboxUrl, t) 21 return unicastTo(data, byAccount, video.VideoChannel.Account.sharedInboxUrl, t)
@@ -24,14 +24,14 @@ async function sendLikeToOrigin (byAccount: AccountInstance, video: VideoInstanc
24async function sendLikeToVideoFollowers (byAccount: AccountInstance, video: VideoInstance, t: Transaction) { 24async function sendLikeToVideoFollowers (byAccount: AccountInstance, video: VideoInstance, t: Transaction) {
25 const url = getVideoLikeActivityPubUrl(byAccount, video) 25 const url = getVideoLikeActivityPubUrl(byAccount, video)
26 26
27 const audience = getVideoFollowersAudience(video) 27 const accountsInvolvedInVideo = await getAccountsInvolvedInVideo(video)
28 const audience = getVideoFollowersAudience(accountsInvolvedInVideo)
28 const data = await likeActivityData(url, byAccount, video, audience) 29 const data = await likeActivityData(url, byAccount, video, audience)
29 30
30 const accountsToForwardView = await getAccountsToForwardVideoAction(byAccount, video) 31 const toAccountsFollowers = await getAccountsInvolvedInVideo(video)
31 const serverAccount = await getServerAccount()
32 32
33 const followersException = [ byAccount ] 33 const followersException = [ byAccount ]
34 return broadcastToFollowers(data, serverAccount, accountsToForwardView, t, followersException) 34 return broadcastToFollowers(data, byAccount, toAccountsFollowers, t, followersException)
35} 35}
36 36
37async function likeActivityData (url: string, byAccount: AccountInstance, video: VideoInstance, audience?: { to: string[], cc: string[] }) { 37async function likeActivityData (url: string, byAccount: AccountInstance, video: VideoInstance, audience?: { to: string[], cc: string[] }) {
diff --git a/server/lib/activitypub/send/send-undo.ts b/server/lib/activitypub/send/send-undo.ts
index 8f46a051e..79fc113f0 100644
--- a/server/lib/activitypub/send/send-undo.ts
+++ b/server/lib/activitypub/send/send-undo.ts
@@ -1,11 +1,16 @@
1import { Transaction } from 'sequelize' 1import { Transaction } from 'sequelize'
2import { ActivityCreate, ActivityFollow, ActivityLike, ActivityUndo } from '../../../../shared/models/activitypub/activity' 2import {
3import { getServerAccount } from '../../../helpers/utils' 3 ActivityAudience,
4 ActivityCreate,
5 ActivityFollow,
6 ActivityLike,
7 ActivityUndo
8} from '../../../../shared/models/activitypub/activity'
4import { AccountInstance } from '../../../models' 9import { AccountInstance } from '../../../models'
5import { AccountFollowInstance } from '../../../models/account/account-follow-interface' 10import { AccountFollowInstance } from '../../../models/account/account-follow-interface'
6import { VideoInstance } from '../../../models/video/video-interface' 11import { VideoInstance } from '../../../models/video/video-interface'
7import { getAccountFollowActivityPubUrl, getUndoActivityPubUrl, getVideoDislikeActivityPubUrl, getVideoLikeActivityPubUrl } from '../url' 12import { getAccountFollowActivityPubUrl, getUndoActivityPubUrl, getVideoDislikeActivityPubUrl, getVideoLikeActivityPubUrl } from '../url'
8import { broadcastToFollowers, getAccountsToForwardVideoAction, unicastTo } from './misc' 13import { broadcastToFollowers, getAccountsInvolvedInVideo, getAudience, getVideoFollowersAudience, unicastTo } from './misc'
9import { createActivityData, createDislikeActivityData } from './send-create' 14import { createActivityData, createDislikeActivityData } from './send-create'
10import { followActivityData } from './send-follow' 15import { followActivityData } from './send-follow'
11import { likeActivityData } from './send-like' 16import { likeActivityData } from './send-like'
@@ -37,14 +42,13 @@ async function sendUndoLikeToVideoFollowers (byAccount: AccountInstance, video:
37 const likeUrl = getVideoLikeActivityPubUrl(byAccount, video) 42 const likeUrl = getVideoLikeActivityPubUrl(byAccount, video)
38 const undoUrl = getUndoActivityPubUrl(likeUrl) 43 const undoUrl = getUndoActivityPubUrl(likeUrl)
39 44
45 const toAccountsFollowers = await getAccountsInvolvedInVideo(video)
46 const audience = getVideoFollowersAudience(toAccountsFollowers)
40 const object = await likeActivityData(likeUrl, byAccount, video) 47 const object = await likeActivityData(likeUrl, byAccount, video)
41 const data = await undoActivityData(undoUrl, byAccount, object) 48 const data = await undoActivityData(undoUrl, byAccount, object, audience)
42
43 const accountsToForwardView = await getAccountsToForwardVideoAction(byAccount, video)
44 const serverAccount = await getServerAccount()
45 49
46 const followersException = [ byAccount ] 50 const followersException = [ byAccount ]
47 return broadcastToFollowers(data, serverAccount, accountsToForwardView, t, followersException) 51 return broadcastToFollowers(data, byAccount, toAccountsFollowers, t, followersException)
48} 52}
49 53
50async function sendUndoDislikeToOrigin (byAccount: AccountInstance, video: VideoInstance, t: Transaction) { 54async function sendUndoDislikeToOrigin (byAccount: AccountInstance, video: VideoInstance, t: Transaction) {
@@ -68,11 +72,10 @@ async function sendUndoDislikeToVideoFollowers (byAccount: AccountInstance, vide
68 72
69 const data = await undoActivityData(undoUrl, byAccount, object) 73 const data = await undoActivityData(undoUrl, byAccount, object)
70 74
71 const accountsToForwardView = await getAccountsToForwardVideoAction(byAccount, video) 75 const toAccountsFollowers = await getAccountsInvolvedInVideo(video)
72 const serverAccount = await getServerAccount()
73 76
74 const followersException = [ byAccount ] 77 const followersException = [ byAccount ]
75 return broadcastToFollowers(data, serverAccount, accountsToForwardView, t, followersException) 78 return broadcastToFollowers(data, byAccount, toAccountsFollowers, t, followersException)
76} 79}
77 80
78// --------------------------------------------------------------------------- 81// ---------------------------------------------------------------------------
@@ -87,11 +90,22 @@ export {
87 90
88// --------------------------------------------------------------------------- 91// ---------------------------------------------------------------------------
89 92
90async function undoActivityData (url: string, byAccount: AccountInstance, object: ActivityFollow | ActivityLike | ActivityCreate) { 93async function undoActivityData (
94 url: string,
95 byAccount: AccountInstance,
96 object: ActivityFollow | ActivityLike | ActivityCreate,
97 audience?: ActivityAudience
98) {
99 if (!audience) {
100 audience = await getAudience(byAccount)
101 }
102
91 const activity: ActivityUndo = { 103 const activity: ActivityUndo = {
92 type: 'Undo', 104 type: 'Undo',
93 id: url, 105 id: url,
94 actor: byAccount.url, 106 actor: byAccount.url,
107 to: audience.to,
108 cc: audience.cc,
95 object 109 object
96 } 110 }
97 111