aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/helpers
diff options
context:
space:
mode:
Diffstat (limited to 'server/helpers')
-rw-r--r--server/helpers/core-utils.ts29
-rw-r--r--server/helpers/database-utils.ts10
-rw-r--r--server/helpers/express-utils.ts24
-rw-r--r--server/helpers/ffmpeg-utils.ts23
-rw-r--r--server/helpers/signup.ts59
-rw-r--r--server/helpers/utils.ts151
6 files changed, 149 insertions, 147 deletions
diff --git a/server/helpers/core-utils.ts b/server/helpers/core-utils.ts
index 3b38da66c..90d2cd9b3 100644
--- a/server/helpers/core-utils.ts
+++ b/server/helpers/core-utils.ts
@@ -14,6 +14,35 @@ import * as rimraf from 'rimraf'
14import { URL } from 'url' 14import { URL } from 'url'
15import { truncate } from 'lodash' 15import { truncate } from 'lodash'
16 16
17const timeTable = {
18 ms: 1,
19 second: 1000,
20 minute: 60000,
21 hour: 3600000,
22 day: 3600000 * 24,
23 week: 3600000 * 24 * 7,
24 month: 3600000 * 24 * 30
25}
26export function parseDuration (duration: number | string): number {
27 if (typeof duration === 'number') return duration
28
29 if (typeof duration === 'string') {
30 const split = duration.match(/^([\d\.,]+)\s?(\w+)$/)
31
32 if (split.length === 3) {
33 const len = parseFloat(split[1])
34 let unit = split[2].replace(/s$/i,'').toLowerCase()
35 if (unit === 'm') {
36 unit = 'ms'
37 }
38
39 return (len || 1) * (timeTable[unit] || 0)
40 }
41 }
42
43 throw new Error('Duration could not be properly parsed')
44}
45
17function sanitizeUrl (url: string) { 46function sanitizeUrl (url: string) {
18 const urlObject = new URL(url) 47 const urlObject = new URL(url)
19 48
diff --git a/server/helpers/database-utils.ts b/server/helpers/database-utils.ts
index 53f881fb3..1005d2cf1 100644
--- a/server/helpers/database-utils.ts
+++ b/server/helpers/database-utils.ts
@@ -1,6 +1,6 @@
1import * as retry from 'async/retry' 1import * as retry from 'async/retry'
2import * as Bluebird from 'bluebird' 2import * as Bluebird from 'bluebird'
3import { Model, Sequelize } from 'sequelize-typescript' 3import { Model } from 'sequelize-typescript'
4import { logger } from './logger' 4import { logger } from './logger'
5 5
6function retryTransactionWrapper <T, A, B, C> ( 6function retryTransactionWrapper <T, A, B, C> (
@@ -66,9 +66,17 @@ function updateInstanceWithAnother <T extends Model<T>> (instanceToUpdate: Model
66 } 66 }
67} 67}
68 68
69function resetSequelizeInstance (instance: Model<any>, savedFields: object) {
70 Object.keys(savedFields).forEach(key => {
71 const value = savedFields[key]
72 instance.set(key, value)
73 })
74}
75
69// --------------------------------------------------------------------------- 76// ---------------------------------------------------------------------------
70 77
71export { 78export {
79 resetSequelizeInstance,
72 retryTransactionWrapper, 80 retryTransactionWrapper,
73 transactionRetryer, 81 transactionRetryer,
74 updateInstanceWithAnother 82 updateInstanceWithAnother
diff --git a/server/helpers/express-utils.ts b/server/helpers/express-utils.ts
index b3cc40848..1d7bee87e 100644
--- a/server/helpers/express-utils.ts
+++ b/server/helpers/express-utils.ts
@@ -3,8 +3,9 @@ import * as multer from 'multer'
3import { CONFIG, REMOTE_SCHEME } from '../initializers' 3import { CONFIG, REMOTE_SCHEME } from '../initializers'
4import { logger } from './logger' 4import { logger } from './logger'
5import { User } from '../../shared/models/users' 5import { User } from '../../shared/models/users'
6import { generateRandomString } from './utils' 6import { deleteFileAsync, generateRandomString } from './utils'
7import { extname } from 'path' 7import { extname } from 'path'
8import { isArray } from './custom-validators/misc'
8 9
9function buildNSFWFilter (res: express.Response, paramNSFW?: string) { 10function buildNSFWFilter (res: express.Response, paramNSFW?: string) {
10 if (paramNSFW === 'true') return true 11 if (paramNSFW === 'true') return true
@@ -23,6 +24,24 @@ function buildNSFWFilter (res: express.Response, paramNSFW?: string) {
23 return null 24 return null
24} 25}
25 26
27function cleanUpReqFiles (req: { files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[] }) {
28 const files = req.files
29
30 if (!files) return
31
32 if (isArray(files)) {
33 (files as Express.Multer.File[]).forEach(f => deleteFileAsync(f.path))
34 return
35 }
36
37 for (const key of Object.keys(files)) {
38 const file = files[ key ]
39
40 if (isArray(file)) file.forEach(f => deleteFileAsync(f.path))
41 else deleteFileAsync(file.path)
42 }
43}
44
26function getHostWithPort (host: string) { 45function getHostWithPort (host: string) {
27 const splitted = host.split(':') 46 const splitted = host.split(':')
28 47
@@ -82,5 +101,6 @@ export {
82 buildNSFWFilter, 101 buildNSFWFilter,
83 getHostWithPort, 102 getHostWithPort,
84 badRequest, 103 badRequest,
85 createReqFiles 104 createReqFiles,
105 cleanUpReqFiles
86} 106}
diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts
index ced56b82d..f8299c36f 100644
--- a/server/helpers/ffmpeg-utils.ts
+++ b/server/helpers/ffmpeg-utils.ts
@@ -7,6 +7,28 @@ import { processImage } from './image-utils'
7import { logger } from './logger' 7import { logger } from './logger'
8import { checkFFmpegEncoders } from '../initializers/checker' 8import { checkFFmpegEncoders } from '../initializers/checker'
9 9
10function computeResolutionsToTranscode (videoFileHeight: number) {
11 const resolutionsEnabled: number[] = []
12 const configResolutions = CONFIG.TRANSCODING.RESOLUTIONS
13
14 // Put in the order we want to proceed jobs
15 const resolutions = [
16 VideoResolution.H_480P,
17 VideoResolution.H_360P,
18 VideoResolution.H_720P,
19 VideoResolution.H_240P,
20 VideoResolution.H_1080P
21 ]
22
23 for (const resolution of resolutions) {
24 if (configResolutions[ resolution + 'p' ] === true && videoFileHeight > resolution) {
25 resolutionsEnabled.push(resolution)
26 }
27 }
28
29 return resolutionsEnabled
30}
31
10async function getVideoFileResolution (path: string) { 32async function getVideoFileResolution (path: string) {
11 const videoStream = await getVideoFileStream(path) 33 const videoStream = await getVideoFileStream(path)
12 34
@@ -134,6 +156,7 @@ export {
134 generateImageFromVideoFile, 156 generateImageFromVideoFile,
135 transcode, 157 transcode,
136 getVideoFileFPS, 158 getVideoFileFPS,
159 computeResolutionsToTranscode,
137 audio 160 audio
138} 161}
139 162
diff --git a/server/helpers/signup.ts b/server/helpers/signup.ts
new file mode 100644
index 000000000..cdce7989d
--- /dev/null
+++ b/server/helpers/signup.ts
@@ -0,0 +1,59 @@
1import { CONFIG } from '../initializers'
2import { UserModel } from '../models/account/user'
3import * as ipaddr from 'ipaddr.js'
4const isCidr = require('is-cidr')
5
6async function isSignupAllowed () {
7 if (CONFIG.SIGNUP.ENABLED === false) {
8 return false
9 }
10
11 // No limit and signup is enabled
12 if (CONFIG.SIGNUP.LIMIT === -1) {
13 return true
14 }
15
16 const totalUsers = await UserModel.countTotal()
17
18 return totalUsers < CONFIG.SIGNUP.LIMIT
19}
20
21function isSignupAllowedForCurrentIP (ip: string) {
22 const addr = ipaddr.parse(ip)
23 let excludeList = [ 'blacklist' ]
24 let matched = ''
25
26 // if there is a valid, non-empty whitelist, we exclude all unknown adresses too
27 if (CONFIG.SIGNUP.FILTERS.CIDR.WHITELIST.filter(cidr => isCidr(cidr)).length > 0) {
28 excludeList.push('unknown')
29 }
30
31 if (addr.kind() === 'ipv4') {
32 const addrV4 = ipaddr.IPv4.parse(ip)
33 const rangeList = {
34 whitelist: CONFIG.SIGNUP.FILTERS.CIDR.WHITELIST.filter(cidr => isCidr.v4(cidr))
35 .map(cidr => ipaddr.IPv4.parseCIDR(cidr)),
36 blacklist: CONFIG.SIGNUP.FILTERS.CIDR.BLACKLIST.filter(cidr => isCidr.v4(cidr))
37 .map(cidr => ipaddr.IPv4.parseCIDR(cidr))
38 }
39 matched = ipaddr.subnetMatch(addrV4, rangeList, 'unknown')
40 } else if (addr.kind() === 'ipv6') {
41 const addrV6 = ipaddr.IPv6.parse(ip)
42 const rangeList = {
43 whitelist: CONFIG.SIGNUP.FILTERS.CIDR.WHITELIST.filter(cidr => isCidr.v6(cidr))
44 .map(cidr => ipaddr.IPv6.parseCIDR(cidr)),
45 blacklist: CONFIG.SIGNUP.FILTERS.CIDR.BLACKLIST.filter(cidr => isCidr.v6(cidr))
46 .map(cidr => ipaddr.IPv6.parseCIDR(cidr))
47 }
48 matched = ipaddr.subnetMatch(addrV6, rangeList, 'unknown')
49 }
50
51 return !excludeList.includes(matched)
52}
53
54// ---------------------------------------------------------------------------
55
56export {
57 isSignupAllowed,
58 isSignupAllowedForCurrentIP
59}
diff --git a/server/helpers/utils.ts b/server/helpers/utils.ts
index eaad55555..703e57887 100644
--- a/server/helpers/utils.ts
+++ b/server/helpers/utils.ts
@@ -1,37 +1,12 @@
1import { Model } from 'sequelize-typescript'
2import * as ipaddr from 'ipaddr.js'
3import { ResultList } from '../../shared' 1import { ResultList } from '../../shared'
4import { VideoResolution } from '../../shared/models/videos'
5import { CONFIG } from '../initializers' 2import { CONFIG } from '../initializers'
6import { UserModel } from '../models/account/user'
7import { ActorModel } from '../models/activitypub/actor' 3import { ActorModel } from '../models/activitypub/actor'
8import { ApplicationModel } from '../models/application/application' 4import { ApplicationModel } from '../models/application/application'
9import { pseudoRandomBytesPromise, sha256, unlinkPromise } from './core-utils' 5import { pseudoRandomBytesPromise, sha256, unlinkPromise } from './core-utils'
10import { logger } from './logger' 6import { logger } from './logger'
11import { isArray } from './custom-validators/misc'
12import { join } from 'path' 7import { join } from 'path'
13import { Instance as ParseTorrent } from 'parse-torrent' 8import { Instance as ParseTorrent } from 'parse-torrent'
14 9
15const isCidr = require('is-cidr')
16
17function cleanUpReqFiles (req: { files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[] }) {
18 const files = req.files
19
20 if (!files) return
21
22 if (isArray(files)) {
23 (files as Express.Multer.File[]).forEach(f => deleteFileAsync(f.path))
24 return
25 }
26
27 for (const key of Object.keys(files)) {
28 const file = files[key]
29
30 if (isArray(file)) file.forEach(f => deleteFileAsync(f.path))
31 else deleteFileAsync(file.path)
32 }
33}
34
35function deleteFileAsync (path: string) { 10function deleteFileAsync (path: string) {
36 unlinkPromise(path) 11 unlinkPromise(path)
37 .catch(err => logger.error('Cannot delete the file %s asynchronously.', path, { err })) 12 .catch(err => logger.error('Cannot delete the file %s asynchronously.', path, { err }))
@@ -60,127 +35,23 @@ function getFormattedObjects<U, T extends FormattableToJSON> (objects: T[], obje
60 } as ResultList<U> 35 } as ResultList<U>
61} 36}
62 37
63async function isSignupAllowed () {
64 if (CONFIG.SIGNUP.ENABLED === false) {
65 return false
66 }
67
68 // No limit and signup is enabled
69 if (CONFIG.SIGNUP.LIMIT === -1) {
70 return true
71 }
72
73 const totalUsers = await UserModel.countTotal()
74
75 return totalUsers < CONFIG.SIGNUP.LIMIT
76}
77
78function isSignupAllowedForCurrentIP (ip: string) {
79 const addr = ipaddr.parse(ip)
80 let excludeList = [ 'blacklist' ]
81 let matched = ''
82
83 // if there is a valid, non-empty whitelist, we exclude all unknown adresses too
84 if (CONFIG.SIGNUP.FILTERS.CIDR.WHITELIST.filter(cidr => isCidr(cidr)).length > 0) {
85 excludeList.push('unknown')
86 }
87
88 if (addr.kind() === 'ipv4') {
89 const addrV4 = ipaddr.IPv4.parse(ip)
90 const rangeList = {
91 whitelist: CONFIG.SIGNUP.FILTERS.CIDR.WHITELIST.filter(cidr => isCidr.v4(cidr))
92 .map(cidr => ipaddr.IPv4.parseCIDR(cidr)),
93 blacklist: CONFIG.SIGNUP.FILTERS.CIDR.BLACKLIST.filter(cidr => isCidr.v4(cidr))
94 .map(cidr => ipaddr.IPv4.parseCIDR(cidr))
95 }
96 matched = ipaddr.subnetMatch(addrV4, rangeList, 'unknown')
97 } else if (addr.kind() === 'ipv6') {
98 const addrV6 = ipaddr.IPv6.parse(ip)
99 const rangeList = {
100 whitelist: CONFIG.SIGNUP.FILTERS.CIDR.WHITELIST.filter(cidr => isCidr.v6(cidr))
101 .map(cidr => ipaddr.IPv6.parseCIDR(cidr)),
102 blacklist: CONFIG.SIGNUP.FILTERS.CIDR.BLACKLIST.filter(cidr => isCidr.v6(cidr))
103 .map(cidr => ipaddr.IPv6.parseCIDR(cidr))
104 }
105 matched = ipaddr.subnetMatch(addrV6, rangeList, 'unknown')
106 }
107
108 return !excludeList.includes(matched)
109}
110
111function computeResolutionsToTranscode (videoFileHeight: number) {
112 const resolutionsEnabled: number[] = []
113 const configResolutions = CONFIG.TRANSCODING.RESOLUTIONS
114
115 // Put in the order we want to proceed jobs
116 const resolutions = [
117 VideoResolution.H_480P,
118 VideoResolution.H_360P,
119 VideoResolution.H_720P,
120 VideoResolution.H_240P,
121 VideoResolution.H_1080P
122 ]
123
124 for (const resolution of resolutions) {
125 if (configResolutions[ resolution + 'p' ] === true && videoFileHeight > resolution) {
126 resolutionsEnabled.push(resolution)
127 }
128 }
129
130 return resolutionsEnabled
131}
132
133const timeTable = {
134 ms: 1,
135 second: 1000,
136 minute: 60000,
137 hour: 3600000,
138 day: 3600000 * 24,
139 week: 3600000 * 24 * 7,
140 month: 3600000 * 24 * 30
141}
142export function parseDuration (duration: number | string): number {
143 if (typeof duration === 'number') return duration
144
145 if (typeof duration === 'string') {
146 const split = duration.match(/^([\d\.,]+)\s?(\w+)$/)
147
148 if (split.length === 3) {
149 const len = parseFloat(split[1])
150 let unit = split[2].replace(/s$/i,'').toLowerCase()
151 if (unit === 'm') {
152 unit = 'ms'
153 }
154
155 return (len || 1) * (timeTable[unit] || 0)
156 }
157 }
158
159 throw new Error('Duration could not be properly parsed')
160}
161
162function resetSequelizeInstance (instance: Model<any>, savedFields: object) {
163 Object.keys(savedFields).forEach(key => {
164 const value = savedFields[key]
165 instance.set(key, value)
166 })
167}
168
169let serverActor: ActorModel
170async function getServerActor () { 38async function getServerActor () {
171 if (serverActor === undefined) { 39 if (getServerActor.serverActor === undefined) {
172 const application = await ApplicationModel.load() 40 const application = await ApplicationModel.load()
173 if (!application) throw Error('Could not load Application from database.') 41 if (!application) throw Error('Could not load Application from database.')
174 42
175 serverActor = application.Account.Actor 43 getServerActor.serverActor = application.Account.Actor
176 } 44 }
177 45
178 if (!serverActor) { 46 if (!getServerActor.serverActor) {
179 logger.error('Cannot load server actor.') 47 logger.error('Cannot load server actor.')
180 process.exit(0) 48 process.exit(0)
181 } 49 }
182 50
183 return Promise.resolve(serverActor) 51 return Promise.resolve(getServerActor.serverActor)
52}
53namespace getServerActor {
54 export let serverActor: ActorModel
184} 55}
185 56
186function generateVideoTmpPath (target: string | ParseTorrent) { 57function generateVideoTmpPath (target: string | ParseTorrent) {
@@ -194,21 +65,13 @@ function getSecureTorrentName (originalName: string) {
194 return sha256(originalName) + '.torrent' 65 return sha256(originalName) + '.torrent'
195} 66}
196 67
197type SortType = { sortModel: any, sortValue: string }
198
199// --------------------------------------------------------------------------- 68// ---------------------------------------------------------------------------
200 69
201export { 70export {
202 cleanUpReqFiles,
203 deleteFileAsync, 71 deleteFileAsync,
204 generateRandomString, 72 generateRandomString,
205 getFormattedObjects, 73 getFormattedObjects,
206 isSignupAllowed,
207 getSecureTorrentName, 74 getSecureTorrentName,
208 isSignupAllowedForCurrentIP,
209 computeResolutionsToTranscode,
210 resetSequelizeInstance,
211 getServerActor, 75 getServerActor,
212 SortType,
213 generateVideoTmpPath 76 generateVideoTmpPath
214} 77}