videos.ts 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. import { Request, Response } from 'express'
  2. import { loadVideo, VideoLoadType } from '@server/lib/model-loaders'
  3. import { isAbleToUploadVideo } from '@server/lib/user'
  4. import { VideoTokensManager } from '@server/lib/video-tokens-manager'
  5. import { authenticatePromise } from '@server/middlewares/auth'
  6. import { VideoModel } from '@server/models/video/video'
  7. import { VideoChannelModel } from '@server/models/video/video-channel'
  8. import { VideoFileModel } from '@server/models/video/video-file'
  9. import {
  10. MUser,
  11. MUserAccountId,
  12. MUserId,
  13. MVideo,
  14. MVideoAccountLight,
  15. MVideoFormattableDetails,
  16. MVideoFullLight,
  17. MVideoId,
  18. MVideoImmutable,
  19. MVideoThumbnail,
  20. MVideoWithRights
  21. } from '@server/types/models'
  22. import { HttpStatusCode, ServerErrorCode, UserRight, VideoPrivacy } from '@shared/models'
  23. async function doesVideoExist (id: number | string, res: Response, fetchType: VideoLoadType = 'all') {
  24. const userId = res.locals.oauth ? res.locals.oauth.token.User.id : undefined
  25. const video = await loadVideo(id, fetchType, userId)
  26. if (!video) {
  27. res.fail({
  28. status: HttpStatusCode.NOT_FOUND_404,
  29. message: 'Video not found'
  30. })
  31. return false
  32. }
  33. switch (fetchType) {
  34. case 'for-api':
  35. res.locals.videoAPI = video as MVideoFormattableDetails
  36. break
  37. case 'all':
  38. res.locals.videoAll = video as MVideoFullLight
  39. break
  40. case 'only-immutable-attributes':
  41. res.locals.onlyImmutableVideo = video as MVideoImmutable
  42. break
  43. case 'id':
  44. res.locals.videoId = video as MVideoId
  45. break
  46. case 'only-video':
  47. res.locals.onlyVideo = video as MVideoThumbnail
  48. break
  49. }
  50. return true
  51. }
  52. // ---------------------------------------------------------------------------
  53. async function doesVideoFileOfVideoExist (id: number, videoIdOrUUID: number | string, res: Response) {
  54. if (!await VideoFileModel.doesVideoExistForVideoFile(id, videoIdOrUUID)) {
  55. res.fail({
  56. status: HttpStatusCode.NOT_FOUND_404,
  57. message: 'VideoFile matching Video not found'
  58. })
  59. return false
  60. }
  61. return true
  62. }
  63. // ---------------------------------------------------------------------------
  64. async function doesVideoChannelOfAccountExist (channelId: number, user: MUserAccountId, res: Response) {
  65. const videoChannel = await VideoChannelModel.loadAndPopulateAccount(channelId)
  66. if (videoChannel === null) {
  67. res.fail({ message: 'Unknown video "video channel" for this instance.' })
  68. return false
  69. }
  70. // Don't check account id if the user can update any video
  71. if (user.hasRight(UserRight.UPDATE_ANY_VIDEO) === true) {
  72. res.locals.videoChannel = videoChannel
  73. return true
  74. }
  75. if (videoChannel.Account.id !== user.Account.id) {
  76. res.fail({
  77. message: 'Unknown video "video channel" for this account.'
  78. })
  79. return false
  80. }
  81. res.locals.videoChannel = videoChannel
  82. return true
  83. }
  84. // ---------------------------------------------------------------------------
  85. async function checkCanSeeVideo (options: {
  86. req: Request
  87. res: Response
  88. paramId: string
  89. video: MVideo
  90. }) {
  91. const { req, res, video, paramId } = options
  92. if (video.requiresAuth({ urlParamId: paramId, checkBlacklist: true })) {
  93. return checkCanSeeAuthVideo(req, res, video)
  94. }
  95. if (video.privacy === VideoPrivacy.UNLISTED || video.privacy === VideoPrivacy.PUBLIC) {
  96. return true
  97. }
  98. throw new Error('Unknown video privacy when checking video right ' + video.url)
  99. }
  100. async function checkCanSeeAuthVideo (req: Request, res: Response, video: MVideoId | MVideoWithRights) {
  101. const fail = () => {
  102. res.fail({
  103. status: HttpStatusCode.FORBIDDEN_403,
  104. message: 'Cannot fetch information of private/internal/blocked video'
  105. })
  106. return false
  107. }
  108. await authenticatePromise(req, res)
  109. const user = res.locals.oauth?.token.User
  110. if (!user) return fail()
  111. const videoWithRights = (video as MVideoWithRights).VideoChannel?.Account?.userId
  112. ? video as MVideoWithRights
  113. : await VideoModel.loadFull(video.id)
  114. const privacy = videoWithRights.privacy
  115. if (privacy === VideoPrivacy.INTERNAL) {
  116. // We know we have a user
  117. return true
  118. }
  119. const isOwnedByUser = videoWithRights.VideoChannel.Account.userId === user.id
  120. if (videoWithRights.isBlacklisted()) {
  121. if (isOwnedByUser || user.hasRight(UserRight.MANAGE_VIDEO_BLACKLIST)) return true
  122. return fail()
  123. }
  124. if (privacy === VideoPrivacy.PRIVATE || privacy === VideoPrivacy.UNLISTED) {
  125. if (isOwnedByUser || user.hasRight(UserRight.SEE_ALL_VIDEOS)) return true
  126. return fail()
  127. }
  128. // Should not happen
  129. return fail()
  130. }
  131. // ---------------------------------------------------------------------------
  132. async function checkCanAccessVideoStaticFiles (options: {
  133. video: MVideo
  134. req: Request
  135. res: Response
  136. paramId: string
  137. }) {
  138. const { video, req, res } = options
  139. if (res.locals.oauth?.token.User) {
  140. return checkCanSeeVideo(options)
  141. }
  142. const videoFileToken = req.query.videoFileToken
  143. if (videoFileToken && VideoTokensManager.Instance.hasToken({ token: videoFileToken, videoUUID: video.uuid })) {
  144. const user = VideoTokensManager.Instance.getUserFromToken({ token: videoFileToken })
  145. res.locals.videoFileToken = { user }
  146. return true
  147. }
  148. if (!video.hasPrivateStaticPath()) return true
  149. res.sendStatus(HttpStatusCode.FORBIDDEN_403)
  150. return false
  151. }
  152. // ---------------------------------------------------------------------------
  153. function checkUserCanManageVideo (user: MUser, video: MVideoAccountLight, right: UserRight, res: Response, onlyOwned = true) {
  154. // Retrieve the user who did the request
  155. if (onlyOwned && video.isOwned() === false) {
  156. res.fail({
  157. status: HttpStatusCode.FORBIDDEN_403,
  158. message: 'Cannot manage a video of another server.'
  159. })
  160. return false
  161. }
  162. // Check if the user can delete the video
  163. // The user can delete it if he has the right
  164. // Or if s/he is the video's account
  165. const account = video.VideoChannel.Account
  166. if (user.hasRight(right) === false && account.userId !== user.id) {
  167. res.fail({
  168. status: HttpStatusCode.FORBIDDEN_403,
  169. message: 'Cannot manage a video of another user.'
  170. })
  171. return false
  172. }
  173. return true
  174. }
  175. // ---------------------------------------------------------------------------
  176. async function checkUserQuota (user: MUserId, videoFileSize: number, res: Response) {
  177. if (await isAbleToUploadVideo(user.id, videoFileSize) === false) {
  178. res.fail({
  179. status: HttpStatusCode.PAYLOAD_TOO_LARGE_413,
  180. message: 'The user video quota is exceeded with this video.',
  181. type: ServerErrorCode.QUOTA_REACHED
  182. })
  183. return false
  184. }
  185. return true
  186. }
  187. // ---------------------------------------------------------------------------
  188. export {
  189. doesVideoChannelOfAccountExist,
  190. doesVideoExist,
  191. doesVideoFileOfVideoExist,
  192. checkCanAccessVideoStaticFiles,
  193. checkUserCanManageVideo,
  194. checkCanSeeVideo,
  195. checkUserQuota
  196. }