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