]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/middlewares/validators/abuse.ts
Merge branch 'release/5.0.0' into develop
[github/Chocobozzz/PeerTube.git] / server / middlewares / validators / abuse.ts
1 import express from 'express'
2 import { body, param, query } from 'express-validator'
3 import {
4 areAbusePredefinedReasonsValid,
5 isAbuseFilterValid,
6 isAbuseMessageValid,
7 isAbuseModerationCommentValid,
8 isAbusePredefinedReasonValid,
9 isAbuseReasonValid,
10 isAbuseStateValid,
11 isAbuseTimestampCoherent,
12 isAbuseTimestampValid,
13 isAbuseVideoIsValid
14 } from '@server/helpers/custom-validators/abuses'
15 import { exists, isIdOrUUIDValid, isIdValid, toCompleteUUID, toIntOrNull } from '@server/helpers/custom-validators/misc'
16 import { logger } from '@server/helpers/logger'
17 import { AbuseMessageModel } from '@server/models/abuse/abuse-message'
18 import { AbuseCreate, UserRight } from '@shared/models'
19 import { HttpStatusCode } from '../../../shared/models/http/http-error-codes'
20 import { areValidationErrors, doesAbuseExist, doesAccountIdExist, doesCommentIdExist, doesVideoExist } from './shared'
21 import { forceNumber } from '@shared/core-utils'
22
23 const abuseReportValidator = [
24 body('account.id')
25 .optional()
26 .custom(isIdValid),
27
28 body('video.id')
29 .optional()
30 .customSanitizer(toCompleteUUID)
31 .custom(isIdOrUUIDValid),
32 body('video.startAt')
33 .optional()
34 .customSanitizer(toIntOrNull)
35 .custom(isAbuseTimestampValid),
36 body('video.endAt')
37 .optional()
38 .customSanitizer(toIntOrNull)
39 .custom(isAbuseTimestampValid)
40 .bail()
41 .custom(isAbuseTimestampCoherent)
42 .withMessage('Should have a startAt timestamp beginning before endAt'),
43
44 body('comment.id')
45 .optional()
46 .custom(isIdValid),
47
48 body('reason')
49 .custom(isAbuseReasonValid),
50
51 body('predefinedReasons')
52 .optional()
53 .custom(areAbusePredefinedReasonsValid),
54
55 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
56 if (areValidationErrors(req, res)) return
57
58 const body: AbuseCreate = req.body
59
60 if (body.video?.id && !await doesVideoExist(body.video.id, res)) return
61 if (body.account?.id && !await doesAccountIdExist(body.account.id, res)) return
62 if (body.comment?.id && !await doesCommentIdExist(body.comment.id, res)) return
63
64 if (!body.video?.id && !body.account?.id && !body.comment?.id) {
65 res.fail({ message: 'video id or account id or comment id is required.' })
66 return
67 }
68
69 return next()
70 }
71 ]
72
73 const abuseGetValidator = [
74 param('id')
75 .custom(isIdValid),
76
77 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
78 if (areValidationErrors(req, res)) return
79 if (!await doesAbuseExist(req.params.id, res)) return
80
81 return next()
82 }
83 ]
84
85 const abuseUpdateValidator = [
86 param('id')
87 .custom(isIdValid),
88
89 body('state')
90 .optional()
91 .custom(isAbuseStateValid),
92 body('moderationComment')
93 .optional()
94 .custom(isAbuseModerationCommentValid),
95
96 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
97 if (areValidationErrors(req, res)) return
98 if (!await doesAbuseExist(req.params.id, res)) return
99
100 return next()
101 }
102 ]
103
104 const abuseListForAdminsValidator = [
105 query('id')
106 .optional()
107 .custom(isIdValid),
108 query('filter')
109 .optional()
110 .custom(isAbuseFilterValid),
111 query('predefinedReason')
112 .optional()
113 .custom(isAbusePredefinedReasonValid),
114 query('search')
115 .optional()
116 .custom(exists),
117 query('state')
118 .optional()
119 .custom(isAbuseStateValid),
120 query('videoIs')
121 .optional()
122 .custom(isAbuseVideoIsValid),
123 query('searchReporter')
124 .optional()
125 .custom(exists),
126 query('searchReportee')
127 .optional()
128 .custom(exists),
129 query('searchVideo')
130 .optional()
131 .custom(exists),
132 query('searchVideoChannel')
133 .optional()
134 .custom(exists),
135
136 (req: express.Request, res: express.Response, next: express.NextFunction) => {
137 if (areValidationErrors(req, res)) return
138
139 return next()
140 }
141 ]
142
143 const abuseListForUserValidator = [
144 query('id')
145 .optional()
146 .custom(isIdValid),
147
148 query('search')
149 .optional()
150 .custom(exists),
151
152 query('state')
153 .optional()
154 .custom(isAbuseStateValid),
155
156 (req: express.Request, res: express.Response, next: express.NextFunction) => {
157 if (areValidationErrors(req, res)) return
158
159 return next()
160 }
161 ]
162
163 const getAbuseValidator = [
164 param('id')
165 .custom(isIdValid),
166
167 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
168 if (areValidationErrors(req, res)) return
169 if (!await doesAbuseExist(req.params.id, res)) return
170
171 const user = res.locals.oauth.token.user
172 const abuse = res.locals.abuse
173
174 if (user.hasRight(UserRight.MANAGE_ABUSES) !== true && abuse.reporterAccountId !== user.Account.id) {
175 const message = `User ${user.username} does not have right to get abuse ${abuse.id}`
176 logger.warn(message)
177
178 return res.fail({
179 status: HttpStatusCode.FORBIDDEN_403,
180 message
181 })
182 }
183
184 return next()
185 }
186 ]
187
188 const checkAbuseValidForMessagesValidator = [
189 (req: express.Request, res: express.Response, next: express.NextFunction) => {
190 const abuse = res.locals.abuse
191 if (abuse.ReporterAccount.isOwned() === false) {
192 return res.fail({ message: 'This abuse was created by a user of your instance.' })
193 }
194
195 return next()
196 }
197 ]
198
199 const addAbuseMessageValidator = [
200 body('message')
201 .custom(isAbuseMessageValid),
202
203 (req: express.Request, res: express.Response, next: express.NextFunction) => {
204 if (areValidationErrors(req, res)) return
205
206 return next()
207 }
208 ]
209
210 const deleteAbuseMessageValidator = [
211 param('messageId')
212 .custom(isIdValid),
213
214 async (req: express.Request, res: express.Response, next: express.NextFunction) => {
215 if (areValidationErrors(req, res)) return
216
217 const user = res.locals.oauth.token.user
218 const abuse = res.locals.abuse
219
220 const messageId = forceNumber(req.params.messageId)
221 const abuseMessage = await AbuseMessageModel.loadByIdAndAbuseId(messageId, abuse.id)
222
223 if (!abuseMessage) {
224 return res.fail({
225 status: HttpStatusCode.NOT_FOUND_404,
226 message: 'Abuse message not found'
227 })
228 }
229
230 if (user.hasRight(UserRight.MANAGE_ABUSES) !== true && abuseMessage.accountId !== user.Account.id) {
231 return res.fail({
232 status: HttpStatusCode.FORBIDDEN_403,
233 message: 'Cannot delete this abuse message'
234 })
235 }
236
237 res.locals.abuseMessage = abuseMessage
238
239 return next()
240 }
241 ]
242
243 // ---------------------------------------------------------------------------
244
245 export {
246 abuseListForAdminsValidator,
247 abuseReportValidator,
248 abuseGetValidator,
249 addAbuseMessageValidator,
250 checkAbuseValidForMessagesValidator,
251 abuseUpdateValidator,
252 deleteAbuseMessageValidator,
253 abuseListForUserValidator,
254 getAbuseValidator
255 }