aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/middlewares/validators/videos/video-source.ts
blob: bbccb58b08d7e22af1a68b2ca388d8c079534f64 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import express from 'express'
import { body, header } from 'express-validator'
import { getResumableUploadPath } from '@server/helpers/upload'
import { getVideoWithAttributes } from '@server/helpers/video'
import { CONFIG } from '@server/initializers/config'
import { uploadx } from '@server/lib/uploadx'
import { VideoSourceModel } from '@server/models/video/video-source'
import { MVideoFullLight } from '@server/types/models'
import { HttpStatusCode, UserRight } from '@shared/models'
import { Metadata as UploadXMetadata } from '@uploadx/core'
import { logger } from '../../../helpers/logger'
import { areValidationErrors, checkUserCanManageVideo, doesVideoExist, isValidVideoIdParam } from '../shared'
import { addDurationToVideoFileIfNeeded, checkVideoFileCanBeEdited, commonVideoFileChecks, isVideoFileAccepted } from './shared'

export const videoSourceGetLatestValidator = [
  isValidVideoIdParam('id'),

  async (req: express.Request, res: express.Response, next: express.NextFunction) => {
    if (areValidationErrors(req, res)) return
    if (!await doesVideoExist(req.params.id, res, 'all')) return

    const video = getVideoWithAttributes(res) as MVideoFullLight

    const user = res.locals.oauth.token.User
    if (!checkUserCanManageVideo(user, video, UserRight.UPDATE_ANY_VIDEO, res)) return

    res.locals.videoSource = await VideoSourceModel.loadLatest(video.id)

    if (!res.locals.videoSource) {
      return res.fail({
        status: HttpStatusCode.NOT_FOUND_404,
        message: 'Video source not found'
      })
    }

    return next()
  }
]

export const replaceVideoSourceResumableValidator = [
  async (req: express.Request, res: express.Response, next: express.NextFunction) => {
    const body: express.CustomUploadXFile<UploadXMetadata> = req.body
    const file = { ...body, duration: undefined, path: getResumableUploadPath(body.name), filename: body.metadata.filename }
    const cleanup = () => uploadx.storage.delete(file).catch(err => logger.error('Cannot delete the file %s', file.name, { err }))

    if (!await checkCanUpdateVideoFile({ req, res })) {
      return cleanup()
    }

    if (!await addDurationToVideoFileIfNeeded({ videoFile: file, res, middlewareName: 'updateVideoFileResumableValidator' })) {
      return cleanup()
    }

    if (!await isVideoFileAccepted({ req, res, videoFile: file, hook: 'filter:api.video.update-file.accept.result' })) {
      return cleanup()
    }

    res.locals.updateVideoFileResumable = { ...file, originalname: file.filename }

    return next()
  }
]

export const replaceVideoSourceResumableInitValidator = [
  body('filename')
    .exists(),

  header('x-upload-content-length')
    .isNumeric()
    .exists()
    .withMessage('Should specify the file length'),
  header('x-upload-content-type')
    .isString()
    .exists()
    .withMessage('Should specify the file mimetype'),

  async (req: express.Request, res: express.Response, next: express.NextFunction) => {
    const user = res.locals.oauth.token.User

    logger.debug('Checking updateVideoFileResumableInitValidator parameters and headers', {
      parameters: req.body,
      headers: req.headers
    })

    if (areValidationErrors(req, res, { omitLog: true })) return

    if (!await checkCanUpdateVideoFile({ req, res })) return

    const videoFileMetadata = {
      mimetype: req.headers['x-upload-content-type'] as string,
      size: +req.headers['x-upload-content-length'],
      originalname: req.body.filename
    }

    const files = { videofile: [ videoFileMetadata ] }
    if (await commonVideoFileChecks({ res, user, videoFileSize: videoFileMetadata.size, files }) === false) return

    return next()
  }
]

// ---------------------------------------------------------------------------
// Private
// ---------------------------------------------------------------------------

async function checkCanUpdateVideoFile (options: {
  req: express.Request
  res: express.Response
}) {
  const { req, res } = options

  if (!CONFIG.VIDEO_FILE.UPDATE.ENABLED) {
    res.fail({
      status: HttpStatusCode.FORBIDDEN_403,
      message: 'Updating the file of an existing video is not allowed on this instance'
    })
    return false
  }

  if (!await doesVideoExist(req.params.id, res)) return false

  const user = res.locals.oauth.token.User
  const video = res.locals.videoAll

  if (!checkUserCanManageVideo(user, video, UserRight.UPDATE_ANY_VIDEO, res)) return false

  if (!checkVideoFileCanBeEdited(video, res)) return false

  return true
}