e3d900a9ea7130e09c8148504cf656115ecd310b
[oweals/peertube.git] / server / middlewares / validators / videos / video-imports.ts
1 import * as express from 'express'
2 import { body } from 'express-validator'
3 import { isPreImportVideoAccepted } from '@server/lib/moderation'
4 import { Hooks } from '@server/lib/plugins/hooks'
5 import { VideoImportCreate } from '@shared/models/videos/import/video-import-create.model'
6 import { isIdValid, toIntOrNull } from '../../../helpers/custom-validators/misc'
7 import { isVideoImportTargetUrlValid, isVideoImportTorrentFile } from '../../../helpers/custom-validators/video-imports'
8 import { isVideoMagnetUriValid, isVideoNameValid } from '../../../helpers/custom-validators/videos'
9 import { cleanUpReqFiles } from '../../../helpers/express-utils'
10 import { logger } from '../../../helpers/logger'
11 import { doesVideoChannelOfAccountExist } from '../../../helpers/middlewares'
12 import { CONFIG } from '../../../initializers/config'
13 import { CONSTRAINTS_FIELDS } from '../../../initializers/constants'
14 import { areValidationErrors } from '../utils'
15 import { getCommonVideoEditAttributes } from './videos'
16
17 const videoImportAddValidator = getCommonVideoEditAttributes().concat([
18   body('channelId')
19     .customSanitizer(toIntOrNull)
20     .custom(isIdValid).withMessage('Should have correct video channel id'),
21   body('targetUrl')
22     .optional()
23     .custom(isVideoImportTargetUrlValid).withMessage('Should have a valid video import target URL'),
24   body('magnetUri')
25     .optional()
26     .custom(isVideoMagnetUriValid).withMessage('Should have a valid video magnet URI'),
27   body('torrentfile')
28     .custom((value, { req }) => isVideoImportTorrentFile(req.files))
29     .withMessage(
30       'This torrent file is not supported or too large. Please, make sure it is of the following type: ' +
31       CONSTRAINTS_FIELDS.VIDEO_IMPORTS.TORRENT_FILE.EXTNAME.join(', ')
32     ),
33   body('name')
34     .optional()
35     .custom(isVideoNameValid).withMessage('Should have a valid name'),
36
37   async (req: express.Request, res: express.Response, next: express.NextFunction) => {
38     logger.debug('Checking videoImportAddValidator parameters', { parameters: req.body })
39
40     const user = res.locals.oauth.token.User
41     const torrentFile = req.files && req.files['torrentfile'] ? req.files['torrentfile'][0] : undefined
42
43     if (areValidationErrors(req, res)) return cleanUpReqFiles(req)
44
45     if (req.body.targetUrl && CONFIG.IMPORT.VIDEOS.HTTP.ENABLED !== true) {
46       cleanUpReqFiles(req)
47       return res.status(409)
48         .json({ error: 'HTTP import is not enabled on this instance.' })
49         .end()
50     }
51
52     if (CONFIG.IMPORT.VIDEOS.TORRENT.ENABLED !== true && (req.body.magnetUri || torrentFile)) {
53       cleanUpReqFiles(req)
54       return res.status(409)
55                 .json({ error: 'Torrent/magnet URI import is not enabled on this instance.' })
56                 .end()
57     }
58
59     if (!await doesVideoChannelOfAccountExist(req.body.channelId, user, res)) return cleanUpReqFiles(req)
60
61     // Check we have at least 1 required param
62     if (!req.body.targetUrl && !req.body.magnetUri && !torrentFile) {
63       cleanUpReqFiles(req)
64
65       return res.status(400)
66         .json({ error: 'Should have a magnetUri or a targetUrl or a torrent file.' })
67         .end()
68     }
69
70     if (!await isImportAccepted(req, res)) return cleanUpReqFiles(req)
71
72     return next()
73   }
74 ])
75
76 // ---------------------------------------------------------------------------
77
78 export {
79   videoImportAddValidator
80 }
81
82 // ---------------------------------------------------------------------------
83
84 async function isImportAccepted (req: express.Request, res: express.Response) {
85   const body: VideoImportCreate = req.body
86   const hookName = body.targetUrl
87     ? 'filter:api.video.pre-import-url.accept.result'
88     : 'filter:api.video.pre-import-torrent.accept.result'
89
90   // Check we accept this video
91   const acceptParameters = {
92     videoImportBody: body,
93     user: res.locals.oauth.token.User
94   }
95   const acceptedResult = await Hooks.wrapFun(
96     isPreImportVideoAccepted,
97     acceptParameters,
98     hookName
99   )
100
101   if (!acceptedResult || acceptedResult.accepted !== true) {
102     logger.info('Refused to import video.', { acceptedResult, acceptParameters })
103     res.status(403)
104        .json({ error: acceptedResult.errorMessage || 'Refused to import video' })
105
106     return false
107   }
108
109   return true
110 }