diff --git a/client/src/app/shared/video/video-details.model.ts b/client/src/app/shared/video/video-details.model.ts index 4e4f64c7b..a22ed68da 100644 --- a/client/src/app/shared/video/video-details.model.ts +++ b/client/src/app/shared/video/video-details.model.ts @@ -88,6 +88,6 @@ export class VideoDetails extends Video implements VideoDetailsServerModel { } isUpdatableBy (user: AuthUser) { - return user && this.isLocal === true && user.username === this.accountName + return user && this.isLocal === true && (this.accountName === user.username || user.hasRight(UserRight.UPDATE_ANY_VIDEO)) } } diff --git a/client/src/app/videos/+video-edit/video-update.component.ts b/client/src/app/videos/+video-edit/video-update.component.ts index d97e00a3a..2fc09278c 100644 --- a/client/src/app/videos/+video-edit/video-update.component.ts +++ b/client/src/app/videos/+video-edit/video-update.component.ts @@ -53,9 +53,6 @@ export class VideoUpdateComponent extends FormReactive implements OnInit { this.serverService.videoPrivaciesLoaded .subscribe(() => this.videoPrivacies = this.serverService.getVideoPrivacies()) - populateAsyncUserVideoChannels(this.authService, this.userVideoChannels) - .catch(err => console.error('Cannot populate async user video channels.', err)) - const uuid: string = this.route.snapshot.params['uuid'] this.videoService.getVideo(uuid) .switchMap(video => { @@ -67,6 +64,13 @@ export class VideoUpdateComponent extends FormReactive implements OnInit { video => { this.video = new VideoEdit(video) + this.userVideoChannels = [ + { + id: video.channel.id, + label: video.channel.displayName + } + ] + // We cannot set private a video that was not private if (video.privacy !== VideoPrivacy.PRIVATE) { const newVideoPrivacies = [] diff --git a/server/middlewares/validators/videos.ts b/server/middlewares/validators/videos.ts index e91739f81..1dc8429c8 100644 --- a/server/middlewares/validators/videos.ts +++ b/server/middlewares/validators/videos.ts @@ -130,18 +130,8 @@ const videosUpdateValidator = [ const video = res.locals.video - // We need to make additional checks - if (video.isOwned() === false) { - return res.status(403) - .json({ error: 'Cannot update video of another server' }) - .end() - } - - if (video.VideoChannel.Account.userId !== res.locals.oauth.token.User.id) { - return res.status(403) - .json({ error: 'Cannot update video of another user' }) - .end() - } + // Check if the user who did the request is able to update the video + if (!checkUserCanManageVideo(res.locals.oauth.token.User, res.locals.video, UserRight.UPDATE_ANY_VIDEO, res)) return if (video.privacy !== VideoPrivacy.PRIVATE && req.body.privacy === VideoPrivacy.PRIVATE) { return res.status(409) @@ -198,7 +188,7 @@ const videosRemoveValidator = [ if (!await isVideoExist(req.params.id, res)) return // Check if the user who did the request is able to delete the video - if (!checkUserCanDeleteVideo(res.locals.oauth.token.User, res.locals.video, res)) return + if (!checkUserCanManageVideo(res.locals.oauth.token.User, res.locals.video, UserRight.REMOVE_ANY_VIDEO, res)) return return next() } @@ -282,7 +272,7 @@ export { // --------------------------------------------------------------------------- -function checkUserCanDeleteVideo (user: UserModel, video: VideoModel, res: express.Response) { +function checkUserCanManageVideo (user: UserModel, video: VideoModel, right: UserRight, res: express.Response) { // Retrieve the user who did the request if (video.isOwned() === false) { res.status(403) @@ -295,7 +285,7 @@ function checkUserCanDeleteVideo (user: UserModel, video: VideoModel, res: expre // The user can delete it if he has the right // Or if s/he is the video's account const account = video.VideoChannel.Account - if (user.hasRight(UserRight.REMOVE_ANY_VIDEO) === false && account.userId !== user.id) { + if (user.hasRight(right) === false && account.userId !== user.id) { res.status(403) .json({ error: 'Cannot remove video of another user' }) .end() diff --git a/server/tests/api/check-params/videos.ts b/server/tests/api/check-params/videos.ts index 1d5c8543d..1d19daa60 100644 --- a/server/tests/api/check-params/videos.ts +++ b/server/tests/api/check-params/videos.ts @@ -16,7 +16,9 @@ const expect = chai.expect describe('Test videos API validator', function () { const path = '/api/v1/videos/' let server: ServerInfo + let userAccessToken = '' let channelId: number + let videoId // --------------------------------------------------------------- @@ -29,6 +31,11 @@ describe('Test videos API validator', function () { await setAccessTokensToServers([ server ]) + const username = 'user1' + const password = 'my super password' + await createUser(server.url, server.accessToken, username, password) + userAccessToken = await userLogin(server, { username, password }) + const res = await getMyUserInformation(server.url, server.accessToken) channelId = res.body.videoChannels[0].id }) @@ -359,11 +366,10 @@ describe('Test videos API validator', function () { privacy: VideoPrivacy.PUBLIC, tags: [ 'tag1', 'tag2' ] } - let videoId before(async function () { const res = await getVideosList(server.url) - videoId = res.body.data[0].id + videoId = res.body.data[0].uuid }) it('Should fail with nothing', async function () { @@ -518,7 +524,11 @@ describe('Test videos API validator', function () { }) }) - it('Should fail with a video of another user') + it('Should fail with a video of another user without the appropriate right', async function () { + const fields = baseCorrectParams + + await makePutBodyRequest({ url: server.url, path: path + videoId, token: userAccessToken, fields, statusCodeExpected: 403 }) + }) it('Should fail with a video of another server') @@ -549,7 +559,9 @@ describe('Test videos API validator', function () { await getVideo(server.url, '4da6fde3-88f7-4d16-b119-108df5630b06', 404) }) - it('Should succeed with the correct parameters') + it('Should succeed with the correct parameters', async function () { + await getVideo(server.url, videoId) + }) }) describe('When rating a video', function () { @@ -618,11 +630,15 @@ describe('Test videos API validator', function () { await removeVideo(server.url, server.accessToken, '4da6fde3-88f7-4d16-b119-108df5630b06', 404) }) - it('Should fail with a video of another user') + it('Should fail with a video of another user without the appropriate right', async function () { + await removeVideo(server.url, userAccessToken, videoId, 403) + }) it('Should fail with a video of another server') - it('Should succeed with the correct parameters') + it('Should succeed with the correct parameters', async function () { + await removeVideo(server.url, server.accessToken, videoId) + }) }) after(async function () { diff --git a/shared/models/users/user-right.enum.ts b/shared/models/users/user-right.enum.ts index 1fa149999..ff6ec61f4 100644 --- a/shared/models/users/user-right.enum.ts +++ b/shared/models/users/user-right.enum.ts @@ -8,5 +8,6 @@ export enum UserRight { MANAGE_CONFIGURATION, REMOVE_ANY_VIDEO, REMOVE_ANY_VIDEO_CHANNEL, - REMOVE_ANY_VIDEO_COMMENT + REMOVE_ANY_VIDEO_COMMENT, + UPDATE_ANY_VIDEO } diff --git a/shared/models/users/user-role.ts b/shared/models/users/user-role.ts index 271c9a46f..552aad999 100644 --- a/shared/models/users/user-role.ts +++ b/shared/models/users/user-role.ts @@ -25,7 +25,8 @@ const userRoleRights: { [ id: number ]: UserRight[] } = { UserRight.MANAGE_VIDEO_ABUSES, UserRight.REMOVE_ANY_VIDEO, UserRight.REMOVE_ANY_VIDEO_CHANNEL, - UserRight.REMOVE_ANY_VIDEO_COMMENT + UserRight.REMOVE_ANY_VIDEO_COMMENT, + UserRight.UPDATE_ANY_VIDEO ], [UserRole.USER]: []