1 import * as express from 'express'
2 import * as RateLimit from 'express-rate-limit'
3 import { UserCreate, UserRight, UserRole, UserUpdate } from '../../../../shared'
4 import { logger } from '../../../helpers/logger'
5 import { getFormattedObjects } from '../../../helpers/utils'
6 import { CONFIG, RATES_LIMIT, sequelizeTypescript } from '../../../initializers'
7 import { Emailer } from '../../../lib/emailer'
8 import { Redis } from '../../../lib/redis'
9 import { createUserAccountAndChannel } from '../../../lib/user'
12 asyncRetryTransactionMiddleware,
15 ensureUserRegistrationAllowed,
16 ensureUserRegistrationAllowedForIP,
23 usersRegisterValidator,
27 } from '../../../middlewares'
29 usersAskResetPasswordValidator, usersBlockingValidator, usersResetPasswordValidator,
30 usersAskSendVerifyEmailValidator, usersVerifyEmailValidator
31 } from '../../../middlewares/validators'
32 import { UserModel } from '../../../models/account/user'
33 import { OAuthTokenModel } from '../../../models/oauth/oauth-token'
34 import { auditLoggerFactory, UserAuditView } from '../../../helpers/audit-logger'
35 import { meRouter } from './me'
37 const auditLogger = auditLoggerFactory('users')
39 const loginRateLimiter = new RateLimit({
40 windowMs: RATES_LIMIT.LOGIN.WINDOW_MS,
41 max: RATES_LIMIT.LOGIN.MAX,
45 const usersRouter = express.Router()
46 usersRouter.use('/', meRouter)
50 ensureUserHasRight(UserRight.MANAGE_USERS),
55 asyncMiddleware(listUsers)
58 usersRouter.post('/:id/block',
60 ensureUserHasRight(UserRight.MANAGE_USERS),
61 asyncMiddleware(usersBlockingValidator),
62 asyncMiddleware(blockUser)
64 usersRouter.post('/:id/unblock',
66 ensureUserHasRight(UserRight.MANAGE_USERS),
67 asyncMiddleware(usersBlockingValidator),
68 asyncMiddleware(unblockUser)
71 usersRouter.get('/:id',
73 ensureUserHasRight(UserRight.MANAGE_USERS),
74 asyncMiddleware(usersGetValidator),
80 ensureUserHasRight(UserRight.MANAGE_USERS),
81 asyncMiddleware(usersAddValidator),
82 asyncRetryTransactionMiddleware(createUser)
85 usersRouter.post('/register',
86 asyncMiddleware(ensureUserRegistrationAllowed),
87 ensureUserRegistrationAllowedForIP,
88 asyncMiddleware(usersRegisterValidator),
89 asyncRetryTransactionMiddleware(registerUser)
92 usersRouter.put('/:id',
94 ensureUserHasRight(UserRight.MANAGE_USERS),
95 asyncMiddleware(usersUpdateValidator),
96 asyncMiddleware(updateUser)
99 usersRouter.delete('/:id',
101 ensureUserHasRight(UserRight.MANAGE_USERS),
102 asyncMiddleware(usersRemoveValidator),
103 asyncMiddleware(removeUser)
106 usersRouter.post('/ask-reset-password',
107 asyncMiddleware(usersAskResetPasswordValidator),
108 asyncMiddleware(askResetUserPassword)
111 usersRouter.post('/:id/reset-password',
112 asyncMiddleware(usersResetPasswordValidator),
113 asyncMiddleware(resetUserPassword)
116 usersRouter.post('/ask-send-verify-email',
118 asyncMiddleware(usersAskSendVerifyEmailValidator),
119 asyncMiddleware(askSendVerifyUserEmail)
122 usersRouter.post('/:id/verify-email',
123 asyncMiddleware(usersVerifyEmailValidator),
124 asyncMiddleware(verifyUserEmail)
127 usersRouter.post('/token',
132 // TODO: Once https://github.com/oauthjs/node-oauth2-server/pull/289 is merged, implement revoke token route
134 // ---------------------------------------------------------------------------
140 // ---------------------------------------------------------------------------
142 async function createUser (req: express.Request, res: express.Response) {
143 const body: UserCreate = req.body
144 const userToCreate = new UserModel({
145 username: body.username,
146 password: body.password,
148 nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY,
151 videoQuota: body.videoQuota,
152 videoQuotaDaily: body.videoQuotaDaily
155 const { user, account } = await createUserAccountAndChannel(userToCreate)
157 auditLogger.create(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new UserAuditView(user.toFormattedJSON()))
158 logger.info('User %s with its channel and account created.', body.username)
165 uuid: account.Actor.uuid
171 async function registerUser (req: express.Request, res: express.Response) {
172 const body: UserCreate = req.body
174 const userToCreate = new UserModel({
175 username: body.username,
176 password: body.password,
178 nsfwPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY,
181 videoQuota: CONFIG.USER.VIDEO_QUOTA,
182 videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY,
183 emailVerified: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION ? false : null
186 const { user } = await createUserAccountAndChannel(userToCreate)
188 auditLogger.create(body.username, new UserAuditView(user.toFormattedJSON()))
189 logger.info('User %s with its channel and account registered.', body.username)
191 if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION) {
192 await sendVerifyUserEmail(user)
195 return res.type('json').status(204).end()
198 async function unblockUser (req: express.Request, res: express.Response, next: express.NextFunction) {
199 const user: UserModel = res.locals.user
201 await changeUserBlock(res, user, false)
203 return res.status(204).end()
206 async function blockUser (req: express.Request, res: express.Response, next: express.NextFunction) {
207 const user: UserModel = res.locals.user
208 const reason = req.body.reason
210 await changeUserBlock(res, user, true, reason)
212 return res.status(204).end()
215 function getUser (req: express.Request, res: express.Response, next: express.NextFunction) {
216 return res.json((res.locals.user as UserModel).toFormattedJSON())
219 async function listUsers (req: express.Request, res: express.Response, next: express.NextFunction) {
220 const resultList = await UserModel.listForApi(req.query.start, req.query.count, req.query.sort)
222 return res.json(getFormattedObjects(resultList.data, resultList.total))
225 async function removeUser (req: express.Request, res: express.Response, next: express.NextFunction) {
226 const user: UserModel = res.locals.user
230 auditLogger.delete(res.locals.oauth.token.User.Account.Actor.getIdentifier(), new UserAuditView(user.toFormattedJSON()))
232 return res.sendStatus(204)
235 async function updateUser (req: express.Request, res: express.Response, next: express.NextFunction) {
236 const body: UserUpdate = req.body
237 const userToUpdate = res.locals.user as UserModel
238 const oldUserAuditView = new UserAuditView(userToUpdate.toFormattedJSON())
239 const roleChanged = body.role !== undefined && body.role !== userToUpdate.role
241 if (body.email !== undefined) userToUpdate.email = body.email
242 if (body.videoQuota !== undefined) userToUpdate.videoQuota = body.videoQuota
243 if (body.videoQuotaDaily !== undefined) userToUpdate.videoQuotaDaily = body.videoQuotaDaily
244 if (body.role !== undefined) userToUpdate.role = body.role
246 const user = await userToUpdate.save()
248 // Destroy user token to refresh rights
250 await OAuthTokenModel.deleteUserToken(userToUpdate.id)
254 res.locals.oauth.token.User.Account.Actor.getIdentifier(),
255 new UserAuditView(user.toFormattedJSON()),
259 // Don't need to send this update to followers, these attributes are not propagated
261 return res.sendStatus(204)
264 async function askResetUserPassword (req: express.Request, res: express.Response, next: express.NextFunction) {
265 const user = res.locals.user as UserModel
267 const verificationString = await Redis.Instance.setResetPasswordVerificationString(user.id)
268 const url = CONFIG.WEBSERVER.URL + '/reset-password?userId=' + user.id + '&verificationString=' + verificationString
269 await Emailer.Instance.addForgetPasswordEmailJob(user.email, url)
271 return res.status(204).end()
274 async function resetUserPassword (req: express.Request, res: express.Response, next: express.NextFunction) {
275 const user = res.locals.user as UserModel
276 user.password = req.body.password
280 return res.status(204).end()
283 async function sendVerifyUserEmail (user: UserModel) {
284 const verificationString = await Redis.Instance.setVerifyEmailVerificationString(user.id)
285 const url = CONFIG.WEBSERVER.URL + '/verify-account/email?userId=' + user.id + '&verificationString=' + verificationString
286 await Emailer.Instance.addVerifyEmailJob(user.email, url)
290 async function askSendVerifyUserEmail (req: express.Request, res: express.Response, next: express.NextFunction) {
291 const user = res.locals.user as UserModel
293 await sendVerifyUserEmail(user)
295 return res.status(204).end()
298 async function verifyUserEmail (req: express.Request, res: express.Response, next: express.NextFunction) {
299 const user = res.locals.user as UserModel
300 user.emailVerified = true
304 return res.status(204).end()
307 function success (req: express.Request, res: express.Response, next: express.NextFunction) {
311 async function changeUserBlock (res: express.Response, user: UserModel, block: boolean, reason?: string) {
312 const oldUserAuditView = new UserAuditView(user.toFormattedJSON())
315 user.blockedReason = reason || null
317 await sequelizeTypescript.transaction(async t => {
318 await OAuthTokenModel.deleteUserToken(user.id, t)
320 await user.save({ transaction: t })
323 await Emailer.Instance.addUserBlockJob(user, block, reason)
326 res.locals.oauth.token.User.Account.Actor.getIdentifier(),
327 new UserAuditView(user.toFormattedJSON()),