Add commentsEnabled field to AS context
[oweals/peertube.git] / server / middlewares / validators / users.ts
1 import * as express from 'express'
2 import 'express-validator'
3 import { body, param } from 'express-validator/check'
4 import { isIdOrUUIDValid } from '../../helpers/custom-validators/misc'
5 import {
6   isAvatarFile, isUserAutoPlayVideoValid, isUserDisplayNSFWValid, isUserPasswordValid, isUserRoleValid, isUserUsernameValid,
7   isUserVideoQuotaValid
8 } from '../../helpers/custom-validators/users'
9 import { isVideoExist } from '../../helpers/custom-validators/videos'
10 import { logger } from '../../helpers/logger'
11 import { isSignupAllowed } from '../../helpers/utils'
12 import { CONSTRAINTS_FIELDS } from '../../initializers'
13 import { UserModel } from '../../models/account/user'
14 import { areValidationErrors } from './utils'
15
16 const usersAddValidator = [
17   body('username').custom(isUserUsernameValid).withMessage('Should have a valid username (lowercase alphanumeric characters)'),
18   body('password').custom(isUserPasswordValid).withMessage('Should have a valid password'),
19   body('email').isEmail().withMessage('Should have a valid email'),
20   body('videoQuota').custom(isUserVideoQuotaValid).withMessage('Should have a valid user quota'),
21   body('role').custom(isUserRoleValid).withMessage('Should have a valid role'),
22
23   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
24     logger.debug('Checking usersAdd parameters', { parameters: req.body })
25
26     if (areValidationErrors(req, res)) return
27     if (!await checkUserNameOrEmailDoesNotAlreadyExist(req.body.username, req.body.email, res)) return
28
29     return next()
30   }
31 ]
32
33 const usersRegisterValidator = [
34   body('username').custom(isUserUsernameValid).withMessage('Should have a valid username'),
35   body('password').custom(isUserPasswordValid).withMessage('Should have a valid password'),
36   body('email').isEmail().withMessage('Should have a valid email'),
37
38   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
39     logger.debug('Checking usersRegister parameters', { parameters: req.body })
40
41     if (areValidationErrors(req, res)) return
42     if (!await checkUserNameOrEmailDoesNotAlreadyExist(req.body.username, req.body.email, res)) return
43
44     return next()
45   }
46 ]
47
48 const usersRemoveValidator = [
49   param('id').isInt().not().isEmpty().withMessage('Should have a valid id'),
50
51   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
52     logger.debug('Checking usersRemove parameters', { parameters: req.params })
53
54     if (areValidationErrors(req, res)) return
55     if (!await checkUserIdExist(req.params.id, res)) return
56
57     const user = res.locals.user
58     if (user.username === 'root') {
59       return res.status(400)
60                 .send({ error: 'Cannot remove the root user' })
61                 .end()
62     }
63
64     return next()
65   }
66 ]
67
68 const usersUpdateValidator = [
69   param('id').isInt().not().isEmpty().withMessage('Should have a valid id'),
70   body('email').optional().isEmail().withMessage('Should have a valid email attribute'),
71   body('videoQuota').optional().custom(isUserVideoQuotaValid).withMessage('Should have a valid user quota'),
72   body('role').optional().custom(isUserRoleValid).withMessage('Should have a valid role'),
73
74   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
75     logger.debug('Checking usersUpdate parameters', { parameters: req.body })
76
77     if (areValidationErrors(req, res)) return
78     if (!await checkUserIdExist(req.params.id, res)) return
79
80     return next()
81   }
82 ]
83
84 const usersUpdateMeValidator = [
85   body('password').optional().custom(isUserPasswordValid).withMessage('Should have a valid password'),
86   body('email').optional().isEmail().withMessage('Should have a valid email attribute'),
87   body('displayNSFW').optional().custom(isUserDisplayNSFWValid).withMessage('Should have a valid display Not Safe For Work attribute'),
88   body('autoPlayVideo').optional().custom(isUserAutoPlayVideoValid).withMessage('Should have a valid automatically plays video attribute'),
89
90   (req: express.Request, res: express.Response, next: express.NextFunction) => {
91     // TODO: Add old password verification
92     logger.debug('Checking usersUpdateMe parameters', { parameters: req.body })
93
94     if (areValidationErrors(req, res)) return
95
96     return next()
97   }
98 ]
99
100 const usersUpdateMyAvatarValidator = [
101   body('avatarfile').custom((value, { req }) => isAvatarFile(req.files)).withMessage(
102     'This file is not supported. Please, make sure it is of the following type : '
103     + CONSTRAINTS_FIELDS.ACTORS.AVATAR.EXTNAME.join(', ')
104   ),
105
106   (req: express.Request, res: express.Response, next: express.NextFunction) => {
107     logger.debug('Checking usersUpdateMyAvatarValidator parameters', { files: req.files })
108
109     if (areValidationErrors(req, res)) return
110
111     const imageFile = req.files['avatarfile'][0] as Express.Multer.File
112     if (imageFile.size > CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max) {
113       res.status(400)
114         .send({ error: `The size of the avatar is too big (>${CONSTRAINTS_FIELDS.ACTORS.AVATAR.FILE_SIZE.max}).` })
115         .end()
116       return
117     }
118
119     return next()
120   }
121 ]
122
123 const usersGetValidator = [
124   param('id').isInt().not().isEmpty().withMessage('Should have a valid id'),
125
126   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
127     logger.debug('Checking usersGet parameters', { parameters: req.body })
128
129     if (areValidationErrors(req, res)) return
130     if (!await checkUserIdExist(req.params.id, res)) return
131
132     return next()
133   }
134 ]
135
136 const usersVideoRatingValidator = [
137   param('videoId').custom(isIdOrUUIDValid).not().isEmpty().withMessage('Should have a valid video id'),
138
139   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
140     logger.debug('Checking usersVideoRating parameters', { parameters: req.params })
141
142     if (areValidationErrors(req, res)) return
143     if (!await isVideoExist(req.params.videoId, res)) return
144
145     return next()
146   }
147 ]
148
149 const ensureUserRegistrationAllowed = [
150   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
151     const allowed = await isSignupAllowed()
152     if (allowed === false) {
153       return res.status(403)
154                 .send({ error: 'User registration is not enabled or user limit is reached.' })
155                 .end()
156     }
157
158     return next()
159   }
160 ]
161
162 // ---------------------------------------------------------------------------
163
164 export {
165   usersAddValidator,
166   usersRegisterValidator,
167   usersRemoveValidator,
168   usersUpdateValidator,
169   usersUpdateMeValidator,
170   usersVideoRatingValidator,
171   ensureUserRegistrationAllowed,
172   usersGetValidator,
173   usersUpdateMyAvatarValidator
174 }
175
176 // ---------------------------------------------------------------------------
177
178 async function checkUserIdExist (id: number, res: express.Response) {
179   const user = await UserModel.loadById(id)
180
181   if (!user) {
182     res.status(404)
183               .send({ error: 'User not found' })
184               .end()
185
186     return false
187   }
188
189   res.locals.user = user
190   return true
191 }
192
193 async function checkUserNameOrEmailDoesNotAlreadyExist (username: string, email: string, res: express.Response) {
194   const user = await UserModel.loadByUsernameOrEmail(username, email)
195
196   if (user) {
197     res.status(409)
198               .send({ error: 'User with this username of email already exists.' })
199               .end()
200     return false
201   }
202
203   return true
204 }