import { FormValidatorService } from '@app/shared/shared-forms'
import { BytesPipe, Video, VideoCaptionService, VideoEdit, VideoService } from '@app/shared/shared-main'
import { LoadingBarService } from '@ngx-loading-bar/core'
-import { HttpStatusCode, VideoCreateResult, VideoPrivacy } from '@shared/models'
+import { HttpStatusCode, VideoCreateResult } from '@shared/models'
import { UploaderXFormData } from './uploaderx-form-data'
import { VideoSend } from './video-send'
--- /dev/null
+import { lookup } from 'dns'
+import { parse as parseIP } from 'ipaddr.js'
+
+function dnsLookupAll (hostname: string) {
+ return new Promise<string[]>((res, rej) => {
+ lookup(hostname, { family: 0, all: true }, (err, adresses) => {
+ if (err) return rej(err)
+
+ return res(adresses.map(a => a.address))
+ })
+ })
+}
+
+async function isResolvingToUnicastOnly (hostname: string) {
+ const addresses = await dnsLookupAll(hostname)
+
+ for (const address of addresses) {
+ const parsed = parseIP(address)
+
+ if (parsed.range() !== 'unicast') return false
+ }
+
+ return true
+}
+
+export {
+ dnsLookupAll,
+ isResolvingToUnicastOnly
+}
import express from 'express'
import { body, param } from 'express-validator'
-import { isValid as isIPValid, parse as parseIP } from 'ipaddr.js'
+import { isResolvingToUnicastOnly } from '@server/helpers/dns'
import { isPreImportVideoAccepted } from '@server/lib/moderation'
import { Hooks } from '@server/lib/plugins/hooks'
import { MUserAccountId, MVideoImport } from '@server/types/models'
if (req.body.targetUrl) {
const hostname = new URL(req.body.targetUrl).hostname
- if (isIPValid(hostname)) {
- const parsed = parseIP(hostname)
+ if (await isResolvingToUnicastOnly(hostname) !== true) {
+ cleanUpReqFiles(req)
- if (parsed.range() !== 'unicast') {
- cleanUpReqFiles(req)
-
- return res.fail({
- status: HttpStatusCode.FORBIDDEN_403,
- message: 'Cannot use non unicast IP as targetUrl.'
- })
- }
+ return res.fail({
+ status: HttpStatusCode.FORBIDDEN_403,
+ message: 'Cannot use non unicast IP as targetUrl.'
+ })
}
}
'http://127.0.0.1',
'http://127.0.0.1/hello',
'https://192.168.1.42',
- 'http://192.168.1.42'
+ 'http://192.168.1.42',
+ 'http://127.0.0.1.cpy.re'
]
for (const targetUrl of targetUrls) {
--- /dev/null
+/* eslint-disable @typescript-eslint/no-unused-expressions,@typescript-eslint/require-await */
+
+import 'mocha'
+import { expect } from 'chai'
+import { isResolvingToUnicastOnly } from '@server/helpers/dns'
+
+describe('DNS helpers', function () {
+
+ it('Should correctly check unicast IPs', async function () {
+ expect(await isResolvingToUnicastOnly('cpy.re')).to.be.true
+ expect(await isResolvingToUnicastOnly('framasoft.org')).to.be.true
+ expect(await isResolvingToUnicastOnly('8.8.8.8')).to.be.true
+
+ expect(await isResolvingToUnicastOnly('127.0.0.1')).to.be.false
+ expect(await isResolvingToUnicastOnly('127.0.0.1.cpy.re')).to.be.false
+ })
+})
import './image'
import './core-utils'
+import './dns'
import './comment-model'
import './markdown'
import './request'