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