videos.ts 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. import { Response } from 'express'
  2. import 'express-validator'
  3. import { values } from 'lodash'
  4. import 'multer'
  5. import * as validator from 'validator'
  6. import { UserRight, VideoFilter, VideoPrivacy, VideoRateType } from '../../../shared'
  7. import {
  8. CONSTRAINTS_FIELDS,
  9. MIMETYPES,
  10. VIDEO_CATEGORIES,
  11. VIDEO_LICENCES,
  12. VIDEO_PRIVACIES,
  13. VIDEO_RATE_TYPES,
  14. VIDEO_STATES
  15. } from '../../initializers/constants'
  16. import { VideoModel } from '../../models/video/video'
  17. import { exists, isArray, isDateValid, isFileValid } from './misc'
  18. import { VideoChannelModel } from '../../models/video/video-channel'
  19. import { UserModel } from '../../models/account/user'
  20. import * as magnetUtil from 'magnet-uri'
  21. import { fetchVideo, VideoFetchType } from '../video'
  22. const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
  23. function isVideoFilterValid (filter: VideoFilter) {
  24. return filter === 'local' || filter === 'all-local'
  25. }
  26. function isVideoCategoryValid (value: any) {
  27. return value === null || VIDEO_CATEGORIES[ value ] !== undefined
  28. }
  29. function isVideoStateValid (value: any) {
  30. return exists(value) && VIDEO_STATES[ value ] !== undefined
  31. }
  32. function isVideoLicenceValid (value: any) {
  33. return value === null || VIDEO_LICENCES[ value ] !== undefined
  34. }
  35. function isVideoLanguageValid (value: any) {
  36. return value === null ||
  37. (typeof value === 'string' && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.LANGUAGE))
  38. }
  39. function isVideoDurationValid (value: string) {
  40. return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION)
  41. }
  42. function isVideoTruncatedDescriptionValid (value: string) {
  43. return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.TRUNCATED_DESCRIPTION)
  44. }
  45. function isVideoDescriptionValid (value: string) {
  46. return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION))
  47. }
  48. function isVideoSupportValid (value: string) {
  49. return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.SUPPORT))
  50. }
  51. function isVideoNameValid (value: string) {
  52. return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
  53. }
  54. function isVideoTagValid (tag: string) {
  55. return exists(tag) && validator.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG)
  56. }
  57. function isVideoTagsValid (tags: string[]) {
  58. return tags === null || (
  59. isArray(tags) &&
  60. validator.isInt(tags.length.toString(), VIDEOS_CONSTRAINTS_FIELDS.TAGS) &&
  61. tags.every(tag => isVideoTagValid(tag))
  62. )
  63. }
  64. function isVideoViewsValid (value: string) {
  65. return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.VIEWS)
  66. }
  67. function isVideoRatingTypeValid (value: string) {
  68. return value === 'none' || values(VIDEO_RATE_TYPES).indexOf(value as VideoRateType) !== -1
  69. }
  70. function isVideoFileExtnameValid (value: string) {
  71. return exists(value) && MIMETYPES.VIDEO.EXT_MIMETYPE[value] !== undefined
  72. }
  73. function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) {
  74. const videoFileTypesRegex = Object.keys(MIMETYPES.VIDEO.MIMETYPE_EXT)
  75. .map(m => `(${m})`)
  76. .join('|')
  77. return isFileValid(files, videoFileTypesRegex, 'videofile', null)
  78. }
  79. const videoImageTypes = CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME
  80. .map(v => v.replace('.', ''))
  81. .join('|')
  82. const videoImageTypesRegex = `image/(${videoImageTypes})`
  83. function isVideoImage (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[], field: string) {
  84. return isFileValid(files, videoImageTypesRegex, field, CONSTRAINTS_FIELDS.VIDEOS.IMAGE.FILE_SIZE.max, true)
  85. }
  86. function isVideoPrivacyValid (value: number) {
  87. return validator.isInt(value + '') && VIDEO_PRIVACIES[ value ] !== undefined
  88. }
  89. function isScheduleVideoUpdatePrivacyValid (value: number) {
  90. return validator.isInt(value + '') &&
  91. (
  92. value === VideoPrivacy.UNLISTED ||
  93. value === VideoPrivacy.PUBLIC
  94. )
  95. }
  96. function isVideoOriginallyPublishedAtValid (value: string | null) {
  97. return value === null || isDateValid(value)
  98. }
  99. function isVideoFileInfoHashValid (value: string | null | undefined) {
  100. return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH)
  101. }
  102. function isVideoFileResolutionValid (value: string) {
  103. return exists(value) && validator.isInt(value + '')
  104. }
  105. function isVideoFPSResolutionValid (value: string) {
  106. return value === null || validator.isInt(value + '')
  107. }
  108. function isVideoFileSizeValid (value: string) {
  109. return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.FILE_SIZE)
  110. }
  111. function isVideoMagnetUriValid (value: string) {
  112. if (!exists(value)) return false
  113. const parsed = magnetUtil.decode(value)
  114. return parsed && isVideoFileInfoHashValid(parsed.infoHash)
  115. }
  116. function checkUserCanManageVideo (user: UserModel, video: VideoModel, right: UserRight, res: Response) {
  117. // Retrieve the user who did the request
  118. if (video.isOwned() === false) {
  119. res.status(403)
  120. .json({ error: 'Cannot manage a video of another server.' })
  121. .end()
  122. return false
  123. }
  124. // Check if the user can delete the video
  125. // The user can delete it if he has the right
  126. // Or if s/he is the video's account
  127. const account = video.VideoChannel.Account
  128. if (user.hasRight(right) === false && account.userId !== user.id) {
  129. res.status(403)
  130. .json({ error: 'Cannot manage a video of another user.' })
  131. .end()
  132. return false
  133. }
  134. return true
  135. }
  136. async function doesVideoExist (id: number | string, res: Response, fetchType: VideoFetchType = 'all') {
  137. const userId = res.locals.oauth ? res.locals.oauth.token.User.id : undefined
  138. const video = await fetchVideo(id, fetchType, userId)
  139. if (video === null) {
  140. res.status(404)
  141. .json({ error: 'Video not found' })
  142. .end()
  143. return false
  144. }
  145. if (fetchType !== 'none') res.locals.video = video
  146. return true
  147. }
  148. async function doesVideoChannelOfAccountExist (channelId: number, user: UserModel, res: Response) {
  149. if (user.hasRight(UserRight.UPDATE_ANY_VIDEO) === true) {
  150. const videoChannel = await VideoChannelModel.loadAndPopulateAccount(channelId)
  151. if (videoChannel === null) {
  152. res.status(400)
  153. .json({ error: 'Unknown video `video channel` on this instance.' })
  154. .end()
  155. return false
  156. }
  157. res.locals.videoChannel = videoChannel
  158. return true
  159. }
  160. const videoChannel = await VideoChannelModel.loadByIdAndAccount(channelId, user.Account.id)
  161. if (videoChannel === null) {
  162. res.status(400)
  163. .json({ error: 'Unknown video `video channel` for this account.' })
  164. .end()
  165. return false
  166. }
  167. res.locals.videoChannel = videoChannel
  168. return true
  169. }
  170. // ---------------------------------------------------------------------------
  171. export {
  172. isVideoCategoryValid,
  173. checkUserCanManageVideo,
  174. isVideoLicenceValid,
  175. isVideoLanguageValid,
  176. isVideoTruncatedDescriptionValid,
  177. isVideoDescriptionValid,
  178. isVideoFileInfoHashValid,
  179. isVideoNameValid,
  180. isVideoTagsValid,
  181. isVideoFPSResolutionValid,
  182. isScheduleVideoUpdatePrivacyValid,
  183. isVideoOriginallyPublishedAtValid,
  184. isVideoFile,
  185. isVideoMagnetUriValid,
  186. isVideoStateValid,
  187. isVideoViewsValid,
  188. isVideoRatingTypeValid,
  189. isVideoFileExtnameValid,
  190. isVideoDurationValid,
  191. isVideoTagValid,
  192. isVideoPrivacyValid,
  193. isVideoFileResolutionValid,
  194. isVideoFileSizeValid,
  195. doesVideoExist,
  196. isVideoImage,
  197. doesVideoChannelOfAccountExist,
  198. isVideoSupportValid,
  199. isVideoFilterValid
  200. }