diff options
Diffstat (limited to 'server/lib/activitypub/process/process-follow.ts')
-rw-r--r-- | server/lib/activitypub/process/process-follow.ts | 156 |
1 files changed, 0 insertions, 156 deletions
diff --git a/server/lib/activitypub/process/process-follow.ts b/server/lib/activitypub/process/process-follow.ts deleted file mode 100644 index 7def753d5..000000000 --- a/server/lib/activitypub/process/process-follow.ts +++ /dev/null | |||
@@ -1,156 +0,0 @@ | |||
1 | import { Transaction } from 'sequelize/types' | ||
2 | import { isBlockedByServerOrAccount } from '@server/lib/blocklist' | ||
3 | import { AccountModel } from '@server/models/account/account' | ||
4 | import { getServerActor } from '@server/models/application/application' | ||
5 | import { ActivityFollow } from '../../../../shared/models/activitypub' | ||
6 | import { retryTransactionWrapper } from '../../../helpers/database-utils' | ||
7 | import { logger } from '../../../helpers/logger' | ||
8 | import { CONFIG } from '../../../initializers/config' | ||
9 | import { sequelizeTypescript } from '../../../initializers/database' | ||
10 | import { getAPId } from '../../../lib/activitypub/activity' | ||
11 | import { ActorModel } from '../../../models/actor/actor' | ||
12 | import { ActorFollowModel } from '../../../models/actor/actor-follow' | ||
13 | import { APProcessorOptions } from '../../../types/activitypub-processor.model' | ||
14 | import { MActorFollow, MActorFull, MActorId, MActorSignature } from '../../../types/models' | ||
15 | import { Notifier } from '../../notifier' | ||
16 | import { autoFollowBackIfNeeded } from '../follow' | ||
17 | import { sendAccept, sendReject } from '../send' | ||
18 | |||
19 | async function processFollowActivity (options: APProcessorOptions<ActivityFollow>) { | ||
20 | const { activity, byActor } = options | ||
21 | |||
22 | const activityId = activity.id | ||
23 | const objectId = getAPId(activity.object) | ||
24 | |||
25 | return retryTransactionWrapper(processFollow, byActor, activityId, objectId) | ||
26 | } | ||
27 | |||
28 | // --------------------------------------------------------------------------- | ||
29 | |||
30 | export { | ||
31 | processFollowActivity | ||
32 | } | ||
33 | |||
34 | // --------------------------------------------------------------------------- | ||
35 | |||
36 | async function processFollow (byActor: MActorSignature, activityId: string, targetActorURL: string) { | ||
37 | const { actorFollow, created, targetActor } = await sequelizeTypescript.transaction(async t => { | ||
38 | const targetActor = await ActorModel.loadByUrlAndPopulateAccountAndChannel(targetActorURL, t) | ||
39 | |||
40 | if (!targetActor) throw new Error('Unknown actor') | ||
41 | if (targetActor.isOwned() === false) throw new Error('This is not a local actor.') | ||
42 | |||
43 | if (await rejectIfInstanceFollowDisabled(byActor, activityId, targetActor)) return { actorFollow: undefined } | ||
44 | if (await rejectIfMuted(byActor, activityId, targetActor)) return { actorFollow: undefined } | ||
45 | |||
46 | const [ actorFollow, created ] = await ActorFollowModel.findOrCreateCustom({ | ||
47 | byActor, | ||
48 | targetActor, | ||
49 | activityId, | ||
50 | state: await isFollowingInstance(targetActor) && CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL | ||
51 | ? 'pending' | ||
52 | : 'accepted', | ||
53 | transaction: t | ||
54 | }) | ||
55 | |||
56 | if (rejectIfAlreadyRejected(actorFollow, byActor, activityId, targetActor)) return { actorFollow: undefined } | ||
57 | |||
58 | await acceptIfNeeded(actorFollow, targetActor, t) | ||
59 | |||
60 | await fixFollowURLIfNeeded(actorFollow, activityId, t) | ||
61 | |||
62 | actorFollow.ActorFollower = byActor | ||
63 | actorFollow.ActorFollowing = targetActor | ||
64 | |||
65 | // Target sends to actor he accepted the follow request | ||
66 | if (actorFollow.state === 'accepted') { | ||
67 | sendAccept(actorFollow) | ||
68 | |||
69 | await autoFollowBackIfNeeded(actorFollow, t) | ||
70 | } | ||
71 | |||
72 | return { actorFollow, created, targetActor } | ||
73 | }) | ||
74 | |||
75 | // Rejected | ||
76 | if (!actorFollow) return | ||
77 | |||
78 | if (created) { | ||
79 | const follower = await ActorModel.loadFull(byActor.id) | ||
80 | const actorFollowFull = Object.assign(actorFollow, { ActorFollowing: targetActor, ActorFollower: follower }) | ||
81 | |||
82 | if (await isFollowingInstance(targetActor)) { | ||
83 | Notifier.Instance.notifyOfNewInstanceFollow(actorFollowFull) | ||
84 | } else { | ||
85 | Notifier.Instance.notifyOfNewUserFollow(actorFollowFull) | ||
86 | } | ||
87 | } | ||
88 | |||
89 | logger.info('Actor %s is followed by actor %s.', targetActorURL, byActor.url) | ||
90 | } | ||
91 | |||
92 | async function rejectIfInstanceFollowDisabled (byActor: MActorSignature, activityId: string, targetActor: MActorFull) { | ||
93 | if (await isFollowingInstance(targetActor) && CONFIG.FOLLOWERS.INSTANCE.ENABLED === false) { | ||
94 | logger.info('Rejecting %s because instance followers are disabled.', targetActor.url) | ||
95 | |||
96 | sendReject(activityId, byActor, targetActor) | ||
97 | |||
98 | return true | ||
99 | } | ||
100 | |||
101 | return false | ||
102 | } | ||
103 | |||
104 | async function rejectIfMuted (byActor: MActorSignature, activityId: string, targetActor: MActorFull) { | ||
105 | const followerAccount = await AccountModel.load(byActor.Account.id) | ||
106 | const followingAccountId = targetActor.Account | ||
107 | |||
108 | if (followerAccount && await isBlockedByServerOrAccount(followerAccount, followingAccountId)) { | ||
109 | logger.info('Rejecting %s because follower is muted.', byActor.url) | ||
110 | |||
111 | sendReject(activityId, byActor, targetActor) | ||
112 | |||
113 | return true | ||
114 | } | ||
115 | |||
116 | return false | ||
117 | } | ||
118 | |||
119 | function rejectIfAlreadyRejected (actorFollow: MActorFollow, byActor: MActorSignature, activityId: string, targetActor: MActorFull) { | ||
120 | // Already rejected | ||
121 | if (actorFollow.state === 'rejected') { | ||
122 | logger.info('Rejecting %s because follow is already rejected.', byActor.url) | ||
123 | |||
124 | sendReject(activityId, byActor, targetActor) | ||
125 | |||
126 | return true | ||
127 | } | ||
128 | |||
129 | return false | ||
130 | } | ||
131 | |||
132 | async function acceptIfNeeded (actorFollow: MActorFollow, targetActor: MActorFull, transaction: Transaction) { | ||
133 | // Set the follow as accepted if the remote actor follows a channel or account | ||
134 | // Or if the instance automatically accepts followers | ||
135 | if (actorFollow.state === 'accepted') return | ||
136 | if (!await isFollowingInstance(targetActor)) return | ||
137 | if (CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL === true && await isFollowingInstance(targetActor)) return | ||
138 | |||
139 | actorFollow.state = 'accepted' | ||
140 | |||
141 | await actorFollow.save({ transaction }) | ||
142 | } | ||
143 | |||
144 | async function fixFollowURLIfNeeded (actorFollow: MActorFollow, activityId: string, transaction: Transaction) { | ||
145 | // Before PeerTube V3 we did not save the follow ID. Try to fix these old follows | ||
146 | if (!actorFollow.url) { | ||
147 | actorFollow.url = activityId | ||
148 | await actorFollow.save({ transaction }) | ||
149 | } | ||
150 | } | ||
151 | |||
152 | async function isFollowingInstance (targetActor: MActorId) { | ||
153 | const serverActor = await getServerActor() | ||
154 | |||
155 | return targetActor.id === serverActor.id | ||
156 | } | ||