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/index.ts7
-rw-r--r--server/lib/activitypub/send/misc.ts58
-rw-r--r--server/lib/activitypub/send/send-accept.ts34
-rw-r--r--server/lib/activitypub/send/send-add.ts38
-rw-r--r--server/lib/activitypub/send/send-announce.ts45
-rw-r--r--server/lib/activitypub/send/send-create.ts44
-rw-r--r--server/lib/activitypub/send/send-delete.ts53
-rw-r--r--server/lib/activitypub/send/send-follow.ts34
-rw-r--r--server/lib/activitypub/send/send-undo.ts39
-rw-r--r--server/lib/activitypub/send/send-update.ts55
10 files changed, 407 insertions, 0 deletions
diff --git a/server/lib/activitypub/send/index.ts b/server/lib/activitypub/send/index.ts
new file mode 100644
index 000000000..5f15dd4b5
--- /dev/null
+++ b/server/lib/activitypub/send/index.ts
@@ -0,0 +1,7 @@
1export * from './send-accept'
2export * from './send-add'
3export * from './send-announce'
4export * from './send-create'
5export * from './send-delete'
6export * from './send-follow'
7export * from './send-update'
diff --git a/server/lib/activitypub/send/misc.ts b/server/lib/activitypub/send/misc.ts
new file mode 100644
index 000000000..bea955b67
--- /dev/null
+++ b/server/lib/activitypub/send/misc.ts
@@ -0,0 +1,58 @@
1import { Transaction } from 'sequelize'
2import { logger } from '../../../helpers/logger'
3import { ACTIVITY_PUB, database as db } from '../../../initializers'
4import { AccountInstance } from '../../../models/account/account-interface'
5import { activitypubHttpJobScheduler } from '../../jobs/activitypub-http-job-scheduler/activitypub-http-job-scheduler'
6
7async function broadcastToFollowers (data: any, byAccount: AccountInstance, toAccountFollowers: AccountInstance[], t: Transaction) {
8 const toAccountFollowerIds = toAccountFollowers.map(a => a.id)
9 const result = await db.AccountFollow.listAcceptedFollowerSharedInboxUrls(toAccountFollowerIds)
10 if (result.data.length === 0) {
11 logger.info('Not broadcast because of 0 followers for %s.', toAccountFollowerIds.join(', '))
12 return undefined
13 }
14
15 const jobPayload = {
16 uris: result.data,
17 signatureAccountId: byAccount.id,
18 body: data
19 }
20
21 return activitypubHttpJobScheduler.createJob(t, 'activitypubHttpBroadcastHandler', jobPayload)
22}
23
24async function unicastTo (data: any, byAccount: AccountInstance, toAccountUrl: string, t: Transaction) {
25 const jobPayload = {
26 uris: [ toAccountUrl ],
27 signatureAccountId: byAccount.id,
28 body: data
29 }
30
31 return activitypubHttpJobScheduler.createJob(t, 'activitypubHttpUnicastHandler', jobPayload)
32}
33
34async function getAudience (accountSender: AccountInstance, isPublic = true) {
35 const followerInboxUrls = await accountSender.getFollowerSharedInboxUrls()
36
37 // Thanks Mastodon: https://github.com/tootsuite/mastodon/blob/master/app/lib/activitypub/tag_manager.rb#L47
38 let to = []
39 let cc = []
40
41 if (isPublic) {
42 to = [ ACTIVITY_PUB.PUBLIC ]
43 cc = followerInboxUrls
44 } else { // Unlisted
45 to = followerInboxUrls
46 cc = [ ACTIVITY_PUB.PUBLIC ]
47 }
48
49 return { to, cc }
50}
51
52// ---------------------------------------------------------------------------
53
54export {
55 broadcastToFollowers,
56 unicastTo,
57 getAudience
58}
diff --git a/server/lib/activitypub/send/send-accept.ts b/server/lib/activitypub/send/send-accept.ts
new file mode 100644
index 000000000..0324a30fa
--- /dev/null
+++ b/server/lib/activitypub/send/send-accept.ts
@@ -0,0 +1,34 @@
1import { Transaction } from 'sequelize'
2import { ActivityAccept } from '../../../../shared/models/activitypub/activity'
3import { AccountInstance } from '../../../models'
4import { AccountFollowInstance } from '../../../models/account/account-follow-interface'
5import { unicastTo } from './misc'
6import { getAccountFollowAcceptActivityPubUrl } from '../../../helpers/activitypub'
7
8async function sendAccept (accountFollow: AccountFollowInstance, t: Transaction) {
9 const follower = accountFollow.AccountFollower
10 const me = accountFollow.AccountFollowing
11
12 const url = getAccountFollowAcceptActivityPubUrl(accountFollow)
13 const data = await acceptActivityData(url, me)
14
15 return unicastTo(data, me, follower.inboxUrl, t)
16}
17
18// ---------------------------------------------------------------------------
19
20export {
21 sendAccept
22}
23
24// ---------------------------------------------------------------------------
25
26async function acceptActivityData (url: string, byAccount: AccountInstance) {
27 const activity: ActivityAccept = {
28 type: 'Accept',
29 id: url,
30 actor: byAccount.url
31 }
32
33 return activity
34}
diff --git a/server/lib/activitypub/send/send-add.ts b/server/lib/activitypub/send/send-add.ts
new file mode 100644
index 000000000..3012b7533
--- /dev/null
+++ b/server/lib/activitypub/send/send-add.ts
@@ -0,0 +1,38 @@
1import { Transaction } from 'sequelize'
2import { ActivityAdd } from '../../../../shared/models/activitypub/activity'
3import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum'
4import { AccountInstance, VideoInstance } from '../../../models'
5import { broadcastToFollowers, getAudience } from './misc'
6
7async function sendAddVideo (video: VideoInstance, t: Transaction) {
8 const byAccount = video.VideoChannel.Account
9
10 const videoObject = video.toActivityPubObject()
11 const data = await addActivityData(video.url, byAccount, video, video.VideoChannel.url, videoObject)
12
13 return broadcastToFollowers(data, byAccount, [ byAccount ], t)
14}
15
16async function addActivityData (url: string, byAccount: AccountInstance, video: VideoInstance, target: string, object: any) {
17 const videoPublic = video.privacy === VideoPrivacy.PUBLIC
18
19 const { to, cc } = await getAudience(byAccount, videoPublic)
20 const activity: ActivityAdd = {
21 type: 'Add',
22 id: url,
23 actor: byAccount.url,
24 to,
25 cc,
26 object,
27 target
28 }
29
30 return activity
31}
32
33// ---------------------------------------------------------------------------
34
35export {
36 addActivityData,
37 sendAddVideo
38}
diff --git a/server/lib/activitypub/send/send-announce.ts b/server/lib/activitypub/send/send-announce.ts
new file mode 100644
index 000000000..b9217e4f6
--- /dev/null
+++ b/server/lib/activitypub/send/send-announce.ts
@@ -0,0 +1,45 @@
1import { Transaction } from 'sequelize'
2import { AccountInstance, VideoInstance } from '../../../models'
3import { VideoChannelInstance } from '../../../models/video/video-channel-interface'
4import { broadcastToFollowers } from './misc'
5import { addActivityData } from './send-add'
6import { createActivityData } from './send-create'
7import { getAnnounceActivityPubUrl } from '../../../helpers/activitypub'
8
9async function sendVideoAnnounce (byAccount: AccountInstance, video: VideoInstance, t: Transaction) {
10 const url = getAnnounceActivityPubUrl(video.url, byAccount)
11
12 const videoChannel = video.VideoChannel
13 const announcedActivity = await addActivityData(url, videoChannel.Account, video, videoChannel.url, video.toActivityPubObject())
14
15 const data = await announceActivityData(url, byAccount, announcedActivity)
16 return broadcastToFollowers(data, byAccount, [ byAccount ], t)
17}
18
19async function sendVideoChannelAnnounce (byAccount: AccountInstance, videoChannel: VideoChannelInstance, t: Transaction) {
20 const url = getAnnounceActivityPubUrl(videoChannel.url, byAccount)
21 const announcedActivity = await createActivityData(url, videoChannel.Account, videoChannel.toActivityPubObject())
22
23 const data = await announceActivityData(url, byAccount, announcedActivity)
24 return broadcastToFollowers(data, byAccount, [ byAccount ], t)
25}
26
27// ---------------------------------------------------------------------------
28
29export {
30 sendVideoAnnounce,
31 sendVideoChannelAnnounce
32}
33
34// ---------------------------------------------------------------------------
35
36async function announceActivityData (url: string, byAccount: AccountInstance, object: any) {
37 const activity = {
38 type: 'Announce',
39 id: url,
40 actor: byAccount.url,
41 object
42 }
43
44 return activity
45}
diff --git a/server/lib/activitypub/send/send-create.ts b/server/lib/activitypub/send/send-create.ts
new file mode 100644
index 000000000..66bfeee89
--- /dev/null
+++ b/server/lib/activitypub/send/send-create.ts
@@ -0,0 +1,44 @@
1import { Transaction } from 'sequelize'
2import { ActivityCreate } from '../../../../shared/models/activitypub/activity'
3import { AccountInstance, VideoChannelInstance, VideoInstance } from '../../../models'
4import { VideoAbuseInstance } from '../../../models/video/video-abuse-interface'
5import { broadcastToFollowers, getAudience, unicastTo } from './misc'
6import { getVideoAbuseActivityPubUrl } from '../../../helpers/activitypub'
7
8async function sendCreateVideoChannel (videoChannel: VideoChannelInstance, t: Transaction) {
9 const byAccount = videoChannel.Account
10
11 const videoChannelObject = videoChannel.toActivityPubObject()
12 const data = await createActivityData(videoChannel.url, byAccount, videoChannelObject)
13
14 return broadcastToFollowers(data, byAccount, [ byAccount ], t)
15}
16
17async function sendVideoAbuse (byAccount: AccountInstance, videoAbuse: VideoAbuseInstance, video: VideoInstance, t: Transaction) {
18 const url = getVideoAbuseActivityPubUrl(videoAbuse)
19 const data = await createActivityData(url, byAccount, videoAbuse.toActivityPubObject())
20
21 return unicastTo(data, byAccount, video.VideoChannel.Account.sharedInboxUrl, t)
22}
23
24async function createActivityData (url: string, byAccount: AccountInstance, object: any) {
25 const { to, cc } = await getAudience(byAccount)
26 const activity: ActivityCreate = {
27 type: 'Create',
28 id: url,
29 actor: byAccount.url,
30 to,
31 cc,
32 object
33 }
34
35 return activity
36}
37
38// ---------------------------------------------------------------------------
39
40export {
41 sendCreateVideoChannel,
42 sendVideoAbuse,
43 createActivityData
44}
diff --git a/server/lib/activitypub/send/send-delete.ts b/server/lib/activitypub/send/send-delete.ts
new file mode 100644
index 000000000..5be0e2d24
--- /dev/null
+++ b/server/lib/activitypub/send/send-delete.ts
@@ -0,0 +1,53 @@
1import { Transaction } from 'sequelize'
2import { ActivityDelete } from '../../../../shared/models/activitypub/activity'
3import { database as db } from '../../../initializers'
4import { AccountInstance, VideoChannelInstance, VideoInstance } from '../../../models'
5import { broadcastToFollowers } from './misc'
6
7async function sendDeleteVideoChannel (videoChannel: VideoChannelInstance, t: Transaction) {
8 const byAccount = videoChannel.Account
9
10 const data = await deleteActivityData(videoChannel.url, byAccount)
11
12 const accountsInvolved = await db.VideoChannelShare.loadAccountsByShare(videoChannel.id)
13 accountsInvolved.push(byAccount)
14
15 return broadcastToFollowers(data, byAccount, accountsInvolved, t)
16}
17
18async function sendDeleteVideo (video: VideoInstance, t: Transaction) {
19 const byAccount = video.VideoChannel.Account
20
21 const data = await deleteActivityData(video.url, byAccount)
22
23 const accountsInvolved = await db.VideoShare.loadAccountsByShare(video.id)
24 accountsInvolved.push(byAccount)
25
26 return broadcastToFollowers(data, byAccount, accountsInvolved, t)
27}
28
29async function sendDeleteAccount (account: AccountInstance, t: Transaction) {
30 const data = await deleteActivityData(account.url, account)
31
32 return broadcastToFollowers(data, account, [ account ], t)
33}
34
35// ---------------------------------------------------------------------------
36
37export {
38 sendDeleteVideoChannel,
39 sendDeleteVideo,
40 sendDeleteAccount
41}
42
43// ---------------------------------------------------------------------------
44
45async function deleteActivityData (url: string, byAccount: AccountInstance) {
46 const activity: ActivityDelete = {
47 type: 'Delete',
48 id: url,
49 actor: byAccount.url
50 }
51
52 return activity
53}
diff --git a/server/lib/activitypub/send/send-follow.ts b/server/lib/activitypub/send/send-follow.ts
new file mode 100644
index 000000000..48d641c22
--- /dev/null
+++ b/server/lib/activitypub/send/send-follow.ts
@@ -0,0 +1,34 @@
1import { Transaction } from 'sequelize'
2import { ActivityFollow } from '../../../../shared/models/activitypub/activity'
3import { AccountInstance } from '../../../models'
4import { AccountFollowInstance } from '../../../models/account/account-follow-interface'
5import { unicastTo } from './misc'
6import { getAccountFollowActivityPubUrl } from '../../../helpers/activitypub'
7
8async function sendFollow (accountFollow: AccountFollowInstance, t: Transaction) {
9 const me = accountFollow.AccountFollower
10 const following = accountFollow.AccountFollowing
11
12 const url = getAccountFollowActivityPubUrl(accountFollow)
13 const data = await followActivityData(url, me, following)
14
15 return unicastTo(data, me, following.inboxUrl, t)
16}
17
18async function followActivityData (url: string, byAccount: AccountInstance, targetAccount: AccountInstance) {
19 const activity: ActivityFollow = {
20 type: 'Follow',
21 id: url,
22 actor: byAccount.url,
23 object: targetAccount.url
24 }
25
26 return activity
27}
28
29// ---------------------------------------------------------------------------
30
31export {
32 sendFollow,
33 followActivityData
34}
diff --git a/server/lib/activitypub/send/send-undo.ts b/server/lib/activitypub/send/send-undo.ts
new file mode 100644
index 000000000..39da824f3
--- /dev/null
+++ b/server/lib/activitypub/send/send-undo.ts
@@ -0,0 +1,39 @@
1import { Transaction } from 'sequelize'
2import { ActivityFollow, ActivityUndo } from '../../../../shared/models/activitypub/activity'
3import { AccountInstance } from '../../../models'
4import { AccountFollowInstance } from '../../../models/account/account-follow-interface'
5import { unicastTo } from './misc'
6import { getAccountFollowActivityPubUrl, getUndoActivityPubUrl } from '../../../helpers/activitypub'
7import { followActivityData } from './send-follow'
8
9async function sendUndoFollow (accountFollow: AccountFollowInstance, t: Transaction) {
10 const me = accountFollow.AccountFollower
11 const following = accountFollow.AccountFollowing
12
13 const followUrl = getAccountFollowActivityPubUrl(accountFollow)
14 const undoUrl = getUndoActivityPubUrl(followUrl)
15
16 const object = await followActivityData(followUrl, me, following)
17 const data = await undoActivityData(undoUrl, me, object)
18
19 return unicastTo(data, me, following.inboxUrl, t)
20}
21
22// ---------------------------------------------------------------------------
23
24export {
25 sendUndoFollow
26}
27
28// ---------------------------------------------------------------------------
29
30async function undoActivityData (url: string, byAccount: AccountInstance, object: ActivityFollow) {
31 const activity: ActivityUndo = {
32 type: 'Undo',
33 id: url,
34 actor: byAccount.url,
35 object
36 }
37
38 return activity
39}
diff --git a/server/lib/activitypub/send/send-update.ts b/server/lib/activitypub/send/send-update.ts
new file mode 100644
index 000000000..42738f973
--- /dev/null
+++ b/server/lib/activitypub/send/send-update.ts
@@ -0,0 +1,55 @@
1import { Transaction } from 'sequelize'
2import { ActivityUpdate } from '../../../../shared/models/activitypub/activity'
3import { getUpdateActivityPubUrl } from '../../../helpers/activitypub'
4import { database as db } from '../../../initializers'
5import { AccountInstance, VideoChannelInstance, VideoInstance } from '../../../models'
6import { broadcastToFollowers, getAudience } from './misc'
7
8async function sendUpdateVideoChannel (videoChannel: VideoChannelInstance, t: Transaction) {
9 const byAccount = videoChannel.Account
10
11 const url = getUpdateActivityPubUrl(videoChannel.url, videoChannel.updatedAt.toISOString())
12 const videoChannelObject = videoChannel.toActivityPubObject()
13 const data = await updateActivityData(url, byAccount, videoChannelObject)
14
15 const accountsInvolved = await db.VideoChannelShare.loadAccountsByShare(videoChannel.id)
16 accountsInvolved.push(byAccount)
17
18 return broadcastToFollowers(data, byAccount, accountsInvolved, t)
19}
20
21async function sendUpdateVideo (video: VideoInstance, t: Transaction) {
22 const byAccount = video.VideoChannel.Account
23
24 const url = getUpdateActivityPubUrl(video.url, video.updatedAt.toISOString())
25 const videoObject = video.toActivityPubObject()
26 const data = await updateActivityData(url, byAccount, videoObject)
27
28 const accountsInvolved = await db.VideoShare.loadAccountsByShare(video.id)
29 accountsInvolved.push(byAccount)
30
31 return broadcastToFollowers(data, byAccount, accountsInvolved, t)
32}
33
34// ---------------------------------------------------------------------------
35
36export {
37 sendUpdateVideoChannel,
38 sendUpdateVideo
39}
40
41// ---------------------------------------------------------------------------
42
43async function updateActivityData (url: string, byAccount: AccountInstance, object: any) {
44 const { to, cc } = await getAudience(byAccount)
45 const activity: ActivityUpdate = {
46 type: 'Update',
47 id: url,
48 actor: byAccount.url,
49 to,
50 cc,
51 object
52 }
53
54 return activity
55}