diff options
author | Chocobozzz <me@florianbigard.com> | 2022-01-06 11:16:35 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2022-01-06 11:16:35 +0100 |
commit | 7b54a81cccf6b4c12269e9d6897d608b1a99537a (patch) | |
tree | 9dfb72879f36dcb6b4b3fc5a0b14dc8be09731e1 | |
parent | 37a5d6318b8ce9a3784234751a74b7f15095d5c6 (diff) | |
download | PeerTube-7b54a81cccf6b4c12269e9d6897d608b1a99537a.tar.gz PeerTube-7b54a81cccf6b4c12269e9d6897d608b1a99537a.tar.zst PeerTube-7b54a81cccf6b4c12269e9d6897d608b1a99537a.zip |
Prevent video import on non unicast ips
-rw-r--r-- | server/middlewares/validators/videos/video-imports.ts | 18 | ||||
-rw-r--r-- | server/tests/api/check-params/video-imports.ts | 28 |
2 files changed, 46 insertions, 0 deletions
diff --git a/server/middlewares/validators/videos/video-imports.ts b/server/middlewares/validators/videos/video-imports.ts index 640139c73..e4b54283f 100644 --- a/server/middlewares/validators/videos/video-imports.ts +++ b/server/middlewares/validators/videos/video-imports.ts | |||
@@ -13,6 +13,7 @@ import { CONFIG } from '../../../initializers/config' | |||
13 | import { CONSTRAINTS_FIELDS } from '../../../initializers/constants' | 13 | import { CONSTRAINTS_FIELDS } from '../../../initializers/constants' |
14 | import { areValidationErrors, doesVideoChannelOfAccountExist } from '../shared' | 14 | import { areValidationErrors, doesVideoChannelOfAccountExist } from '../shared' |
15 | import { getCommonVideoEditAttributes } from './videos' | 15 | import { getCommonVideoEditAttributes } from './videos' |
16 | import { isValid as isIPValid, parse as parseIP } from 'ipaddr.js' | ||
16 | 17 | ||
17 | const videoImportAddValidator = getCommonVideoEditAttributes().concat([ | 18 | const videoImportAddValidator = getCommonVideoEditAttributes().concat([ |
18 | body('channelId') | 19 | body('channelId') |
@@ -71,6 +72,23 @@ const videoImportAddValidator = getCommonVideoEditAttributes().concat([ | |||
71 | return res.fail({ message: 'Should have a magnetUri or a targetUrl or a torrent file.' }) | 72 | return res.fail({ message: 'Should have a magnetUri or a targetUrl or a torrent file.' }) |
72 | } | 73 | } |
73 | 74 | ||
75 | if (req.body.targetUrl) { | ||
76 | const hostname = new URL(req.body.targetUrl).hostname | ||
77 | |||
78 | if (isIPValid(hostname)) { | ||
79 | const parsed = parseIP(hostname) | ||
80 | |||
81 | if (parsed.range() !== 'unicast') { | ||
82 | cleanUpReqFiles(req) | ||
83 | |||
84 | return res.fail({ | ||
85 | status: HttpStatusCode.FORBIDDEN_403, | ||
86 | message: 'Cannot use non unicast IP as targetUrl.' | ||
87 | }) | ||
88 | } | ||
89 | } | ||
90 | } | ||
91 | |||
74 | if (!await isImportAccepted(req, res)) return cleanUpReqFiles(req) | 92 | if (!await isImportAccepted(req, res)) return cleanUpReqFiles(req) |
75 | 93 | ||
76 | return next() | 94 | return next() |
diff --git a/server/tests/api/check-params/video-imports.ts b/server/tests/api/check-params/video-imports.ts index d6d745488..6c31daa9b 100644 --- a/server/tests/api/check-params/video-imports.ts +++ b/server/tests/api/check-params/video-imports.ts | |||
@@ -108,6 +108,34 @@ describe('Test video imports API validator', function () { | |||
108 | await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) | 108 | await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) |
109 | }) | 109 | }) |
110 | 110 | ||
111 | it('Should fail with localhost', async function () { | ||
112 | const fields = { ...baseCorrectParams, targetUrl: 'http://localhost:8000' } | ||
113 | |||
114 | await makePostBodyRequest({ url: server.url, path, token: server.accessToken, fields }) | ||
115 | }) | ||
116 | |||
117 | it('Should fail with a private IP target urls', async function () { | ||
118 | const targetUrls = [ | ||
119 | 'http://127.0.0.1:8000', | ||
120 | 'http://127.0.0.1', | ||
121 | 'http://127.0.0.1/hello', | ||
122 | 'https://192.168.1.42', | ||
123 | 'http://192.168.1.42' | ||
124 | ] | ||
125 | |||
126 | for (const targetUrl of targetUrls) { | ||
127 | const fields = { ...baseCorrectParams, targetUrl } | ||
128 | |||
129 | await makePostBodyRequest({ | ||
130 | url: server.url, | ||
131 | path, | ||
132 | token: server.accessToken, | ||
133 | fields, | ||
134 | expectedStatus: HttpStatusCode.FORBIDDEN_403 | ||
135 | }) | ||
136 | } | ||
137 | }) | ||
138 | |||
111 | it('Should fail with a long name', async function () { | 139 | it('Should fail with a long name', async function () { |
112 | const fields = { ...baseCorrectParams, name: 'super'.repeat(65) } | 140 | const fields = { ...baseCorrectParams, name: 'super'.repeat(65) } |
113 | 141 | ||