]>
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' |
ce33919c C |
12 | import * as crypto from "crypto" |
13 | import { join } from "path" | |
990b6a0b | 14 | import { Instance as ParseTorrent } from 'parse-torrent' |
cbe2f7c3 | 15 | |
2186386c C |
16 | const isCidr = require('is-cidr') |
17 | ||
cf7a61b5 C |
18 | function cleanUpReqFiles (req: { files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[] }) { |
19 | const files = req.files | |
20 | ||
21 | if (!files) return | |
22 | ||
23 | if (isArray(files)) { | |
24 | (files as Express.Multer.File[]).forEach(f => deleteFileAsync(f.path)) | |
25 | return | |
26 | } | |
27 | ||
28 | for (const key of Object.keys(files)) { | |
29 | const file = files[key] | |
30 | ||
31 | if (isArray(file)) file.forEach(f => deleteFileAsync(f.path)) | |
32 | else deleteFileAsync(file.path) | |
33 | } | |
34 | } | |
35 | ||
36 | function deleteFileAsync (path: string) { | |
37 | unlinkPromise(path) | |
38 | .catch(err => logger.error('Cannot delete the file %s asynchronously.', path, { err })) | |
39 | } | |
40 | ||
f5028693 C |
41 | async function generateRandomString (size: number) { |
42 | const raw = await pseudoRandomBytesPromise(size) | |
43 | ||
44 | return raw.toString('hex') | |
e4c87ec2 C |
45 | } |
46 | ||
40298b02 | 47 | interface FormattableToJSON { |
2186386c | 48 | toFormattedJSON (args?: any) |
154898b0 C |
49 | } |
50 | ||
2186386c | 51 | function getFormattedObjects<U, T extends FormattableToJSON> (objects: T[], objectsTotal: number, formattedArg?: any) { |
0aef76c4 | 52 | const formattedObjects: U[] = [] |
55fa55a9 | 53 | |
075f16ca | 54 | objects.forEach(object => { |
2186386c | 55 | formattedObjects.push(object.toFormattedJSON(formattedArg)) |
55fa55a9 C |
56 | }) |
57 | ||
2186386c | 58 | return { |
55fa55a9 | 59 | total: objectsTotal, |
0aef76c4 | 60 | data: formattedObjects |
2186386c | 61 | } as ResultList<U> |
55fa55a9 C |
62 | } |
63 | ||
f5028693 | 64 | async function isSignupAllowed () { |
291e8d3e | 65 | if (CONFIG.SIGNUP.ENABLED === false) { |
f5028693 | 66 | return false |
291e8d3e C |
67 | } |
68 | ||
69 | // No limit and signup is enabled | |
70 | if (CONFIG.SIGNUP.LIMIT === -1) { | |
f5028693 | 71 | return true |
291e8d3e C |
72 | } |
73 | ||
3fd3ab2d | 74 | const totalUsers = await UserModel.countTotal() |
f5028693 C |
75 | |
76 | return totalUsers < CONFIG.SIGNUP.LIMIT | |
291e8d3e C |
77 | } |
78 | ||
ff2c1fe8 RK |
79 | function isSignupAllowedForCurrentIP (ip: string) { |
80 | const addr = ipaddr.parse(ip) | |
81 | let excludeList = [ 'blacklist' ] | |
c1e791ba | 82 | let matched = '' |
ff2c1fe8 RK |
83 | |
84 | // if there is a valid, non-empty whitelist, we exclude all unknown adresses too | |
85 | if (CONFIG.SIGNUP.FILTERS.CIDR.WHITELIST.filter(cidr => isCidr(cidr)).length > 0) { | |
86 | excludeList.push('unknown') | |
87 | } | |
88 | ||
89 | if (addr.kind() === 'ipv4') { | |
90 | const addrV4 = ipaddr.IPv4.parse(ip) | |
91 | const rangeList = { | |
92 | whitelist: CONFIG.SIGNUP.FILTERS.CIDR.WHITELIST.filter(cidr => isCidr.v4(cidr)) | |
93 | .map(cidr => ipaddr.IPv4.parseCIDR(cidr)), | |
94 | blacklist: CONFIG.SIGNUP.FILTERS.CIDR.BLACKLIST.filter(cidr => isCidr.v4(cidr)) | |
95 | .map(cidr => ipaddr.IPv4.parseCIDR(cidr)) | |
96 | } | |
97 | matched = ipaddr.subnetMatch(addrV4, rangeList, 'unknown') | |
98 | } else if (addr.kind() === 'ipv6') { | |
99 | const addrV6 = ipaddr.IPv6.parse(ip) | |
100 | const rangeList = { | |
101 | whitelist: CONFIG.SIGNUP.FILTERS.CIDR.WHITELIST.filter(cidr => isCidr.v6(cidr)) | |
102 | .map(cidr => ipaddr.IPv6.parseCIDR(cidr)), | |
103 | blacklist: CONFIG.SIGNUP.FILTERS.CIDR.BLACKLIST.filter(cidr => isCidr.v6(cidr)) | |
104 | .map(cidr => ipaddr.IPv6.parseCIDR(cidr)) | |
105 | } | |
106 | matched = ipaddr.subnetMatch(addrV6, rangeList, 'unknown') | |
107 | } | |
108 | ||
109 | return !excludeList.includes(matched) | |
110 | } | |
111 | ||
40298b02 C |
112 | function computeResolutionsToTranscode (videoFileHeight: number) { |
113 | const resolutionsEnabled: number[] = [] | |
114 | const configResolutions = CONFIG.TRANSCODING.RESOLUTIONS | |
115 | ||
2186386c | 116 | // Put in the order we want to proceed jobs |
40298b02 | 117 | const resolutions = [ |
40298b02 | 118 | VideoResolution.H_480P, |
2186386c | 119 | VideoResolution.H_360P, |
40298b02 | 120 | VideoResolution.H_720P, |
2186386c | 121 | VideoResolution.H_240P, |
40298b02 C |
122 | VideoResolution.H_1080P |
123 | ] | |
124 | ||
125 | for (const resolution of resolutions) { | |
2186386c | 126 | if (configResolutions[ resolution + 'p' ] === true && videoFileHeight > resolution) { |
40298b02 C |
127 | resolutionsEnabled.push(resolution) |
128 | } | |
129 | } | |
130 | ||
131 | return resolutionsEnabled | |
132 | } | |
133 | ||
3f6d68d9 RK |
134 | const timeTable = { |
135 | ms: 1, | |
136 | second: 1000, | |
137 | minute: 60000, | |
138 | hour: 3600000, | |
139 | day: 3600000 * 24, | |
140 | week: 3600000 * 24 * 7, | |
141 | month: 3600000 * 24 * 30 | |
142 | } | |
98d3324d | 143 | export function parseDuration (duration: number | string): number { |
3f6d68d9 RK |
144 | if (typeof duration === 'number') return duration |
145 | ||
146 | if (typeof duration === 'string') { | |
147 | const split = duration.match(/^([\d\.,]+)\s?(\w+)$/) | |
148 | ||
149 | if (split.length === 3) { | |
150 | const len = parseFloat(split[1]) | |
151 | let unit = split[2].replace(/s$/i,'').toLowerCase() | |
152 | if (unit === 'm') { | |
153 | unit = 'ms' | |
154 | } | |
155 | ||
156 | return (len || 1) * (timeTable[unit] || 0) | |
157 | } | |
158 | } | |
159 | ||
98d3324d | 160 | throw new Error('Duration could not be properly parsed') |
3f6d68d9 RK |
161 | } |
162 | ||
3fd3ab2d | 163 | function resetSequelizeInstance (instance: Model<any>, savedFields: object) { |
eb080476 C |
164 | Object.keys(savedFields).forEach(key => { |
165 | const value = savedFields[key] | |
166 | instance.set(key, value) | |
167 | }) | |
168 | } | |
169 | ||
50d6de9c C |
170 | let serverActor: ActorModel |
171 | async function getServerActor () { | |
172 | if (serverActor === undefined) { | |
173 | const application = await ApplicationModel.load() | |
2cebd797 C |
174 | if (!application) throw Error('Could not load Application from database.') |
175 | ||
50d6de9c | 176 | serverActor = application.Account.Actor |
7a7724e6 C |
177 | } |
178 | ||
50d6de9c C |
179 | if (!serverActor) { |
180 | logger.error('Cannot load server actor.') | |
efc32059 C |
181 | process.exit(0) |
182 | } | |
183 | ||
50d6de9c | 184 | return Promise.resolve(serverActor) |
7a7724e6 C |
185 | } |
186 | ||
990b6a0b C |
187 | function generateVideoTmpPath (target: string | ParseTorrent) { |
188 | const id = typeof target === 'string' ? target : target.infoHash | |
189 | ||
190 | const hash = sha256(id) | |
ce33919c C |
191 | return join(CONFIG.STORAGE.VIDEOS_DIR, hash + '-import.mp4') |
192 | } | |
193 | ||
990b6a0b C |
194 | function getSecureTorrentName (originalName: string) { |
195 | return sha256(originalName) + '.torrent' | |
196 | } | |
792dbaf0 | 197 | |
990b6a0b | 198 | type SortType = { sortModel: any, sortValue: string } |
ce33919c | 199 | |
9f10b292 | 200 | // --------------------------------------------------------------------------- |
c45f7f84 | 201 | |
65fcc311 | 202 | export { |
cf7a61b5 C |
203 | cleanUpReqFiles, |
204 | deleteFileAsync, | |
65fcc311 | 205 | generateRandomString, |
0aef76c4 | 206 | getFormattedObjects, |
792dbaf0 | 207 | isSignupAllowed, |
990b6a0b | 208 | getSecureTorrentName, |
ff2c1fe8 | 209 | isSignupAllowedForCurrentIP, |
40298b02 | 210 | computeResolutionsToTranscode, |
eb080476 | 211 | resetSequelizeInstance, |
50d6de9c | 212 | getServerActor, |
ce33919c C |
213 | SortType, |
214 | generateVideoTmpPath | |
65fcc311 | 215 | } |