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