diff options
author | Chocobozzz <me@florianbigard.com> | 2018-08-07 09:54:36 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2018-08-08 09:30:31 +0200 |
commit | 990b6a0b0c4fbebc165e5cf7cec8fbc1cbaa6c66 (patch) | |
tree | 8aaa0638798bfa14813f4d6ed5247242313b9ce6 /server/helpers | |
parent | ce33919c24e7402d92d81f3cd8e545df52d98240 (diff) | |
download | PeerTube-990b6a0b0c4fbebc165e5cf7cec8fbc1cbaa6c66.tar.gz PeerTube-990b6a0b0c4fbebc165e5cf7cec8fbc1cbaa6c66.tar.zst PeerTube-990b6a0b0c4fbebc165e5cf7cec8fbc1cbaa6c66.zip |
Import torrents with webtorrent
Diffstat (limited to 'server/helpers')
-rw-r--r-- | server/helpers/core-utils.ts | 6 | ||||
-rw-r--r-- | server/helpers/custom-validators/video-imports.ts | 14 | ||||
-rw-r--r-- | server/helpers/utils.ts | 15 | ||||
-rw-r--r-- | server/helpers/webtorrent.ts | 15 |
4 files changed, 37 insertions, 13 deletions
diff --git a/server/helpers/core-utils.ts b/server/helpers/core-utils.ts index 884206aad..25eb6454a 100644 --- a/server/helpers/core-utils.ts +++ b/server/helpers/core-utils.ts | |||
@@ -13,6 +13,7 @@ import * as pem from 'pem' | |||
13 | import * as rimraf from 'rimraf' | 13 | import * as rimraf from 'rimraf' |
14 | import { URL } from 'url' | 14 | import { URL } from 'url' |
15 | import { truncate } from 'lodash' | 15 | import { truncate } from 'lodash' |
16 | import * as crypto from 'crypto' | ||
16 | 17 | ||
17 | function sanitizeUrl (url: string) { | 18 | function sanitizeUrl (url: string) { |
18 | const urlObject = new URL(url) | 19 | const urlObject = new URL(url) |
@@ -95,6 +96,10 @@ function peertubeTruncate (str: string, maxLength: number) { | |||
95 | return truncate(str, options) | 96 | return truncate(str, options) |
96 | } | 97 | } |
97 | 98 | ||
99 | function sha256 (str: string) { | ||
100 | return crypto.createHash('sha256').update(str).digest('hex') | ||
101 | } | ||
102 | |||
98 | function promisify0<A> (func: (cb: (err: any, result: A) => void) => void): () => Promise<A> { | 103 | function promisify0<A> (func: (cb: (err: any, result: A) => void) => void): () => Promise<A> { |
99 | return function promisified (): Promise<A> { | 104 | return function promisified (): Promise<A> { |
100 | return new Promise<A>((resolve: (arg: A) => void, reject: (err: any) => void) => { | 105 | return new Promise<A>((resolve: (arg: A) => void, reject: (err: any) => void) => { |
@@ -165,6 +170,7 @@ export { | |||
165 | sanitizeHost, | 170 | sanitizeHost, |
166 | buildPath, | 171 | buildPath, |
167 | peertubeTruncate, | 172 | peertubeTruncate, |
173 | sha256, | ||
168 | 174 | ||
169 | promisify0, | 175 | promisify0, |
170 | promisify1, | 176 | promisify1, |
diff --git a/server/helpers/custom-validators/video-imports.ts b/server/helpers/custom-validators/video-imports.ts index d8b9bfaff..4d6ab1fa4 100644 --- a/server/helpers/custom-validators/video-imports.ts +++ b/server/helpers/custom-validators/video-imports.ts | |||
@@ -1,10 +1,9 @@ | |||
1 | import 'express-validator' | 1 | import 'express-validator' |
2 | import 'multer' | 2 | import 'multer' |
3 | import * as validator from 'validator' | 3 | import * as validator from 'validator' |
4 | import { CONSTRAINTS_FIELDS, VIDEO_IMPORT_STATES } from '../../initializers' | 4 | import { CONSTRAINTS_FIELDS, TORRENT_MIMETYPE_EXT, VIDEO_IMPORT_STATES } from '../../initializers' |
5 | import { exists } from './misc' | 5 | import { exists, isFileValid } from './misc' |
6 | import * as express from 'express' | 6 | import * as express from 'express' |
7 | import { VideoChannelModel } from '../../models/video/video-channel' | ||
8 | import { VideoImportModel } from '../../models/video/video-import' | 7 | import { VideoImportModel } from '../../models/video/video-import' |
9 | 8 | ||
10 | function isVideoImportTargetUrlValid (url: string) { | 9 | function isVideoImportTargetUrlValid (url: string) { |
@@ -25,6 +24,12 @@ function isVideoImportStateValid (value: any) { | |||
25 | return exists(value) && VIDEO_IMPORT_STATES[ value ] !== undefined | 24 | return exists(value) && VIDEO_IMPORT_STATES[ value ] !== undefined |
26 | } | 25 | } |
27 | 26 | ||
27 | const videoTorrentImportTypes = Object.keys(TORRENT_MIMETYPE_EXT).map(m => `(${m})`) | ||
28 | const videoTorrentImportRegex = videoTorrentImportTypes.join('|') | ||
29 | function isVideoImportTorrentFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) { | ||
30 | return isFileValid(files, videoTorrentImportRegex, 'torrentfile', CONSTRAINTS_FIELDS.VIDEO_IMPORTS.TORRENT_FILE.FILE_SIZE.max, true) | ||
31 | } | ||
32 | |||
28 | async function isVideoImportExist (id: number, res: express.Response) { | 33 | async function isVideoImportExist (id: number, res: express.Response) { |
29 | const videoImport = await VideoImportModel.loadAndPopulateVideo(id) | 34 | const videoImport = await VideoImportModel.loadAndPopulateVideo(id) |
30 | 35 | ||
@@ -45,5 +50,6 @@ async function isVideoImportExist (id: number, res: express.Response) { | |||
45 | export { | 50 | export { |
46 | isVideoImportStateValid, | 51 | isVideoImportStateValid, |
47 | isVideoImportTargetUrlValid, | 52 | isVideoImportTargetUrlValid, |
48 | isVideoImportExist | 53 | isVideoImportExist, |
54 | isVideoImportTorrentFile | ||
49 | } | 55 | } |
diff --git a/server/helpers/utils.ts b/server/helpers/utils.ts index f4cc5547d..2ad87951e 100644 --- a/server/helpers/utils.ts +++ b/server/helpers/utils.ts | |||
@@ -6,11 +6,12 @@ import { CONFIG } from '../initializers' | |||
6 | import { UserModel } from '../models/account/user' | 6 | import { UserModel } from '../models/account/user' |
7 | import { ActorModel } from '../models/activitypub/actor' | 7 | import { ActorModel } from '../models/activitypub/actor' |
8 | import { ApplicationModel } from '../models/application/application' | 8 | import { ApplicationModel } from '../models/application/application' |
9 | import { pseudoRandomBytesPromise, unlinkPromise } from './core-utils' | 9 | import { pseudoRandomBytesPromise, sha256, unlinkPromise } from './core-utils' |
10 | import { logger } from './logger' | 10 | import { logger } from './logger' |
11 | import { isArray } from './custom-validators/misc' | 11 | import { isArray } from './custom-validators/misc' |
12 | import * as crypto from "crypto" | 12 | import * as crypto from "crypto" |
13 | import { join } from "path" | 13 | import { join } from "path" |
14 | import { Instance as ParseTorrent } from 'parse-torrent' | ||
14 | 15 | ||
15 | const isCidr = require('is-cidr') | 16 | const isCidr = require('is-cidr') |
16 | 17 | ||
@@ -183,13 +184,18 @@ async function getServerActor () { | |||
183 | return Promise.resolve(serverActor) | 184 | return Promise.resolve(serverActor) |
184 | } | 185 | } |
185 | 186 | ||
186 | function generateVideoTmpPath (id: string) { | 187 | function generateVideoTmpPath (target: string | ParseTorrent) { |
187 | const hash = crypto.createHash('sha256').update(id).digest('hex') | 188 | const id = typeof target === 'string' ? target : target.infoHash |
189 | |||
190 | const hash = sha256(id) | ||
188 | return join(CONFIG.STORAGE.VIDEOS_DIR, hash + '-import.mp4') | 191 | return join(CONFIG.STORAGE.VIDEOS_DIR, hash + '-import.mp4') |
189 | } | 192 | } |
190 | 193 | ||
191 | type SortType = { sortModel: any, sortValue: string } | 194 | function getSecureTorrentName (originalName: string) { |
195 | return sha256(originalName) + '.torrent' | ||
196 | } | ||
192 | 197 | ||
198 | type SortType = { sortModel: any, sortValue: string } | ||
193 | 199 | ||
194 | // --------------------------------------------------------------------------- | 200 | // --------------------------------------------------------------------------- |
195 | 201 | ||
@@ -199,6 +205,7 @@ export { | |||
199 | generateRandomString, | 205 | generateRandomString, |
200 | getFormattedObjects, | 206 | getFormattedObjects, |
201 | isSignupAllowed, | 207 | isSignupAllowed, |
208 | getSecureTorrentName, | ||
202 | isSignupAllowedForCurrentIP, | 209 | isSignupAllowedForCurrentIP, |
203 | computeResolutionsToTranscode, | 210 | computeResolutionsToTranscode, |
204 | resetSequelizeInstance, | 211 | resetSequelizeInstance, |
diff --git a/server/helpers/webtorrent.ts b/server/helpers/webtorrent.ts index fce88a1f6..04b3ac71b 100644 --- a/server/helpers/webtorrent.ts +++ b/server/helpers/webtorrent.ts | |||
@@ -2,17 +2,22 @@ import { logger } from './logger' | |||
2 | import { generateVideoTmpPath } from './utils' | 2 | import { generateVideoTmpPath } from './utils' |
3 | import * as WebTorrent from 'webtorrent' | 3 | import * as WebTorrent from 'webtorrent' |
4 | import { createWriteStream } from 'fs' | 4 | import { createWriteStream } from 'fs' |
5 | import { Instance as ParseTorrent } from 'parse-torrent' | ||
6 | import { CONFIG } from '../initializers' | ||
7 | import { join } from 'path' | ||
5 | 8 | ||
6 | function downloadWebTorrentVideo (target: string) { | 9 | function downloadWebTorrentVideo (target: { magnetUri: string, torrentName: string }) { |
7 | const path = generateVideoTmpPath(target) | 10 | const id = target.magnetUri || target.torrentName |
8 | 11 | ||
9 | logger.info('Importing torrent video %s', target) | 12 | const path = generateVideoTmpPath(id) |
13 | logger.info('Importing torrent video %s', id) | ||
10 | 14 | ||
11 | return new Promise<string>((res, rej) => { | 15 | return new Promise<string>((res, rej) => { |
12 | const webtorrent = new WebTorrent() | 16 | const webtorrent = new WebTorrent() |
13 | 17 | ||
14 | const torrent = webtorrent.add(target, torrent => { | 18 | const torrentId = target.magnetUri || join(CONFIG.STORAGE.TORRENTS_DIR, target.torrentName) |
15 | if (torrent.files.length !== 1) throw new Error('The number of files is not equal to 1 for ' + target) | 19 | const torrent = webtorrent.add(torrentId, torrent => { |
20 | if (torrent.files.length !== 1) return rej(new Error('The number of files is not equal to 1 for ' + torrentId)) | ||
16 | 21 | ||
17 | const file = torrent.files[ 0 ] | 22 | const file = torrent.files[ 0 ] |
18 | file.createReadStream().pipe(createWriteStream(path)) | 23 | file.createReadStream().pipe(createWriteStream(path)) |