]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/controllers/api/server/follows.ts
Allow admins to disable two factor auth
[github/Chocobozzz/PeerTube.git] / server / controllers / api / server / follows.ts
CommitLineData
41fb13c3 1import express from 'express'
7d9ba5c0 2import { getServerActor } from '@server/models/application/application'
927fa4b1 3import { ServerFollowCreate } from '@shared/models'
c0e8b12e 4import { HttpStatusCode } from '../../../../shared/models/http/http-error-codes'
3fd3ab2d 5import { UserRight } from '../../../../shared/models/users'
da854ddd 6import { logger } from '../../../helpers/logger'
e1c55031 7import { getFormattedObjects } from '../../../helpers/utils'
74dc3bca 8import { SERVER_ACTOR_NAME } from '../../../initializers/constants'
7d9ba5c0
C
9import { sequelizeTypescript } from '../../../initializers/database'
10import { autoFollowBackIfNeeded } from '../../../lib/activitypub/follow'
14893eb7 11import { sendAccept, sendReject, sendUndoFollow } from '../../../lib/activitypub/send'
7d9ba5c0
C
12import { JobQueue } from '../../../lib/job-queue'
13import { removeRedundanciesOfServer } from '../../../lib/redundancy'
3fd3ab2d 14import {
5350fd8e
C
15 asyncMiddleware,
16 authenticate,
17 ensureUserHasRight,
18 paginationValidator,
5350fd8e
C
19 setBodyHostsPort,
20 setDefaultPagination,
21 setDefaultSort
3fd3ab2d 22} from '../../../middlewares'
0e9c48c2 23import {
927fa4b1 24 acceptFollowerValidator,
0e9c48c2 25 followValidator,
14893eb7 26 getFollowerValidator,
927fa4b1
C
27 instanceFollowersSortValidator,
28 instanceFollowingSortValidator,
7d9ba5c0 29 listFollowsValidator,
927fa4b1 30 rejectFollowerValidator,
7d9ba5c0 31 removeFollowingValidator
0e9c48c2 32} from '../../../middlewares/validators'
7d9ba5c0 33import { ActorFollowModel } from '../../../models/actor/actor-follow'
51548b31 34
4610bc5b 35const serverFollowsRouter = express.Router()
4610bc5b 36serverFollowsRouter.get('/following',
b8f4167f 37 listFollowsValidator,
8a02bd04 38 paginationValidator,
9593a78a 39 instanceFollowingSortValidator,
1174a847 40 setDefaultSort,
f05a1c30 41 setDefaultPagination,
7a7724e6
C
42 asyncMiddleware(listFollowing)
43)
44
9a27cdc2 45serverFollowsRouter.post('/following',
8e696487 46 authenticate,
4610bc5b 47 ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW),
ce548a10
C
48 followValidator,
49 setBodyHostsPort,
4d029ef8 50 asyncMiddleware(addFollow)
ce548a10
C
51)
52
4d029ef8 53serverFollowsRouter.delete('/following/:hostOrHandle',
54141398
C
54 authenticate,
55 ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW),
a2431b7d 56 asyncMiddleware(removeFollowingValidator),
0e9c48c2 57 asyncMiddleware(removeFollowing)
54141398
C
58)
59
4610bc5b 60serverFollowsRouter.get('/followers',
b8f4167f 61 listFollowsValidator,
7a7724e6 62 paginationValidator,
9593a78a 63 instanceFollowersSortValidator,
1174a847 64 setDefaultSort,
f05a1c30 65 setDefaultPagination,
7a7724e6 66 asyncMiddleware(listFollowers)
65fcc311 67)
65fcc311 68
0e9c48c2
C
69serverFollowsRouter.delete('/followers/:nameWithHost',
70 authenticate,
71 ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW),
14893eb7 72 asyncMiddleware(getFollowerValidator),
927fa4b1 73 asyncMiddleware(removeFollower)
14893eb7
C
74)
75
76serverFollowsRouter.post('/followers/:nameWithHost/reject',
77 authenticate,
78 ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW),
79 asyncMiddleware(getFollowerValidator),
927fa4b1
C
80 rejectFollowerValidator,
81 asyncMiddleware(rejectFollower)
14893eb7
C
82)
83
84serverFollowsRouter.post('/followers/:nameWithHost/accept',
85 authenticate,
86 ensureUserHasRight(UserRight.MANAGE_SERVER_FOLLOW),
87 asyncMiddleware(getFollowerValidator),
927fa4b1 88 acceptFollowerValidator,
14893eb7 89 asyncMiddleware(acceptFollower)
0e9c48c2
C
90)
91
65fcc311
C
92// ---------------------------------------------------------------------------
93
94export {
4610bc5b 95 serverFollowsRouter
65fcc311
C
96}
97
98// ---------------------------------------------------------------------------
99
dae86118 100async function listFollowing (req: express.Request, res: express.Response) {
50d6de9c 101 const serverActor = await getServerActor()
4beda9e1 102 const resultList = await ActorFollowModel.listInstanceFollowingForApi({
bae61627 103 followerId: serverActor.id,
b8f4167f
C
104 start: req.query.start,
105 count: req.query.count,
106 sort: req.query.sort,
107 search: req.query.search,
97ecddae 108 actorType: req.query.actorType,
b8f4167f
C
109 state: req.query.state
110 })
7a7724e6
C
111
112 return res.json(getFormattedObjects(resultList.data, resultList.total))
113}
114
dae86118 115async function listFollowers (req: express.Request, res: express.Response) {
50d6de9c 116 const serverActor = await getServerActor()
b8f4167f 117 const resultList = await ActorFollowModel.listFollowersForApi({
4beda9e1 118 actorIds: [ serverActor.id ],
b8f4167f
C
119 start: req.query.start,
120 count: req.query.count,
121 sort: req.query.sort,
122 search: req.query.search,
97ecddae 123 actorType: req.query.actorType,
b8f4167f
C
124 state: req.query.state
125 })
eb080476
C
126
127 return res.json(getFormattedObjects(resultList.data, resultList.total))
65fcc311 128}
ce548a10 129
4d029ef8
C
130async function addFollow (req: express.Request, res: express.Response) {
131 const { hosts, handles } = req.body as ServerFollowCreate
06a05d5f 132 const follower = await getServerActor()
350e31d6 133
ce548a10 134 for (const host of hosts) {
06a05d5f
C
135 const payload = {
136 host,
137 name: SERVER_ACTOR_NAME,
138 followerActorId: follower.id
139 }
140
bd911b54 141 JobQueue.Instance.createJobAsync({ type: 'activitypub-follow', payload })
ce548a10
C
142 }
143
4d029ef8
C
144 for (const handle of handles) {
145 const [ name, host ] = handle.split('@')
146
147 const payload = {
148 host,
149 name,
150 followerActorId: follower.id
151 }
152
bd911b54 153 JobQueue.Instance.createJobAsync({ type: 'activitypub-follow', payload })
4d029ef8
C
154 }
155
2d53be02 156 return res.status(HttpStatusCode.NO_CONTENT_204).end()
ce548a10 157}
350e31d6 158
0e9c48c2 159async function removeFollowing (req: express.Request, res: express.Response) {
dae86118 160 const follow = res.locals.follow
54141398 161
3fd3ab2d 162 await sequelizeTypescript.transaction(async t => {
bae61627 163 if (follow.state === 'accepted') sendUndoFollow(follow, t)
40ff5707 164
c48e82b5
C
165 // Disable redundancy on unfollowed instances
166 const server = follow.ActorFollowing.Server
167 server.redundancyAllowed = false
168 await server.save({ transaction: t })
169
161b061d 170 // Async, could be long
b764380a 171 removeRedundanciesOfServer(server.id)
1cc97746 172 .catch(err => logger.error('Cannot remove redundancy of %s.', server.host, { err }))
161b061d 173
0f91ae62 174 await follow.destroy({ transaction: t })
54141398
C
175 })
176
2d53be02 177 return res.status(HttpStatusCode.NO_CONTENT_204).end()
54141398 178}
0e9c48c2 179
927fa4b1 180async function rejectFollower (req: express.Request, res: express.Response) {
0e9c48c2
C
181 const follow = res.locals.follow
182
927fa4b1
C
183 follow.state = 'rejected'
184 await follow.save()
185
186 sendReject(follow.url, follow.ActorFollower, follow.ActorFollowing)
187
188 return res.status(HttpStatusCode.NO_CONTENT_204).end()
189}
190
191async function removeFollower (req: express.Request, res: express.Response) {
192 const follow = res.locals.follow
193
194 if (follow.state === 'accepted' || follow.state === 'pending') {
195 sendReject(follow.url, follow.ActorFollower, follow.ActorFollowing)
196 }
0e9c48c2
C
197
198 await follow.destroy()
199
2d53be02 200 return res.status(HttpStatusCode.NO_CONTENT_204).end()
0e9c48c2 201}
14893eb7
C
202
203async function acceptFollower (req: express.Request, res: express.Response) {
204 const follow = res.locals.follow
205
eae0365b 206 sendAccept(follow)
14893eb7
C
207
208 follow.state = 'accepted'
209 await follow.save()
210
8424c402
C
211 await autoFollowBackIfNeeded(follow)
212
2d53be02 213 return res.status(HttpStatusCode.NO_CONTENT_204).end()
14893eb7 214}