aboutsummaryrefslogtreecommitdiffhomepage
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/controllers/api/users/index.ts20
-rw-r--r--server/controllers/api/users/me.ts2
-rw-r--r--server/initializers/constants.ts2
-rw-r--r--server/lib/emailer.ts20
-rw-r--r--server/middlewares/validators/users.ts2
-rw-r--r--server/tests/api/check-params/users.ts18
-rw-r--r--server/tests/api/users/users.ts16
7 files changed, 51 insertions, 29 deletions
diff --git a/server/controllers/api/users/index.ts b/server/controllers/api/users/index.ts
index beac6d8b1..e3533a7f6 100644
--- a/server/controllers/api/users/index.ts
+++ b/server/controllers/api/users/index.ts
@@ -3,7 +3,6 @@ import * as RateLimit from 'express-rate-limit'
3import { UserCreate, UserRight, UserRole, UserUpdate } from '../../../../shared' 3import { UserCreate, UserRight, UserRole, UserUpdate } from '../../../../shared'
4import { logger } from '../../../helpers/logger' 4import { logger } from '../../../helpers/logger'
5import { getFormattedObjects } from '../../../helpers/utils' 5import { getFormattedObjects } from '../../../helpers/utils'
6import { pseudoRandomBytesPromise } from '../../../helpers/core-utils'
7import { CONFIG, RATES_LIMIT, sequelizeTypescript } from '../../../initializers' 6import { CONFIG, RATES_LIMIT, sequelizeTypescript } from '../../../initializers'
8import { Emailer } from '../../../lib/emailer' 7import { Emailer } from '../../../lib/emailer'
9import { Redis } from '../../../lib/redis' 8import { Redis } from '../../../lib/redis'
@@ -230,7 +229,7 @@ async function unblockUser (req: express.Request, res: express.Response, next: e
230 return res.status(204).end() 229 return res.status(204).end()
231} 230}
232 231
233async function blockUser (req: express.Request, res: express.Response, next: express.NextFunction) { 232async function blockUser (req: express.Request, res: express.Response) {
234 const user: UserModel = res.locals.user 233 const user: UserModel = res.locals.user
235 const reason = req.body.reason 234 const reason = req.body.reason
236 235
@@ -239,23 +238,23 @@ async function blockUser (req: express.Request, res: express.Response, next: exp
239 return res.status(204).end() 238 return res.status(204).end()
240} 239}
241 240
242function getUser (req: express.Request, res: express.Response, next: express.NextFunction) { 241function getUser (req: express.Request, res: express.Response) {
243 return res.json((res.locals.user as UserModel).toFormattedJSON()) 242 return res.json((res.locals.user as UserModel).toFormattedJSON())
244} 243}
245 244
246async function autocompleteUsers (req: express.Request, res: express.Response, next: express.NextFunction) { 245async function autocompleteUsers (req: express.Request, res: express.Response) {
247 const resultList = await UserModel.autoComplete(req.query.search as string) 246 const resultList = await UserModel.autoComplete(req.query.search as string)
248 247
249 return res.json(resultList) 248 return res.json(resultList)
250} 249}
251 250
252async function listUsers (req: express.Request, res: express.Response, next: express.NextFunction) { 251async function listUsers (req: express.Request, res: express.Response) {
253 const resultList = await UserModel.listForApi(req.query.start, req.query.count, req.query.sort, req.query.search) 252 const resultList = await UserModel.listForApi(req.query.start, req.query.count, req.query.sort, req.query.search)
254 253
255 return res.json(getFormattedObjects(resultList.data, resultList.total)) 254 return res.json(getFormattedObjects(resultList.data, resultList.total))
256} 255}
257 256
258async function removeUser (req: express.Request, res: express.Response, next: express.NextFunction) { 257async function removeUser (req: express.Request, res: express.Response) {
259 const user: UserModel = res.locals.user 258 const user: UserModel = res.locals.user
260 259
261 await user.destroy() 260 await user.destroy()
@@ -265,12 +264,13 @@ async function removeUser (req: express.Request, res: express.Response, next: ex
265 return res.sendStatus(204) 264 return res.sendStatus(204)
266} 265}
267 266
268async function updateUser (req: express.Request, res: express.Response, next: express.NextFunction) { 267async function updateUser (req: express.Request, res: express.Response) {
269 const body: UserUpdate = req.body 268 const body: UserUpdate = req.body
270 const userToUpdate = res.locals.user as UserModel 269 const userToUpdate = res.locals.user as UserModel
271 const oldUserAuditView = new UserAuditView(userToUpdate.toFormattedJSON()) 270 const oldUserAuditView = new UserAuditView(userToUpdate.toFormattedJSON())
272 const roleChanged = body.role !== undefined && body.role !== userToUpdate.role 271 const roleChanged = body.role !== undefined && body.role !== userToUpdate.role
273 272
273 if (body.password !== undefined) userToUpdate.password = body.password
274 if (body.email !== undefined) userToUpdate.email = body.email 274 if (body.email !== undefined) userToUpdate.email = body.email
275 if (body.emailVerified !== undefined) userToUpdate.emailVerified = body.emailVerified 275 if (body.emailVerified !== undefined) userToUpdate.emailVerified = body.emailVerified
276 if (body.videoQuota !== undefined) userToUpdate.videoQuota = body.videoQuota 276 if (body.videoQuota !== undefined) userToUpdate.videoQuota = body.videoQuota
@@ -280,11 +280,11 @@ async function updateUser (req: express.Request, res: express.Response, next: ex
280 const user = await userToUpdate.save() 280 const user = await userToUpdate.save()
281 281
282 // Destroy user token to refresh rights 282 // Destroy user token to refresh rights
283 if (roleChanged) await deleteUserToken(userToUpdate.id) 283 if (roleChanged || body.password !== undefined) await deleteUserToken(userToUpdate.id)
284 284
285 auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()), oldUserAuditView) 285 auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON()), oldUserAuditView)
286 286
287 // Don't need to send this update to followers, these attributes are not propagated 287 // Don't need to send this update to followers, these attributes are not federated
288 288
289 return res.sendStatus(204) 289 return res.sendStatus(204)
290} 290}
@@ -294,7 +294,7 @@ async function askResetUserPassword (req: express.Request, res: express.Response
294 294
295 const verificationString = await Redis.Instance.setResetPasswordVerificationString(user.id) 295 const verificationString = await Redis.Instance.setResetPasswordVerificationString(user.id)
296 const url = CONFIG.WEBSERVER.URL + '/reset-password?userId=' + user.id + '&verificationString=' + verificationString 296 const url = CONFIG.WEBSERVER.URL + '/reset-password?userId=' + user.id + '&verificationString=' + verificationString
297 await Emailer.Instance.addForgetPasswordEmailJob(user.email, url) 297 await Emailer.Instance.addPasswordResetEmailJob(user.email, url)
298 298
299 return res.status(204).end() 299 return res.status(204).end()
300} 300}
diff --git a/server/controllers/api/users/me.ts b/server/controllers/api/users/me.ts
index 94a2b8732..d5e154869 100644
--- a/server/controllers/api/users/me.ts
+++ b/server/controllers/api/users/me.ts
@@ -167,7 +167,7 @@ async function deleteMe (req: express.Request, res: express.Response) {
167 return res.sendStatus(204) 167 return res.sendStatus(204)
168} 168}
169 169
170async function updateMe (req: express.Request, res: express.Response, next: express.NextFunction) { 170async function updateMe (req: express.Request, res: express.Response) {
171 const body: UserUpdateMe = req.body 171 const body: UserUpdateMe = req.body
172 172
173 const user: UserModel = res.locals.oauth.token.user 173 const user: UserModel = res.locals.oauth.token.user
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts
index 98f8f8694..e5c4c4e63 100644
--- a/server/initializers/constants.ts
+++ b/server/initializers/constants.ts
@@ -711,6 +711,8 @@ if (isTestInstance() === true) {
711 CACHE.VIDEO_CAPTIONS.MAX_AGE = 3000 711 CACHE.VIDEO_CAPTIONS.MAX_AGE = 3000
712 MEMOIZE_TTL.OVERVIEWS_SAMPLE = 1 712 MEMOIZE_TTL.OVERVIEWS_SAMPLE = 1
713 ROUTE_CACHE_LIFETIME.OVERVIEWS.VIDEOS = '0ms' 713 ROUTE_CACHE_LIFETIME.OVERVIEWS.VIDEOS = '0ms'
714
715 RATES_LIMIT.LOGIN.MAX = 20
714} 716}
715 717
716updateWebserverUrls() 718updateWebserverUrls()
diff --git a/server/lib/emailer.ts b/server/lib/emailer.ts
index 7681164b3..672414cc0 100644
--- a/server/lib/emailer.ts
+++ b/server/lib/emailer.ts
@@ -101,22 +101,6 @@ class Emailer {
101 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) 101 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
102 } 102 }
103 103
104 addForceResetPasswordEmailJob (to: string, resetPasswordUrl: string) {
105 const text = `Hi dear user,\n\n` +
106 `Your password has been reset on ${CONFIG.WEBSERVER.HOST}! ` +
107 `Please follow this link to reset it: ${resetPasswordUrl}\n\n` +
108 `Cheers,\n` +
109 `PeerTube.`
110
111 const emailPayload: EmailPayload = {
112 to: [ to ],
113 subject: 'Reset of your PeerTube password',
114 text
115 }
116
117 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
118 }
119
120 addNewFollowNotification (to: string[], actorFollow: ActorFollowModel, followType: 'account' | 'channel') { 104 addNewFollowNotification (to: string[], actorFollow: ActorFollowModel, followType: 'account' | 'channel') {
121 const followerName = actorFollow.ActorFollower.Account.getDisplayName() 105 const followerName = actorFollow.ActorFollower.Account.getDisplayName()
122 const followingName = (actorFollow.ActorFollowing.VideoChannel || actorFollow.ActorFollowing.Account).getDisplayName() 106 const followingName = (actorFollow.ActorFollowing.VideoChannel || actorFollow.ActorFollowing.Account).getDisplayName()
@@ -312,9 +296,9 @@ class Emailer {
312 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) 296 return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload })
313 } 297 }
314 298
315 addForgetPasswordEmailJob (to: string, resetPasswordUrl: string) { 299 addPasswordResetEmailJob (to: string, resetPasswordUrl: string) {
316 const text = `Hi dear user,\n\n` + 300 const text = `Hi dear user,\n\n` +
317 `It seems you forgot your password on ${CONFIG.WEBSERVER.HOST}! ` + 301 `A reset password procedure for your account ${to} has been requested on ${CONFIG.WEBSERVER.HOST} ` +
318 `Please follow this link to reset it: ${resetPasswordUrl}\n\n` + 302 `Please follow this link to reset it: ${resetPasswordUrl}\n\n` +
319 `If you are not the person who initiated this request, please ignore this email.\n\n` + 303 `If you are not the person who initiated this request, please ignore this email.\n\n` +
320 `Cheers,\n` + 304 `Cheers,\n` +
diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts
index 1bb0bfb1b..a52e3060a 100644
--- a/server/middlewares/validators/users.ts
+++ b/server/middlewares/validators/users.ts
@@ -113,6 +113,7 @@ const deleteMeValidator = [
113 113
114const usersUpdateValidator = [ 114const usersUpdateValidator = [
115 param('id').isInt().not().isEmpty().withMessage('Should have a valid id'), 115 param('id').isInt().not().isEmpty().withMessage('Should have a valid id'),
116 body('password').optional().custom(isUserPasswordValid).withMessage('Should have a valid password'),
116 body('email').optional().isEmail().withMessage('Should have a valid email attribute'), 117 body('email').optional().isEmail().withMessage('Should have a valid email attribute'),
117 body('emailVerified').optional().isBoolean().withMessage('Should have a valid email verified attribute'), 118 body('emailVerified').optional().isBoolean().withMessage('Should have a valid email verified attribute'),
118 body('videoQuota').optional().custom(isUserVideoQuotaValid).withMessage('Should have a valid user quota'), 119 body('videoQuota').optional().custom(isUserVideoQuotaValid).withMessage('Should have a valid user quota'),
@@ -233,6 +234,7 @@ const usersAskResetPasswordValidator = [
233 logger.debug('Checking usersAskResetPassword parameters', { parameters: req.body }) 234 logger.debug('Checking usersAskResetPassword parameters', { parameters: req.body })
234 235
235 if (areValidationErrors(req, res)) return 236 if (areValidationErrors(req, res)) return
237
236 const exists = await checkUserEmailExist(req.body.email, res, false) 238 const exists = await checkUserEmailExist(req.body.email, res, false)
237 if (!exists) { 239 if (!exists) {
238 logger.debug('User with email %s does not exist (asking reset password).', req.body.email) 240 logger.debug('User with email %s does not exist (asking reset password).', req.body.email)
diff --git a/server/tests/api/check-params/users.ts b/server/tests/api/check-params/users.ts
index a3e8e2e9c..13be8b460 100644
--- a/server/tests/api/check-params/users.ts
+++ b/server/tests/api/check-params/users.ts
@@ -464,6 +464,24 @@ describe('Test users API validators', function () {
464 await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields }) 464 await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
465 }) 465 })
466 466
467 it('Should fail with a too small password', async function () {
468 const fields = {
469 currentPassword: 'my super password',
470 password: 'bla'
471 }
472
473 await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
474 })
475
476 it('Should fail with a too long password', async function () {
477 const fields = {
478 currentPassword: 'my super password',
479 password: 'super'.repeat(61)
480 }
481
482 await makePutBodyRequest({ url: server.url, path: path + userId, token: server.accessToken, fields })
483 })
484
467 it('Should fail with an non authenticated user', async function () { 485 it('Should fail with an non authenticated user', async function () {
468 const fields = { 486 const fields = {
469 videoQuota: 42 487 videoQuota: 42
diff --git a/server/tests/api/users/users.ts b/server/tests/api/users/users.ts
index ad98ab1c7..c4465d541 100644
--- a/server/tests/api/users/users.ts
+++ b/server/tests/api/users/users.ts
@@ -501,6 +501,22 @@ describe('Test users', function () {
501 accessTokenUser = await userLogin(server, user) 501 accessTokenUser = await userLogin(server, user)
502 }) 502 })
503 503
504 it('Should be able to update another user password', async function () {
505 await updateUser({
506 url: server.url,
507 userId,
508 accessToken,
509 password: 'password updated'
510 })
511
512 await getMyUserVideoQuotaUsed(server.url, accessTokenUser, 401)
513
514 await userLogin(server, user, 400)
515
516 user.password = 'password updated'
517 accessTokenUser = await userLogin(server, user)
518 })
519
504 it('Should be able to list video blacklist by a moderator', async function () { 520 it('Should be able to list video blacklist by a moderator', async function () {
505 await getBlacklistedVideosList(server.url, accessTokenUser) 521 await getBlacklistedVideosList(server.url, accessTokenUser)
506 }) 522 })