diff options
author | Chocobozzz <me@florianbigard.com> | 2022-02-07 11:21:25 +0100 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2022-02-07 11:21:25 +0100 |
commit | f33e515991a32885622b217bf2ed1d1b0d9d6832 (patch) | |
tree | 43bf9e63c821f2b363ee60e8b1de07ab7c883580 /server | |
parent | 4afec7357129590b0e0f3558ecb9ac20e0903600 (diff) | |
download | PeerTube-f33e515991a32885622b217bf2ed1d1b0d9d6832.tar.gz PeerTube-f33e515991a32885622b217bf2ed1d1b0d9d6832.tar.zst PeerTube-f33e515991a32885622b217bf2ed1d1b0d9d6832.zip |
Correctly check import target URL IP
Diffstat (limited to 'server')
-rw-r--r-- | server/helpers/dns.ts | 29 | ||||
-rw-r--r-- | server/middlewares/validators/videos/video-imports.ts | 18 | ||||
-rw-r--r-- | server/tests/api/check-params/video-imports.ts | 3 | ||||
-rw-r--r-- | server/tests/helpers/dns.ts | 17 | ||||
-rw-r--r-- | server/tests/helpers/index.ts | 1 |
5 files changed, 56 insertions, 12 deletions
diff --git a/server/helpers/dns.ts b/server/helpers/dns.ts new file mode 100644 index 000000000..da8b666c2 --- /dev/null +++ b/server/helpers/dns.ts | |||
@@ -0,0 +1,29 @@ | |||
1 | import { lookup } from 'dns' | ||
2 | import { parse as parseIP } from 'ipaddr.js' | ||
3 | |||
4 | function dnsLookupAll (hostname: string) { | ||
5 | return new Promise<string[]>((res, rej) => { | ||
6 | lookup(hostname, { family: 0, all: true }, (err, adresses) => { | ||
7 | if (err) return rej(err) | ||
8 | |||
9 | return res(adresses.map(a => a.address)) | ||
10 | }) | ||
11 | }) | ||
12 | } | ||
13 | |||
14 | async function isResolvingToUnicastOnly (hostname: string) { | ||
15 | const addresses = await dnsLookupAll(hostname) | ||
16 | |||
17 | for (const address of addresses) { | ||
18 | const parsed = parseIP(address) | ||
19 | |||
20 | if (parsed.range() !== 'unicast') return false | ||
21 | } | ||
22 | |||
23 | return true | ||
24 | } | ||
25 | |||
26 | export { | ||
27 | dnsLookupAll, | ||
28 | isResolvingToUnicastOnly | ||
29 | } | ||
diff --git a/server/middlewares/validators/videos/video-imports.ts b/server/middlewares/validators/videos/video-imports.ts index a3a5cc531..9c6d213c4 100644 --- a/server/middlewares/validators/videos/video-imports.ts +++ b/server/middlewares/validators/videos/video-imports.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import express from 'express' | 1 | import express from 'express' |
2 | import { body, param } from 'express-validator' | 2 | import { body, param } from 'express-validator' |
3 | import { isValid as isIPValid, parse as parseIP } from 'ipaddr.js' | 3 | import { isResolvingToUnicastOnly } from '@server/helpers/dns' |
4 | import { isPreImportVideoAccepted } from '@server/lib/moderation' | 4 | import { isPreImportVideoAccepted } from '@server/lib/moderation' |
5 | import { Hooks } from '@server/lib/plugins/hooks' | 5 | import { Hooks } from '@server/lib/plugins/hooks' |
6 | import { MUserAccountId, MVideoImport } from '@server/types/models' | 6 | import { MUserAccountId, MVideoImport } from '@server/types/models' |
@@ -76,17 +76,13 @@ const videoImportAddValidator = getCommonVideoEditAttributes().concat([ | |||
76 | if (req.body.targetUrl) { | 76 | if (req.body.targetUrl) { |
77 | const hostname = new URL(req.body.targetUrl).hostname | 77 | const hostname = new URL(req.body.targetUrl).hostname |
78 | 78 | ||
79 | if (isIPValid(hostname)) { | 79 | if (await isResolvingToUnicastOnly(hostname) !== true) { |
80 | const parsed = parseIP(hostname) | 80 | cleanUpReqFiles(req) |
81 | 81 | ||
82 | if (parsed.range() !== 'unicast') { | 82 | return res.fail({ |
83 | cleanUpReqFiles(req) | 83 | status: HttpStatusCode.FORBIDDEN_403, |
84 | 84 | message: 'Cannot use non unicast IP as targetUrl.' | |
85 | return res.fail({ | 85 | }) |
86 | status: HttpStatusCode.FORBIDDEN_403, | ||
87 | message: 'Cannot use non unicast IP as targetUrl.' | ||
88 | }) | ||
89 | } | ||
90 | } | 86 | } |
91 | } | 87 | } |
92 | 88 | ||
diff --git a/server/tests/api/check-params/video-imports.ts b/server/tests/api/check-params/video-imports.ts index 156a612ee..7893f5cc5 100644 --- a/server/tests/api/check-params/video-imports.ts +++ b/server/tests/api/check-params/video-imports.ts | |||
@@ -120,7 +120,8 @@ describe('Test video imports API validator', function () { | |||
120 | 'http://127.0.0.1', | 120 | 'http://127.0.0.1', |
121 | 'http://127.0.0.1/hello', | 121 | 'http://127.0.0.1/hello', |
122 | 'https://192.168.1.42', | 122 | 'https://192.168.1.42', |
123 | 'http://192.168.1.42' | 123 | 'http://192.168.1.42', |
124 | 'http://127.0.0.1.cpy.re' | ||
124 | ] | 125 | ] |
125 | 126 | ||
126 | for (const targetUrl of targetUrls) { | 127 | for (const targetUrl of targetUrls) { |
diff --git a/server/tests/helpers/dns.ts b/server/tests/helpers/dns.ts new file mode 100644 index 000000000..309de5426 --- /dev/null +++ b/server/tests/helpers/dns.ts | |||
@@ -0,0 +1,17 @@ | |||
1 | /* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */ | ||
2 | |||
3 | import 'mocha' | ||
4 | import { expect } from 'chai' | ||
5 | import { isResolvingToUnicastOnly } from '@server/helpers/dns' | ||
6 | |||
7 | describe('DNS helpers', function () { | ||
8 | |||
9 | it('Should correctly check unicast IPs', async function () { | ||
10 | expect(await isResolvingToUnicastOnly('cpy.re')).to.be.true | ||
11 | expect(await isResolvingToUnicastOnly('framasoft.org')).to.be.true | ||
12 | expect(await isResolvingToUnicastOnly('8.8.8.8')).to.be.true | ||
13 | |||
14 | expect(await isResolvingToUnicastOnly('127.0.0.1')).to.be.false | ||
15 | expect(await isResolvingToUnicastOnly('127.0.0.1.cpy.re')).to.be.false | ||
16 | }) | ||
17 | }) | ||
diff --git a/server/tests/helpers/index.ts b/server/tests/helpers/index.ts index 91d11e25d..951208842 100644 --- a/server/tests/helpers/index.ts +++ b/server/tests/helpers/index.ts | |||
@@ -1,5 +1,6 @@ | |||
1 | import './image' | 1 | import './image' |
2 | import './core-utils' | 2 | import './core-utils' |
3 | import './dns' | ||
3 | import './comment-model' | 4 | import './comment-model' |
4 | import './markdown' | 5 | import './markdown' |
5 | import './request' | 6 | import './request' |