]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/middlewares/validators/shared/videos.ts
Add ability to get user from file token
[github/Chocobozzz/PeerTube.git] / server / middlewares / validators / shared / videos.ts
CommitLineData
795212f7 1import { Request, Response } from 'express'
868fce62 2import { loadVideo, VideoLoadType } from '@server/lib/model-loaders'
c729caf6 3import { isAbleToUploadVideo } from '@server/lib/user'
3545e72c 4import { VideoTokensManager } from '@server/lib/video-tokens-manager'
2c2befaa 5import { authenticatePromise } from '@server/middlewares/auth'
795212f7 6import { VideoModel } from '@server/models/video/video'
10363c74
C
7import { VideoChannelModel } from '@server/models/video/video-channel'
8import { VideoFileModel } from '@server/models/video/video-file'
7eba5e1f
C
9import {
10 MUser,
11 MUserAccountId,
c729caf6 12 MUserId,
795212f7 13 MVideo,
7eba5e1f 14 MVideoAccountLight,
ca4b4b2e 15 MVideoFormattableDetails,
7eba5e1f 16 MVideoFullLight,
71d4af1e 17 MVideoId,
7eba5e1f 18 MVideoImmutable,
795212f7
C
19 MVideoThumbnail,
20 MVideoWithRights
26d6bf65 21} from '@server/types/models'
ff9d43f6 22import { HttpStatusCode, ServerErrorCode, UserRight, VideoPrivacy } from '@shared/models'
3e753302 23
868fce62 24async function doesVideoExist (id: number | string, res: Response, fetchType: VideoLoadType = 'all') {
3e753302
C
25 const userId = res.locals.oauth ? res.locals.oauth.token.User.id : undefined
26
868fce62 27 const video = await loadVideo(id, fetchType, userId)
3e753302 28
ff9d43f6 29 if (!video) {
76148b27
RK
30 res.fail({
31 status: HttpStatusCode.NOT_FOUND_404,
32 message: 'Video not found'
33 })
ff9d43f6 34
3e753302
C
35 return false
36 }
37
453e83ea 38 switch (fetchType) {
ca4b4b2e
C
39 case 'for-api':
40 res.locals.videoAPI = video as MVideoFormattableDetails
41 break
42
453e83ea
C
43 case 'all':
44 res.locals.videoAll = video as MVideoFullLight
45 break
46
7eba5e1f
C
47 case 'only-immutable-attributes':
48 res.locals.onlyImmutableVideo = video as MVideoImmutable
49 break
50
453e83ea 51 case 'id':
71d4af1e 52 res.locals.videoId = video as MVideoId
453e83ea
C
53 break
54
55 case 'only-video':
0283eaac 56 res.locals.onlyVideo = video as MVideoThumbnail
453e83ea 57 break
453e83ea
C
58 }
59
3e753302
C
60 return true
61}
62
ff9d43f6
C
63// ---------------------------------------------------------------------------
64
8319d6ae
RK
65async function doesVideoFileOfVideoExist (id: number, videoIdOrUUID: number | string, res: Response) {
66 if (!await VideoFileModel.doesVideoExistForVideoFile(id, videoIdOrUUID)) {
76148b27
RK
67 res.fail({
68 status: HttpStatusCode.NOT_FOUND_404,
69 message: 'VideoFile matching Video not found'
70 })
8319d6ae
RK
71 return false
72 }
73
74 return true
75}
76
ff9d43f6
C
77// ---------------------------------------------------------------------------
78
453e83ea 79async function doesVideoChannelOfAccountExist (channelId: number, user: MUserAccountId, res: Response) {
2cb03dc1 80 const videoChannel = await VideoChannelModel.loadAndPopulateAccount(channelId)
3e753302 81
2cb03dc1 82 if (videoChannel === null) {
76148b27 83 res.fail({ message: 'Unknown video "video channel" for this instance.' })
2cb03dc1
C
84 return false
85 }
86
87 // Don't check account id if the user can update any video
88 if (user.hasRight(UserRight.UPDATE_ANY_VIDEO) === true) {
3e753302
C
89 res.locals.videoChannel = videoChannel
90 return true
91 }
92
2cb03dc1 93 if (videoChannel.Account.id !== user.Account.id) {
76148b27
RK
94 res.fail({
95 message: 'Unknown video "video channel" for this account.'
96 })
3e753302
C
97 return false
98 }
99
100 res.locals.videoChannel = videoChannel
101 return true
102}
103
ff9d43f6 104// ---------------------------------------------------------------------------
795212f7 105
ff9d43f6
C
106async function checkCanSeeVideo (options: {
107 req: Request
108 res: Response
109 paramId: string
110 video: MVideo
ff9d43f6 111}) {
3545e72c 112 const { req, res, video, paramId } = options
ff9d43f6 113
9ab330b9 114 if (video.requiresAuth({ urlParamId: paramId, checkBlacklist: true })) {
3545e72c 115 return checkCanSeeAuthVideo(req, res, video)
ff9d43f6 116 }
795212f7 117
3545e72c
C
118 if (video.privacy === VideoPrivacy.UNLISTED || video.privacy === VideoPrivacy.PUBLIC) {
119 return true
ff9d43f6 120 }
795212f7 121
3545e72c 122 throw new Error('Unknown video privacy when checking video right ' + video.url)
ff9d43f6 123}
795212f7 124
3545e72c 125async function checkCanSeeAuthVideo (req: Request, res: Response, video: MVideoId | MVideoWithRights) {
ff9d43f6 126 const fail = () => {
c729caf6
C
127 res.fail({
128 status: HttpStatusCode.FORBIDDEN_403,
ff9d43f6 129 message: 'Cannot fetch information of private/internal/blocked video'
c729caf6
C
130 })
131
795212f7
C
132 return false
133 }
134
3545e72c 135 await authenticatePromise(req, res)
ff9d43f6
C
136
137 const user = res.locals.oauth?.token.User
138 if (!user) return fail()
139
140 const videoWithRights = (video as MVideoWithRights).VideoChannel?.Account?.userId
141 ? video as MVideoWithRights
4fae2b1f 142 : await VideoModel.loadFull(video.id)
ff9d43f6
C
143
144 const privacy = videoWithRights.privacy
145
146 if (privacy === VideoPrivacy.INTERNAL) {
147 // We know we have a user
148 return true
149 }
150
151 const isOwnedByUser = videoWithRights.VideoChannel.Account.userId === user.id
2c2befaa
C
152
153 if (videoWithRights.isBlacklisted()) {
154 if (isOwnedByUser || user.hasRight(UserRight.MANAGE_VIDEO_BLACKLIST)) return true
ff9d43f6
C
155
156 return fail()
157 }
158
2c2befaa
C
159 if (privacy === VideoPrivacy.PRIVATE || privacy === VideoPrivacy.UNLISTED) {
160 if (isOwnedByUser || user.hasRight(UserRight.SEE_ALL_VIDEOS)) return true
ff9d43f6
C
161
162 return fail()
163 }
164
165 // Should not happen
166 return fail()
795212f7
C
167}
168
ff9d43f6
C
169// ---------------------------------------------------------------------------
170
3545e72c
C
171async function checkCanAccessVideoStaticFiles (options: {
172 video: MVideo
173 req: Request
174 res: Response
175 paramId: string
176}) {
9ab330b9 177 const { video, req, res } = options
3545e72c
C
178
179 if (res.locals.oauth?.token.User) {
180 return checkCanSeeVideo(options)
181 }
182
3545e72c 183 const videoFileToken = req.query.videoFileToken
868314e8
C
184 if (videoFileToken && VideoTokensManager.Instance.hasToken({ token: videoFileToken, videoUUID: video.uuid })) {
185 const user = VideoTokensManager.Instance.getUserFromToken({ token: videoFileToken })
3545e72c 186
868314e8 187 res.locals.videoFileToken = { user }
3545e72c
C
188 return true
189 }
190
868314e8
C
191 if (!video.hasPrivateStaticPath()) return true
192
3545e72c
C
193 res.sendStatus(HttpStatusCode.FORBIDDEN_403)
194 return false
195}
196
197// ---------------------------------------------------------------------------
198
af4ae64f 199function checkUserCanManageVideo (user: MUser, video: MVideoAccountLight, right: UserRight, res: Response, onlyOwned = true) {
3e753302 200 // Retrieve the user who did the request
af4ae64f 201 if (onlyOwned && video.isOwned() === false) {
76148b27
RK
202 res.fail({
203 status: HttpStatusCode.FORBIDDEN_403,
204 message: 'Cannot manage a video of another server.'
205 })
3e753302
C
206 return false
207 }
208
209 // Check if the user can delete the video
210 // The user can delete it if he has the right
211 // Or if s/he is the video's account
212 const account = video.VideoChannel.Account
213 if (user.hasRight(right) === false && account.userId !== user.id) {
76148b27
RK
214 res.fail({
215 status: HttpStatusCode.FORBIDDEN_403,
216 message: 'Cannot manage a video of another user.'
217 })
3e753302
C
218 return false
219 }
220
221 return true
222}
223
ff9d43f6
C
224// ---------------------------------------------------------------------------
225
c729caf6
C
226async function checkUserQuota (user: MUserId, videoFileSize: number, res: Response) {
227 if (await isAbleToUploadVideo(user.id, videoFileSize) === false) {
228 res.fail({
229 status: HttpStatusCode.PAYLOAD_TOO_LARGE_413,
230 message: 'The user video quota is exceeded with this video.',
231 type: ServerErrorCode.QUOTA_REACHED
232 })
233 return false
234 }
235
236 return true
237}
238
3e753302
C
239// ---------------------------------------------------------------------------
240
241export {
242 doesVideoChannelOfAccountExist,
243 doesVideoExist,
8319d6ae 244 doesVideoFileOfVideoExist,
c729caf6 245
3545e72c 246 checkCanAccessVideoStaticFiles,
795212f7 247 checkUserCanManageVideo,
ff9d43f6 248 checkCanSeeVideo,
c729caf6 249 checkUserQuota
3e753302 250}