]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/controllers/api/users/index.ts
Cache user token
[github/Chocobozzz/PeerTube.git] / server / controllers / api / users / index.ts
CommitLineData
4d4e5cd4 1import * as express from 'express'
490b595a 2import * as RateLimit from 'express-rate-limit'
d03cd8bb
C
3import { UserCreate, UserRight, UserRole, UserUpdate } from '../../../../shared'
4import { logger } from '../../../helpers/logger'
5import { getFormattedObjects } from '../../../helpers/utils'
6import { CONFIG, RATES_LIMIT, sequelizeTypescript } from '../../../initializers'
7import { Emailer } from '../../../lib/emailer'
8import { Redis } from '../../../lib/redis'
9import { createUserAccountAndChannel } from '../../../lib/user'
65fcc311 10import {
f076daa7 11 asyncMiddleware,
90d4bb81 12 asyncRetryTransactionMiddleware,
f076daa7
C
13 authenticate,
14 ensureUserHasRight,
15 ensureUserRegistrationAllowed,
ff2c1fe8 16 ensureUserRegistrationAllowedForIP,
f076daa7
C
17 paginationValidator,
18 setDefaultPagination,
19 setDefaultSort,
20 token,
74d63469 21 userAutocompleteValidator,
f076daa7
C
22 usersAddValidator,
23 usersGetValidator,
24 usersRegisterValidator,
25 usersRemoveValidator,
26 usersSortValidator,
d03cd8bb
C
27 usersUpdateValidator
28} from '../../../middlewares'
d9eaee39 29import {
993cef4b
C
30 usersAskResetPasswordValidator,
31 usersAskSendVerifyEmailValidator,
32 usersBlockingValidator,
33 usersResetPasswordValidator,
34 usersVerifyEmailValidator
d9eaee39 35} from '../../../middlewares/validators'
d03cd8bb
C
36import { UserModel } from '../../../models/account/user'
37import { OAuthTokenModel } from '../../../models/oauth/oauth-token'
993cef4b 38import { auditLoggerFactory, getAuditIdFromRes, UserAuditView } from '../../../helpers/audit-logger'
d03cd8bb 39import { meRouter } from './me'
f201a749 40import { deleteUserToken } from '../../../lib/oauth-model'
80e36cd9
AB
41
42const auditLogger = auditLoggerFactory('users')
65fcc311 43
490b595a
C
44const loginRateLimiter = new RateLimit({
45 windowMs: RATES_LIMIT.LOGIN.WINDOW_MS,
46 max: RATES_LIMIT.LOGIN.MAX,
47 delayMs: 0
48})
c5911fd3 49
288fe385
C
50const askSendEmailLimiter = new RateLimit({
51 windowMs: RATES_LIMIT.ASK_SEND_EMAIL.WINDOW_MS,
52 max: RATES_LIMIT.ASK_SEND_EMAIL.MAX,
53 delayMs: 0
54})
55
65fcc311 56const usersRouter = express.Router()
06a05d5f 57usersRouter.use('/', meRouter)
9bd26629 58
74d63469
GR
59usersRouter.get('/autocomplete',
60 userAutocompleteValidator,
61 asyncMiddleware(autocompleteUsers)
62)
63
65fcc311 64usersRouter.get('/',
86d13ec2
C
65 authenticate,
66 ensureUserHasRight(UserRight.MANAGE_USERS),
65fcc311
C
67 paginationValidator,
68 usersSortValidator,
1174a847 69 setDefaultSort,
f05a1c30 70 setDefaultPagination,
eb080476 71 asyncMiddleware(listUsers)
5c39adb7
C
72)
73
e6921918
C
74usersRouter.post('/:id/block',
75 authenticate,
76 ensureUserHasRight(UserRight.MANAGE_USERS),
77 asyncMiddleware(usersBlockingValidator),
78 asyncMiddleware(blockUser)
79)
80usersRouter.post('/:id/unblock',
81 authenticate,
82 ensureUserHasRight(UserRight.MANAGE_USERS),
83 asyncMiddleware(usersBlockingValidator),
84 asyncMiddleware(unblockUser)
85)
86
8094a898 87usersRouter.get('/:id',
94ff4c23
C
88 authenticate,
89 ensureUserHasRight(UserRight.MANAGE_USERS),
a2431b7d 90 asyncMiddleware(usersGetValidator),
8094a898
C
91 getUser
92)
93
65fcc311
C
94usersRouter.post('/',
95 authenticate,
954605a8 96 ensureUserHasRight(UserRight.MANAGE_USERS),
a2431b7d 97 asyncMiddleware(usersAddValidator),
90d4bb81 98 asyncRetryTransactionMiddleware(createUser)
9bd26629
C
99)
100
65fcc311 101usersRouter.post('/register',
a2431b7d 102 asyncMiddleware(ensureUserRegistrationAllowed),
ff2c1fe8 103 ensureUserRegistrationAllowedForIP,
a2431b7d 104 asyncMiddleware(usersRegisterValidator),
90d4bb81 105 asyncRetryTransactionMiddleware(registerUser)
2c2e9092
C
106)
107
65fcc311
C
108usersRouter.put('/:id',
109 authenticate,
954605a8 110 ensureUserHasRight(UserRight.MANAGE_USERS),
a2431b7d 111 asyncMiddleware(usersUpdateValidator),
eb080476 112 asyncMiddleware(updateUser)
9bd26629
C
113)
114
65fcc311
C
115usersRouter.delete('/:id',
116 authenticate,
954605a8 117 ensureUserHasRight(UserRight.MANAGE_USERS),
a2431b7d 118 asyncMiddleware(usersRemoveValidator),
eb080476 119 asyncMiddleware(removeUser)
9bd26629 120)
6606150c 121
ecb4e35f
C
122usersRouter.post('/ask-reset-password',
123 asyncMiddleware(usersAskResetPasswordValidator),
124 asyncMiddleware(askResetUserPassword)
125)
126
127usersRouter.post('/:id/reset-password',
128 asyncMiddleware(usersResetPasswordValidator),
129 asyncMiddleware(resetUserPassword)
130)
131
d9eaee39 132usersRouter.post('/ask-send-verify-email',
288fe385 133 askSendEmailLimiter,
d9eaee39
JM
134 asyncMiddleware(usersAskSendVerifyEmailValidator),
135 asyncMiddleware(askSendVerifyUserEmail)
136)
137
138usersRouter.post('/:id/verify-email',
139 asyncMiddleware(usersVerifyEmailValidator),
140 asyncMiddleware(verifyUserEmail)
141)
142
490b595a
C
143usersRouter.post('/token',
144 loginRateLimiter,
145 token,
146 success
147)
9bd26629 148// TODO: Once https://github.com/oauthjs/node-oauth2-server/pull/289 is merged, implement revoke token route
9457bf88
C
149
150// ---------------------------------------------------------------------------
151
65fcc311
C
152export {
153 usersRouter
154}
9457bf88
C
155
156// ---------------------------------------------------------------------------
157
90d4bb81 158async function createUser (req: express.Request, res: express.Response) {
4771e000 159 const body: UserCreate = req.body
f05a1c30 160 const userToCreate = new UserModel({
4771e000
C
161 username: body.username,
162 password: body.password,
163 email: body.email,
0883b324 164 nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY,
7efe153b 165 autoPlayVideo: true,
954605a8 166 role: body.role,
bee0abff
FA
167 videoQuota: body.videoQuota,
168 videoQuotaDaily: body.videoQuotaDaily
9bd26629
C
169 })
170
f05a1c30 171 const { user, account } = await createUserAccountAndChannel(userToCreate)
eb080476 172
993cef4b 173 auditLogger.create(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()))
38fa2065 174 logger.info('User %s with its channel and account created.', body.username)
f05a1c30 175
90d4bb81
C
176 return res.json({
177 user: {
178 id: user.id,
179 account: {
180 id: account.id,
181 uuid: account.Actor.uuid
182 }
183 }
184 }).end()
47e0652b
C
185}
186
90d4bb81 187async function registerUser (req: express.Request, res: express.Response) {
77a5501f
C
188 const body: UserCreate = req.body
189
80e36cd9 190 const userToCreate = new UserModel({
77a5501f
C
191 username: body.username,
192 password: body.password,
193 email: body.email,
0883b324 194 nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY,
7efe153b 195 autoPlayVideo: true,
954605a8 196 role: UserRole.USER,
bee0abff 197 videoQuota: CONFIG.USER.VIDEO_QUOTA,
d9eaee39
JM
198 videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY,
199 emailVerified: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION ? false : null
77a5501f
C
200 })
201
80e36cd9 202 const { user } = await createUserAccountAndChannel(userToCreate)
47e0652b 203
80e36cd9 204 auditLogger.create(body.username, new UserAuditView(user.toFormattedJSON()))
47e0652b 205 logger.info('User %s with its channel and account registered.', body.username)
90d4bb81 206
d9eaee39
JM
207 if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) {
208 await sendVerifyUserEmail(user)
209 }
210
90d4bb81 211 return res.type('json').status(204).end()
77a5501f
C
212}
213
e6921918
C
214async function unblockUser (req: express.Request, res: express.Response, next: express.NextFunction) {
215 const user: UserModel = res.locals.user
216
217 await changeUserBlock(res, user, false)
218
219 return res.status(204).end()
220}
221
222async function blockUser (req: express.Request, res: express.Response, next: express.NextFunction) {
223 const user: UserModel = res.locals.user
eacb25c4 224 const reason = req.body.reason
e6921918 225
eacb25c4 226 await changeUserBlock(res, user, true, reason)
e6921918
C
227
228 return res.status(204).end()
229}
230
8094a898 231function getUser (req: express.Request, res: express.Response, next: express.NextFunction) {
ce5496d6 232 return res.json((res.locals.user as UserModel).toFormattedJSON())
8094a898
C
233}
234
74d63469 235async function autocompleteUsers (req: express.Request, res: express.Response, next: express.NextFunction) {
5cf84858 236 const resultList = await UserModel.autoComplete(req.query.search as string)
74d63469
GR
237
238 return res.json(resultList)
239}
240
eb080476 241async function listUsers (req: express.Request, res: express.Response, next: express.NextFunction) {
3fd3ab2d 242 const resultList = await UserModel.listForApi(req.query.start, req.query.count, req.query.sort)
eb080476
C
243
244 return res.json(getFormattedObjects(resultList.data, resultList.total))
9bd26629
C
245}
246
eb080476 247async function removeUser (req: express.Request, res: express.Response, next: express.NextFunction) {
92b9d60c 248 const user: UserModel = res.locals.user
eb080476
C
249
250 await user.destroy()
251
993cef4b 252 auditLogger.delete(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()))
80e36cd9 253
eb080476 254 return res.sendStatus(204)
9bd26629
C
255}
256
eb080476 257async function updateUser (req: express.Request, res: express.Response, next: express.NextFunction) {
8094a898 258 const body: UserUpdate = req.body
80e36cd9
AB
259 const userToUpdate = res.locals.user as UserModel
260 const oldUserAuditView = new UserAuditView(userToUpdate.toFormattedJSON())
261 const roleChanged = body.role !== undefined && body.role !== userToUpdate.role
8094a898 262
80e36cd9
AB
263 if (body.email !== undefined) userToUpdate.email = body.email
264 if (body.videoQuota !== undefined) userToUpdate.videoQuota = body.videoQuota
bee0abff 265 if (body.videoQuotaDaily !== undefined) userToUpdate.videoQuotaDaily = body.videoQuotaDaily
80e36cd9 266 if (body.role !== undefined) userToUpdate.role = body.role
8094a898 267
80e36cd9 268 const user = await userToUpdate.save()
eb080476 269
f8b8c36b 270 // Destroy user token to refresh rights
f201a749 271 if (roleChanged) await deleteUserToken(userToUpdate.id)
f8b8c36b 272
91411dba 273 auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()), oldUserAuditView)
80e36cd9 274
265ba139
C
275 // Don't need to send this update to followers, these attributes are not propagated
276
eb080476 277 return res.sendStatus(204)
8094a898
C
278}
279
ecb4e35f
C
280async function askResetUserPassword (req: express.Request, res: express.Response, next: express.NextFunction) {
281 const user = res.locals.user as UserModel
282
283 const verificationString = await Redis.Instance.setResetPasswordVerificationString(user.id)
284 const url = CONFIG.WEBSERVER.URL + '/reset-password?userId=' + user.id + '&verificationString=' + verificationString
285 await Emailer.Instance.addForgetPasswordEmailJob(user.email, url)
286
287 return res.status(204).end()
288}
289
290async function resetUserPassword (req: express.Request, res: express.Response, next: express.NextFunction) {
291 const user = res.locals.user as UserModel
292 user.password = req.body.password
293
294 await user.save()
295
296 return res.status(204).end()
297}
298
d9eaee39
JM
299async function sendVerifyUserEmail (user: UserModel) {
300 const verificationString = await Redis.Instance.setVerifyEmailVerificationString(user.id)
301 const url = CONFIG.WEBSERVER.URL + '/verify-account/email?userId=' + user.id + '&verificationString=' + verificationString
302 await Emailer.Instance.addVerifyEmailJob(user.email, url)
303 return
304}
305
306async function askSendVerifyUserEmail (req: express.Request, res: express.Response, next: express.NextFunction) {
307 const user = res.locals.user as UserModel
308
309 await sendVerifyUserEmail(user)
310
311 return res.status(204).end()
312}
313
314async function verifyUserEmail (req: express.Request, res: express.Response, next: express.NextFunction) {
315 const user = res.locals.user as UserModel
316 user.emailVerified = true
317
318 await user.save()
319
320 return res.status(204).end()
321}
322
69818c93 323function success (req: express.Request, res: express.Response, next: express.NextFunction) {
9457bf88
C
324 res.end()
325}
e6921918 326
eacb25c4 327async function changeUserBlock (res: express.Response, user: UserModel, block: boolean, reason?: string) {
e6921918
C
328 const oldUserAuditView = new UserAuditView(user.toFormattedJSON())
329
330 user.blocked = block
eacb25c4 331 user.blockedReason = reason || null
e6921918
C
332
333 await sequelizeTypescript.transaction(async t => {
f201a749 334 await deleteUserToken(user.id, t)
e6921918
C
335
336 await user.save({ transaction: t })
337 })
338
eacb25c4
C
339 await Emailer.Instance.addUserBlockJob(user, block, reason)
340
91411dba 341 auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()), oldUserAuditView)
e6921918 342}