]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame_incremental - server/helpers/core-utils.ts
Add timeout on youtube dl to cleaup files
[github/Chocobozzz/PeerTube.git] / server / helpers / core-utils.ts
... / ...
CommitLineData
1/*
2 Different from 'utils' because we don't not import other PeerTube modules.
3 Useful to avoid circular dependencies.
4*/
5
6import * as bcrypt from 'bcrypt'
7import * as createTorrent from 'create-torrent'
8import { createHash, pseudoRandomBytes } from 'crypto'
9import { isAbsolute, join } from 'path'
10import * as pem from 'pem'
11import * as rimraf from 'rimraf'
12import { URL } from 'url'
13import { truncate } from 'lodash'
14
15const timeTable = {
16 ms: 1,
17 second: 1000,
18 minute: 60000,
19 hour: 3600000,
20 day: 3600000 * 24,
21 week: 3600000 * 24 * 7,
22 month: 3600000 * 24 * 30
23}
24export function parseDuration (duration: number | string): number {
25 if (typeof duration === 'number') return duration
26
27 if (typeof duration === 'string') {
28 const split = duration.match(/^([\d\.,]+)\s?(\w+)$/)
29
30 if (split.length === 3) {
31 const len = parseFloat(split[1])
32 let unit = split[2].replace(/s$/i,'').toLowerCase()
33 if (unit === 'm') {
34 unit = 'ms'
35 }
36
37 return (len || 1) * (timeTable[unit] || 0)
38 }
39 }
40
41 throw new Error('Duration could not be properly parsed')
42}
43
44function sanitizeUrl (url: string) {
45 const urlObject = new URL(url)
46
47 if (urlObject.protocol === 'https:' && urlObject.port === '443') {
48 urlObject.port = ''
49 } else if (urlObject.protocol === 'http:' && urlObject.port === '80') {
50 urlObject.port = ''
51 }
52
53 return urlObject.href.replace(/\/$/, '')
54}
55
56// Don't import remote scheme from constants because we are in core utils
57function sanitizeHost (host: string, remoteScheme: string) {
58 const toRemove = remoteScheme === 'https' ? 443 : 80
59
60 return host.replace(new RegExp(`:${toRemove}$`), '')
61}
62
63function isTestInstance () {
64 return process.env.NODE_ENV === 'test'
65}
66
67function isProdInstance () {
68 return process.env.NODE_ENV === 'production'
69}
70
71function root () {
72 // We are in /helpers/utils.js
73 const paths = [ __dirname, '..', '..' ]
74
75 // We are under /dist directory
76 if (process.mainModule && process.mainModule.filename.endsWith('.ts') === false) {
77 paths.push('..')
78 }
79
80 return join.apply(null, paths)
81}
82
83// Thanks: https://stackoverflow.com/a/12034334
84function escapeHTML (stringParam) {
85 if (!stringParam) return ''
86
87 const entityMap = {
88 '&': '&',
89 '<': '&lt;',
90 '>': '&gt;',
91 '"': '&quot;',
92 '\'': '&#39;',
93 '/': '&#x2F;',
94 '`': '&#x60;',
95 '=': '&#x3D;'
96 }
97
98 return String(stringParam).replace(/[&<>"'`=\/]/g, s => entityMap[s])
99}
100
101function pageToStartAndCount (page: number, itemsPerPage: number) {
102 const start = (page - 1) * itemsPerPage
103
104 return { start, count: itemsPerPage }
105}
106
107function buildPath (path: string) {
108 if (isAbsolute(path)) return path
109
110 return join(root(), path)
111}
112
113// Consistent with .length, lodash truncate function is not
114function peertubeTruncate (str: string, maxLength: number) {
115 const options = {
116 length: maxLength
117 }
118 const truncatedStr = truncate(str, options)
119
120 // The truncated string is okay, we can return it
121 if (truncatedStr.length <= maxLength) return truncatedStr
122
123 // Lodash takes into account all UTF characters, whereas String.prototype.length does not: some characters have a length of 2
124 // We always use the .length so we need to truncate more if needed
125 options.length -= truncatedStr.length - maxLength
126 return truncate(str, options)
127}
128
129function sha256 (str: string) {
130 return createHash('sha256').update(str).digest('hex')
131}
132
133function promisify0<A> (func: (cb: (err: any, result: A) => void) => void): () => Promise<A> {
134 return function promisified (): Promise<A> {
135 return new Promise<A>((resolve: (arg: A) => void, reject: (err: any) => void) => {
136 func.apply(null, [ (err: any, res: A) => err ? reject(err) : resolve(res) ])
137 })
138 }
139}
140
141// Thanks to https://gist.github.com/kumasento/617daa7e46f13ecdd9b2
142function promisify1<T, A> (func: (arg: T, cb: (err: any, result: A) => void) => void): (arg: T) => Promise<A> {
143 return function promisified (arg: T): Promise<A> {
144 return new Promise<A>((resolve: (arg: A) => void, reject: (err: any) => void) => {
145 func.apply(null, [ arg, (err: any, res: A) => err ? reject(err) : resolve(res) ])
146 })
147 }
148}
149
150function promisify1WithVoid<T> (func: (arg: T, cb: (err: any) => void) => void): (arg: T) => Promise<void> {
151 return function promisified (arg: T): Promise<void> {
152 return new Promise<void>((resolve: () => void, reject: (err: any) => void) => {
153 func.apply(null, [ arg, (err: any) => err ? reject(err) : resolve() ])
154 })
155 }
156}
157
158function promisify2<T, U, A> (func: (arg1: T, arg2: U, cb: (err: any, result: A) => void) => void): (arg1: T, arg2: U) => Promise<A> {
159 return function promisified (arg1: T, arg2: U): Promise<A> {
160 return new Promise<A>((resolve: (arg: A) => void, reject: (err: any) => void) => {
161 func.apply(null, [ arg1, arg2, (err: any, res: A) => err ? reject(err) : resolve(res) ])
162 })
163 }
164}
165
166function promisify2WithVoid<T, U> (func: (arg1: T, arg2: U, cb: (err: any) => void) => void): (arg1: T, arg2: U) => Promise<void> {
167 return function promisified (arg1: T, arg2: U): Promise<void> {
168 return new Promise<void>((resolve: () => void, reject: (err: any) => void) => {
169 func.apply(null, [ arg1, arg2, (err: any) => err ? reject(err) : resolve() ])
170 })
171 }
172}
173
174const pseudoRandomBytesPromise = promisify1<number, Buffer>(pseudoRandomBytes)
175const createPrivateKey = promisify1<number, { key: string }>(pem.createPrivateKey)
176const getPublicKey = promisify1<string, { publicKey: string }>(pem.getPublicKey)
177const bcryptComparePromise = promisify2<any, string, boolean>(bcrypt.compare)
178const bcryptGenSaltPromise = promisify1<number, string>(bcrypt.genSalt)
179const bcryptHashPromise = promisify2<any, string | number, string>(bcrypt.hash)
180const createTorrentPromise = promisify2<string, any, any>(createTorrent)
181
182// ---------------------------------------------------------------------------
183
184export {
185 isTestInstance,
186 isProdInstance,
187
188 root,
189 escapeHTML,
190 pageToStartAndCount,
191 sanitizeUrl,
192 sanitizeHost,
193 buildPath,
194 peertubeTruncate,
195 sha256,
196
197 promisify0,
198 promisify1,
199
200 pseudoRandomBytesPromise,
201 createPrivateKey,
202 getPublicKey,
203 bcryptComparePromise,
204 bcryptGenSaltPromise,
205 bcryptHashPromise,
206 createTorrentPromise
207}