aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib/activitypub
diff options
context:
space:
mode:
Diffstat (limited to 'server/lib/activitypub')
-rw-r--r--server/lib/activitypub/process-accept.ts27
-rw-r--r--server/lib/activitypub/process-delete.ts105
-rw-r--r--server/lib/activitypub/process-follow.ts32
-rw-r--r--server/lib/activitypub/send-request.ts26
4 files changed, 178 insertions, 12 deletions
diff --git a/server/lib/activitypub/process-accept.ts b/server/lib/activitypub/process-accept.ts
new file mode 100644
index 000000000..37e42bd3a
--- /dev/null
+++ b/server/lib/activitypub/process-accept.ts
@@ -0,0 +1,27 @@
1import { ActivityAccept } from '../../../shared/models/activitypub/activity'
2import { database as db } from '../../initializers'
3import { AccountInstance } from '../../models/account/account-interface'
4
5async function processAcceptActivity (activity: ActivityAccept, inboxAccount?: AccountInstance) {
6 if (inboxAccount === undefined) throw new Error('Need to accept on explicit inbox.')
7
8 const targetAccount = await db.Account.loadByUrl(activity.actor)
9
10 return processFollow(inboxAccount, targetAccount)
11}
12
13// ---------------------------------------------------------------------------
14
15export {
16 processAcceptActivity
17}
18
19// ---------------------------------------------------------------------------
20
21async function processFollow (account: AccountInstance, targetAccount: AccountInstance) {
22 const follow = await db.AccountFollow.loadByAccountAndTarget(account.id, targetAccount.id)
23 if (!follow) throw new Error('Cannot find associated follow.')
24
25 follow.set('state', 'accepted')
26 return follow.save()
27}
diff --git a/server/lib/activitypub/process-delete.ts b/server/lib/activitypub/process-delete.ts
new file mode 100644
index 000000000..377df432d
--- /dev/null
+++ b/server/lib/activitypub/process-delete.ts
@@ -0,0 +1,105 @@
1import { ActivityDelete } from '../../../shared/models/activitypub/activity'
2import { getOrCreateAccount } from '../../helpers/activitypub'
3import { retryTransactionWrapper } from '../../helpers/database-utils'
4import { logger } from '../../helpers/logger'
5import { database as db } from '../../initializers'
6import { AccountInstance } from '../../models/account/account-interface'
7import { VideoChannelInstance } from '../../models/video/video-channel-interface'
8import { VideoInstance } from '../../models/video/video-interface'
9
10async function processDeleteActivity (activity: ActivityDelete) {
11 const account = await getOrCreateAccount(activity.actor)
12
13 if (account.url === activity.id) {
14 return processDeleteAccount(account)
15 }
16
17 {
18 let videoObject = await db.Video.loadByUrl(activity.id)
19 if (videoObject !== undefined) {
20 return processDeleteVideo(account, videoObject)
21 }
22 }
23
24 {
25 let videoChannelObject = await db.VideoChannel.loadByUrl(activity.id)
26 if (videoChannelObject !== undefined) {
27 return processDeleteVideoChannel(account, videoChannelObject)
28 }
29 }
30
31 return undefined
32}
33
34// ---------------------------------------------------------------------------
35
36export {
37 processDeleteActivity
38}
39
40// ---------------------------------------------------------------------------
41
42async function processDeleteVideo (account: AccountInstance, videoToDelete: VideoInstance) {
43 const options = {
44 arguments: [ account, videoToDelete ],
45 errorMessage: 'Cannot remove the remote video with many retries.'
46 }
47
48 await retryTransactionWrapper(deleteRemoteVideo, options)
49}
50
51async function deleteRemoteVideo (account: AccountInstance, videoToDelete: VideoInstance) {
52 logger.debug('Removing remote video "%s".', videoToDelete.uuid)
53
54 await db.sequelize.transaction(async t => {
55 if (videoToDelete.VideoChannel.Account.id !== account.id) {
56 throw new Error('Account ' + account.url + ' does not own video channel ' + videoToDelete.VideoChannel.url)
57 }
58
59 await videoToDelete.destroy({ transaction: t })
60 })
61
62 logger.info('Remote video with uuid %s removed.', videoToDelete.uuid)
63}
64
65async function processDeleteVideoChannel (account: AccountInstance, videoChannelToRemove: VideoChannelInstance) {
66 const options = {
67 arguments: [ account, videoChannelToRemove ],
68 errorMessage: 'Cannot remove the remote video channel with many retries.'
69 }
70
71 await retryTransactionWrapper(deleteRemoteVideoChannel, options)
72}
73
74async function deleteRemoteVideoChannel (account: AccountInstance, videoChannelToRemove: VideoChannelInstance) {
75 logger.debug('Removing remote video channel "%s".', videoChannelToRemove.uuid)
76
77 await db.sequelize.transaction(async t => {
78 if (videoChannelToRemove.Account.id !== account.id) {
79 throw new Error('Account ' + account.url + ' does not own video channel ' + videoChannelToRemove.url)
80 }
81
82 await videoChannelToRemove.destroy({ transaction: t })
83 })
84
85 logger.info('Remote video channel with uuid %s removed.', videoChannelToRemove.uuid)
86}
87
88async function processDeleteAccount (accountToRemove: AccountInstance) {
89 const options = {
90 arguments: [ accountToRemove ],
91 errorMessage: 'Cannot remove the remote account with many retries.'
92 }
93
94 await retryTransactionWrapper(deleteRemoteAccount, options)
95}
96
97async function deleteRemoteAccount (accountToRemove: AccountInstance) {
98 logger.debug('Removing remote account "%s".', accountToRemove.uuid)
99
100 await db.sequelize.transaction(async t => {
101 await accountToRemove.destroy({ transaction: t })
102 })
103
104 logger.info('Remote account with uuid %s removed.', accountToRemove.uuid)
105}
diff --git a/server/lib/activitypub/process-follow.ts b/server/lib/activitypub/process-follow.ts
new file mode 100644
index 000000000..a04fc7994
--- /dev/null
+++ b/server/lib/activitypub/process-follow.ts
@@ -0,0 +1,32 @@
1import { ActivityFollow } from '../../../shared/models/activitypub/activity'
2import { getOrCreateAccount } from '../../helpers'
3import { database as db } from '../../initializers'
4import { AccountInstance } from '../../models/account/account-interface'
5
6async function processFollowActivity (activity: ActivityFollow) {
7 const activityObject = activity.object
8 const account = await getOrCreateAccount(activity.actor)
9
10 return processFollow(account, activityObject)
11}
12
13// ---------------------------------------------------------------------------
14
15export {
16 processFollowActivity
17}
18
19// ---------------------------------------------------------------------------
20
21async function processFollow (account: AccountInstance, targetAccountURL: string) {
22 const targetAccount = await db.Account.loadByUrl(targetAccountURL)
23
24 if (targetAccount === undefined) throw new Error('Unknown account')
25 if (targetAccount.isOwned() === false) throw new Error('This is not a local account.')
26
27 return db.AccountFollow.create({
28 accountId: account.id,
29 targetAccountId: targetAccount.id,
30 state: 'accepted'
31 })
32}
diff --git a/server/lib/activitypub/send-request.ts b/server/lib/activitypub/send-request.ts
index 91101f5ad..ce9a96f14 100644
--- a/server/lib/activitypub/send-request.ts
+++ b/server/lib/activitypub/send-request.ts
@@ -25,8 +25,7 @@ function sendUpdateVideoChannel (videoChannel: VideoChannelInstance, t: Sequeliz
25} 25}
26 26
27function sendDeleteVideoChannel (videoChannel: VideoChannelInstance, t: Sequelize.Transaction) { 27function sendDeleteVideoChannel (videoChannel: VideoChannelInstance, t: Sequelize.Transaction) {
28 const videoChannelObject = videoChannel.toActivityPubObject() 28 const data = deleteActivityData(videoChannel.url, videoChannel.Account)
29 const data = deleteActivityData(videoChannel.url, videoChannel.Account, videoChannelObject)
30 29
31 return broadcastToFollowers(data, videoChannel.Account, t) 30 return broadcastToFollowers(data, videoChannel.Account, t)
32} 31}
@@ -46,12 +45,17 @@ function sendUpdateVideo (video: VideoInstance, t: Sequelize.Transaction) {
46} 45}
47 46
48function sendDeleteVideo (video: VideoInstance, t: Sequelize.Transaction) { 47function sendDeleteVideo (video: VideoInstance, t: Sequelize.Transaction) {
49 const videoObject = video.toActivityPubObject() 48 const data = deleteActivityData(video.url, video.VideoChannel.Account)
50 const data = deleteActivityData(video.url, video.VideoChannel.Account, videoObject)
51 49
52 return broadcastToFollowers(data, video.VideoChannel.Account, t) 50 return broadcastToFollowers(data, video.VideoChannel.Account, t)
53} 51}
54 52
53function sendDeleteAccount (account: AccountInstance, t: Sequelize.Transaction) {
54 const data = deleteActivityData(account.url, account)
55
56 return broadcastToFollowers(data, account, t)
57}
58
55// --------------------------------------------------------------------------- 59// ---------------------------------------------------------------------------
56 60
57export { 61export {
@@ -60,13 +64,14 @@ export {
60 sendDeleteVideoChannel, 64 sendDeleteVideoChannel,
61 sendAddVideo, 65 sendAddVideo,
62 sendUpdateVideo, 66 sendUpdateVideo,
63 sendDeleteVideo 67 sendDeleteVideo,
68 sendDeleteAccount
64} 69}
65 70
66// --------------------------------------------------------------------------- 71// ---------------------------------------------------------------------------
67 72
68async function broadcastToFollowers (data: any, fromAccount: AccountInstance, t: Sequelize.Transaction) { 73async function broadcastToFollowers (data: any, fromAccount: AccountInstance, t: Sequelize.Transaction) {
69 const result = await db.Account.listFollowerUrlsForApi(fromAccount.name, 0) 74 const result = await db.Account.listFollowerUrlsForApi(fromAccount.id, 0)
70 75
71 const jobPayload = { 76 const jobPayload = {
72 uris: result.data, 77 uris: result.data,
@@ -114,14 +119,11 @@ async function updateActivityData (url: string, byAccount: AccountInstance, obje
114 return buildSignedActivity(byAccount, base) 119 return buildSignedActivity(byAccount, base)
115} 120}
116 121
117async function deleteActivityData (url: string, byAccount: AccountInstance, object: any) { 122async function deleteActivityData (url: string, byAccount: AccountInstance) {
118 const to = await getPublicActivityTo(byAccount)
119 const base = { 123 const base = {
120 type: 'Update', 124 type: 'Delete',
121 id: url, 125 id: url,
122 actor: byAccount.url, 126 actor: byAccount.url
123 to,
124 object
125 } 127 }
126 128
127 return buildSignedActivity(byAccount, base) 129 return buildSignedActivity(byAccount, base)