diff options
author | kontrollanten <6680299+kontrollanten@users.noreply.github.com> | 2021-12-13 15:29:13 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-13 15:29:13 +0100 |
commit | a37e9e74ff07b057370d1ed6c0b391a02be8a6d2 (patch) | |
tree | 30d59e12518149a309bbd10bee1485f8be523c75 /server/middlewares/validators | |
parent | 11e520b50d791a0dd48cbb2d0fc681b25eb7cd53 (diff) | |
download | PeerTube-a37e9e74ff07b057370d1ed6c0b391a02be8a6d2.tar.gz PeerTube-a37e9e74ff07b057370d1ed6c0b391a02be8a6d2.tar.zst PeerTube-a37e9e74ff07b057370d1ed6c0b391a02be8a6d2.zip |
Give moderators access to edit channels (#4608)
* give admins access to edit all channels
closes #4598
* test(channels): +admin update another users channel
* Fix tests
* fix(server): delete another users channel
Since the channel owner isn't necessary the auth user we need to check
the right account whether it's the last video or not.
* REMOVE_ANY_VIDEO_CHANNEL > MANAGE_ANY_VIDEO_CHANNEL
Merge REMOVE_ANY_VIDEO_CHANNEL and MANY_VIDEO_CHANNELS to
MANAGE_ANY_VIDEO_CHANNEL.
* user-right: moderator can't manage admins channel
* client: MyVideoChannelCreateComponent > VideoChannelCreateComponent
* client: MyVideoChannelEdit > VideoChannelEdit
* Revert "user-right: moderator can't manage admins channel"
This reverts commit 2c627c154e2bfe6af2e0f45efb27faf4117572f3.
* server: clean dupl validator functionality
* fix ensureUserCanManageChannel usage
It's not async anymore.
* server: merge channel validator middleares
ensureAuthUserOwnsChannelValidator & ensureUserCanManageChannel gets
merged into one middleware.
* client(VideoChannelEdit): redirect to prev route
* fix(VideoChannels): handle anon users
* client: new routes for create/update channel
* Refactor channel validators
Co-authored-by: Chocobozzz <me@florianbigard.com>
Diffstat (limited to 'server/middlewares/validators')
-rw-r--r-- | server/middlewares/validators/shared/video-channels.ts | 7 | ||||
-rw-r--r-- | server/middlewares/validators/users.ts | 17 | ||||
-rw-r--r-- | server/middlewares/validators/videos/video-channels.ts | 60 |
3 files changed, 25 insertions, 59 deletions
diff --git a/server/middlewares/validators/shared/video-channels.ts b/server/middlewares/validators/shared/video-channels.ts index 7c0c89267..bed9f5dbe 100644 --- a/server/middlewares/validators/shared/video-channels.ts +++ b/server/middlewares/validators/shared/video-channels.ts | |||
@@ -3,12 +3,6 @@ import { VideoChannelModel } from '@server/models/video/video-channel' | |||
3 | import { MChannelBannerAccountDefault } from '@server/types/models' | 3 | import { MChannelBannerAccountDefault } from '@server/types/models' |
4 | import { HttpStatusCode } from '@shared/models' | 4 | import { HttpStatusCode } from '@shared/models' |
5 | 5 | ||
6 | async function doesLocalVideoChannelNameExist (name: string, res: express.Response) { | ||
7 | const videoChannel = await VideoChannelModel.loadLocalByNameAndPopulateAccount(name) | ||
8 | |||
9 | return processVideoChannelExist(videoChannel, res) | ||
10 | } | ||
11 | |||
12 | async function doesVideoChannelIdExist (id: number, res: express.Response) { | 6 | async function doesVideoChannelIdExist (id: number, res: express.Response) { |
13 | const videoChannel = await VideoChannelModel.loadAndPopulateAccount(+id) | 7 | const videoChannel = await VideoChannelModel.loadAndPopulateAccount(+id) |
14 | 8 | ||
@@ -24,7 +18,6 @@ async function doesVideoChannelNameWithHostExist (nameWithDomain: string, res: e | |||
24 | // --------------------------------------------------------------------------- | 18 | // --------------------------------------------------------------------------- |
25 | 19 | ||
26 | export { | 20 | export { |
27 | doesLocalVideoChannelNameExist, | ||
28 | doesVideoChannelIdExist, | 21 | doesVideoChannelIdExist, |
29 | doesVideoChannelNameWithHostExist | 22 | doesVideoChannelNameWithHostExist |
30 | } | 23 | } |
diff --git a/server/middlewares/validators/users.ts b/server/middlewares/validators/users.ts index 33b31d54b..7a6b2ce57 100644 --- a/server/middlewares/validators/users.ts +++ b/server/middlewares/validators/users.ts | |||
@@ -3,7 +3,7 @@ import { body, param, query } from 'express-validator' | |||
3 | import { omit } from 'lodash' | 3 | import { omit } from 'lodash' |
4 | import { Hooks } from '@server/lib/plugins/hooks' | 4 | import { Hooks } from '@server/lib/plugins/hooks' |
5 | import { MUserDefault } from '@server/types/models' | 5 | import { MUserDefault } from '@server/types/models' |
6 | import { HttpStatusCode, UserRegister, UserRole } from '@shared/models' | 6 | import { HttpStatusCode, UserRegister, UserRight, UserRole } from '@shared/models' |
7 | import { isBooleanValid, isIdValid, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc' | 7 | import { isBooleanValid, isIdValid, toBooleanOrNull, toIntOrNull } from '../../helpers/custom-validators/misc' |
8 | import { isThemeNameValid } from '../../helpers/custom-validators/plugins' | 8 | import { isThemeNameValid } from '../../helpers/custom-validators/plugins' |
9 | import { | 9 | import { |
@@ -490,14 +490,17 @@ const ensureAuthUserOwnsAccountValidator = [ | |||
490 | } | 490 | } |
491 | ] | 491 | ] |
492 | 492 | ||
493 | const ensureAuthUserOwnsChannelValidator = [ | 493 | const ensureCanManageChannel = [ |
494 | (req: express.Request, res: express.Response, next: express.NextFunction) => { | 494 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
495 | const user = res.locals.oauth.token.User | 495 | const user = res.locals.oauth.token.user |
496 | const isUserOwner = res.locals.videoChannel.Account.userId === user.id | ||
497 | |||
498 | if (!isUserOwner && user.hasRight(UserRight.MANAGE_ANY_VIDEO_CHANNEL) === false) { | ||
499 | const message = `User ${user.username} does not have right to manage channel ${req.params.nameWithHost}.` | ||
496 | 500 | ||
497 | if (res.locals.videoChannel.Account.userId !== user.id) { | ||
498 | return res.fail({ | 501 | return res.fail({ |
499 | status: HttpStatusCode.FORBIDDEN_403, | 502 | status: HttpStatusCode.FORBIDDEN_403, |
500 | message: 'Only owner of this video channel can access this ressource' | 503 | message |
501 | }) | 504 | }) |
502 | } | 505 | } |
503 | 506 | ||
@@ -542,8 +545,8 @@ export { | |||
542 | usersVerifyEmailValidator, | 545 | usersVerifyEmailValidator, |
543 | userAutocompleteValidator, | 546 | userAutocompleteValidator, |
544 | ensureAuthUserOwnsAccountValidator, | 547 | ensureAuthUserOwnsAccountValidator, |
545 | ensureAuthUserOwnsChannelValidator, | 548 | ensureCanManageUser, |
546 | ensureCanManageUser | 549 | ensureCanManageChannel |
547 | } | 550 | } |
548 | 551 | ||
549 | // --------------------------------------------------------------------------- | 552 | // --------------------------------------------------------------------------- |
diff --git a/server/middlewares/validators/videos/video-channels.ts b/server/middlewares/validators/videos/video-channels.ts index edce48c7f..3bfdebbb1 100644 --- a/server/middlewares/validators/videos/video-channels.ts +++ b/server/middlewares/validators/videos/video-channels.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { body, param, query } from 'express-validator' | 2 | import { body, param, query } from 'express-validator' |
3 | import { MChannelAccountDefault, MUser } from '@server/types/models' | 3 | import { CONFIG } from '@server/initializers/config' |
4 | import { UserRight } from '../../../../shared' | 4 | import { MChannelAccountDefault } from '@server/types/models' |
5 | import { HttpStatusCode } from '../../../../shared/models/http/http-error-codes' | 5 | import { HttpStatusCode } from '../../../../shared/models/http/http-error-codes' |
6 | import { isBooleanValid, toBooleanOrNull } from '../../../helpers/custom-validators/misc' | 6 | import { isBooleanValid, toBooleanOrNull } from '../../../helpers/custom-validators/misc' |
7 | import { | 7 | import { |
@@ -13,8 +13,7 @@ import { | |||
13 | import { logger } from '../../../helpers/logger' | 13 | import { logger } from '../../../helpers/logger' |
14 | import { ActorModel } from '../../../models/actor/actor' | 14 | import { ActorModel } from '../../../models/actor/actor' |
15 | import { VideoChannelModel } from '../../../models/video/video-channel' | 15 | import { VideoChannelModel } from '../../../models/video/video-channel' |
16 | import { areValidationErrors, doesLocalVideoChannelNameExist, doesVideoChannelNameWithHostExist } from '../shared' | 16 | import { areValidationErrors, doesVideoChannelNameWithHostExist } from '../shared' |
17 | import { CONFIG } from '@server/initializers/config' | ||
18 | 17 | ||
19 | const videoChannelsAddValidator = [ | 18 | const videoChannelsAddValidator = [ |
20 | body('name').custom(isVideoChannelUsernameValid).withMessage('Should have a valid channel name'), | 19 | body('name').custom(isVideoChannelUsernameValid).withMessage('Should have a valid channel name'), |
@@ -71,16 +70,10 @@ const videoChannelsUpdateValidator = [ | |||
71 | ] | 70 | ] |
72 | 71 | ||
73 | const videoChannelsRemoveValidator = [ | 72 | const videoChannelsRemoveValidator = [ |
74 | param('nameWithHost').exists().withMessage('Should have an video channel name with host'), | ||
75 | |||
76 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 73 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { |
77 | logger.debug('Checking videoChannelsRemove parameters', { parameters: req.params }) | 74 | logger.debug('Checking videoChannelsRemove parameters', { parameters: req.params }) |
78 | 75 | ||
79 | if (areValidationErrors(req, res)) return | 76 | if (!await checkVideoChannelIsNotTheLastOne(res.locals.videoChannel, res)) return |
80 | if (!await doesVideoChannelNameWithHostExist(req.params.nameWithHost, res)) return | ||
81 | |||
82 | if (!checkUserCanDeleteVideoChannel(res.locals.oauth.token.User, res.locals.videoChannel, res)) return | ||
83 | if (!await checkVideoChannelIsNotTheLastOne(res)) return | ||
84 | 77 | ||
85 | return next() | 78 | return next() |
86 | } | 79 | } |
@@ -100,14 +93,14 @@ const videoChannelsNameWithHostValidator = [ | |||
100 | } | 93 | } |
101 | ] | 94 | ] |
102 | 95 | ||
103 | const localVideoChannelValidator = [ | 96 | const ensureIsLocalChannel = [ |
104 | param('name').custom(isVideoChannelDisplayNameValid).withMessage('Should have a valid video channel name'), | 97 | (req: express.Request, res: express.Response, next: express.NextFunction) => { |
105 | 98 | if (res.locals.videoChannel.Actor.isOwned() === false) { | |
106 | async (req: express.Request, res: express.Response, next: express.NextFunction) => { | 99 | return res.fail({ |
107 | logger.debug('Checking localVideoChannelValidator parameters', { parameters: req.params }) | 100 | status: HttpStatusCode.FORBIDDEN_403, |
108 | 101 | message: 'This channel is not owned.' | |
109 | if (areValidationErrors(req, res)) return | 102 | }) |
110 | if (!await doesLocalVideoChannelNameExist(req.params.name, res)) return | 103 | } |
111 | 104 | ||
112 | return next() | 105 | return next() |
113 | } | 106 | } |
@@ -144,38 +137,15 @@ export { | |||
144 | videoChannelsUpdateValidator, | 137 | videoChannelsUpdateValidator, |
145 | videoChannelsRemoveValidator, | 138 | videoChannelsRemoveValidator, |
146 | videoChannelsNameWithHostValidator, | 139 | videoChannelsNameWithHostValidator, |
140 | ensureIsLocalChannel, | ||
147 | videoChannelsListValidator, | 141 | videoChannelsListValidator, |
148 | localVideoChannelValidator, | ||
149 | videoChannelStatsValidator | 142 | videoChannelStatsValidator |
150 | } | 143 | } |
151 | 144 | ||
152 | // --------------------------------------------------------------------------- | 145 | // --------------------------------------------------------------------------- |
153 | 146 | ||
154 | function checkUserCanDeleteVideoChannel (user: MUser, videoChannel: MChannelAccountDefault, res: express.Response) { | 147 | async function checkVideoChannelIsNotTheLastOne (videoChannel: MChannelAccountDefault, res: express.Response) { |
155 | if (videoChannel.Actor.isOwned() === false) { | 148 | const count = await VideoChannelModel.countByAccount(videoChannel.Account.id) |
156 | res.fail({ | ||
157 | status: HttpStatusCode.FORBIDDEN_403, | ||
158 | message: 'Cannot remove video channel of another server.' | ||
159 | }) | ||
160 | return false | ||
161 | } | ||
162 | |||
163 | // Check if the user can delete the video channel | ||
164 | // The user can delete it if s/he is an admin | ||
165 | // Or if s/he is the video channel's account | ||
166 | if (user.hasRight(UserRight.REMOVE_ANY_VIDEO_CHANNEL) === false && videoChannel.Account.userId !== user.id) { | ||
167 | res.fail({ | ||
168 | status: HttpStatusCode.FORBIDDEN_403, | ||
169 | message: 'Cannot remove video channel of another user' | ||
170 | }) | ||
171 | return false | ||
172 | } | ||
173 | |||
174 | return true | ||
175 | } | ||
176 | |||
177 | async function checkVideoChannelIsNotTheLastOne (res: express.Response) { | ||
178 | const count = await VideoChannelModel.countByAccount(res.locals.oauth.token.User.Account.id) | ||
179 | 149 | ||
180 | if (count <= 1) { | 150 | if (count <= 1) { |
181 | res.fail({ | 151 | res.fail({ |