]>
Commit | Line | Data |
---|---|---|
3fd3ab2d | 1 | import { Model } from 'sequelize-typescript' |
ff2c1fe8 | 2 | import * as ipaddr from 'ipaddr.js' |
6fcd19ba | 3 | import { ResultList } from '../../shared' |
3fd3ab2d | 4 | import { VideoResolution } from '../../shared/models/videos' |
0626e7af | 5 | import { CONFIG } from '../initializers' |
3fd3ab2d | 6 | import { UserModel } from '../models/account/user' |
50d6de9c C |
7 | import { ActorModel } from '../models/activitypub/actor' |
8 | import { ApplicationModel } from '../models/application/application' | |
990b6a0b | 9 | import { pseudoRandomBytesPromise, sha256, unlinkPromise } from './core-utils' |
efc32059 | 10 | import { logger } from './logger' |
cf7a61b5 | 11 | import { isArray } from './custom-validators/misc' |
3e17515e | 12 | import { join } from 'path' |
990b6a0b | 13 | import { Instance as ParseTorrent } from 'parse-torrent' |
cbe2f7c3 | 14 | |
2186386c C |
15 | const isCidr = require('is-cidr') |
16 | ||
cf7a61b5 C |
17 | function 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 | ||
35 | function deleteFileAsync (path: string) { | |
36 | unlinkPromise(path) | |
37 | .catch(err => logger.error('Cannot delete the file %s asynchronously.', path, { err })) | |
38 | } | |
39 | ||
f5028693 C |
40 | async function generateRandomString (size: number) { |
41 | const raw = await pseudoRandomBytesPromise(size) | |
42 | ||
43 | return raw.toString('hex') | |
e4c87ec2 C |
44 | } |
45 | ||
40298b02 | 46 | interface FormattableToJSON { |
2186386c | 47 | toFormattedJSON (args?: any) |
154898b0 C |
48 | } |
49 | ||
2186386c | 50 | function getFormattedObjects<U, T extends FormattableToJSON> (objects: T[], objectsTotal: number, formattedArg?: any) { |
0aef76c4 | 51 | const formattedObjects: U[] = [] |
55fa55a9 | 52 | |
075f16ca | 53 | objects.forEach(object => { |
2186386c | 54 | formattedObjects.push(object.toFormattedJSON(formattedArg)) |
55fa55a9 C |
55 | }) |
56 | ||
2186386c | 57 | return { |
55fa55a9 | 58 | total: objectsTotal, |
0aef76c4 | 59 | data: formattedObjects |
2186386c | 60 | } as ResultList<U> |
55fa55a9 C |
61 | } |
62 | ||
f5028693 | 63 | async function isSignupAllowed () { |
291e8d3e | 64 | if (CONFIG.SIGNUP.ENABLED === false) { |
f5028693 | 65 | return false |
291e8d3e C |
66 | } |
67 | ||
68 | // No limit and signup is enabled | |
69 | if (CONFIG.SIGNUP.LIMIT === -1) { | |
f5028693 | 70 | return true |
291e8d3e C |
71 | } |
72 | ||
3fd3ab2d | 73 | const totalUsers = await UserModel.countTotal() |
f5028693 C |
74 | |
75 | return totalUsers < CONFIG.SIGNUP.LIMIT | |
291e8d3e C |
76 | } |
77 | ||
ff2c1fe8 RK |
78 | function isSignupAllowedForCurrentIP (ip: string) { |
79 | const addr = ipaddr.parse(ip) | |
80 | let excludeList = [ 'blacklist' ] | |
c1e791ba | 81 | let matched = '' |
ff2c1fe8 RK |
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 | ||
40298b02 C |
111 | function computeResolutionsToTranscode (videoFileHeight: number) { |
112 | const resolutionsEnabled: number[] = [] | |
113 | const configResolutions = CONFIG.TRANSCODING.RESOLUTIONS | |
114 | ||
2186386c | 115 | // Put in the order we want to proceed jobs |
40298b02 | 116 | const resolutions = [ |
40298b02 | 117 | VideoResolution.H_480P, |
2186386c | 118 | VideoResolution.H_360P, |
40298b02 | 119 | VideoResolution.H_720P, |
2186386c | 120 | VideoResolution.H_240P, |
40298b02 C |
121 | VideoResolution.H_1080P |
122 | ] | |
123 | ||
124 | for (const resolution of resolutions) { | |
2186386c | 125 | if (configResolutions[ resolution + 'p' ] === true && videoFileHeight > resolution) { |
40298b02 C |
126 | resolutionsEnabled.push(resolution) |
127 | } | |
128 | } | |
129 | ||
130 | return resolutionsEnabled | |
131 | } | |
132 | ||
3f6d68d9 RK |
133 | const 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 | } | |
98d3324d | 142 | export function parseDuration (duration: number | string): number { |
3f6d68d9 RK |
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 | ||
98d3324d | 159 | throw new Error('Duration could not be properly parsed') |
3f6d68d9 RK |
160 | } |
161 | ||
3fd3ab2d | 162 | function resetSequelizeInstance (instance: Model<any>, savedFields: object) { |
eb080476 C |
163 | Object.keys(savedFields).forEach(key => { |
164 | const value = savedFields[key] | |
165 | instance.set(key, value) | |
166 | }) | |
167 | } | |
168 | ||
50d6de9c C |
169 | let serverActor: ActorModel |
170 | async function getServerActor () { | |
171 | if (serverActor === undefined) { | |
172 | const application = await ApplicationModel.load() | |
2cebd797 C |
173 | if (!application) throw Error('Could not load Application from database.') |
174 | ||
50d6de9c | 175 | serverActor = application.Account.Actor |
7a7724e6 C |
176 | } |
177 | ||
50d6de9c C |
178 | if (!serverActor) { |
179 | logger.error('Cannot load server actor.') | |
efc32059 C |
180 | process.exit(0) |
181 | } | |
182 | ||
50d6de9c | 183 | return Promise.resolve(serverActor) |
7a7724e6 C |
184 | } |
185 | ||
990b6a0b C |
186 | function generateVideoTmpPath (target: string | ParseTorrent) { |
187 | const id = typeof target === 'string' ? target : target.infoHash | |
188 | ||
189 | const hash = sha256(id) | |
ce33919c C |
190 | return join(CONFIG.STORAGE.VIDEOS_DIR, hash + '-import.mp4') |
191 | } | |
192 | ||
990b6a0b C |
193 | function getSecureTorrentName (originalName: string) { |
194 | return sha256(originalName) + '.torrent' | |
195 | } | |
792dbaf0 | 196 | |
990b6a0b | 197 | type SortType = { sortModel: any, sortValue: string } |
ce33919c | 198 | |
9f10b292 | 199 | // --------------------------------------------------------------------------- |
c45f7f84 | 200 | |
65fcc311 | 201 | export { |
cf7a61b5 C |
202 | cleanUpReqFiles, |
203 | deleteFileAsync, | |
65fcc311 | 204 | generateRandomString, |
0aef76c4 | 205 | getFormattedObjects, |
792dbaf0 | 206 | isSignupAllowed, |
990b6a0b | 207 | getSecureTorrentName, |
ff2c1fe8 | 208 | isSignupAllowedForCurrentIP, |
40298b02 | 209 | computeResolutionsToTranscode, |
eb080476 | 210 | resetSequelizeInstance, |
50d6de9c | 211 | getServerActor, |
ce33919c C |
212 | SortType, |
213 | generateVideoTmpPath | |
65fcc311 | 214 | } |