diff options
author | Chocobozzz <me@florianbigard.com> | 2021-06-08 09:33:03 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2021-06-08 10:01:50 +0200 |
commit | ea54cd04c1ff0e55651cd5fb1a83672acde68604 (patch) | |
tree | 4e10fea658e72a9f79375d0e9b23d08915d3d0b2 /server/helpers | |
parent | 295106516277581ba4967199fa5580264a90ae2c (diff) | |
download | PeerTube-ea54cd04c1ff0e55651cd5fb1a83672acde68604.tar.gz PeerTube-ea54cd04c1ff0e55651cd5fb1a83672acde68604.tar.zst PeerTube-ea54cd04c1ff0e55651cd5fb1a83672acde68604.zip |
Fix video upload with a capitalized ext
Diffstat (limited to 'server/helpers')
-rw-r--r-- | server/helpers/core-utils.ts | 88 | ||||
-rw-r--r-- | server/helpers/express-utils.ts | 4 | ||||
-rw-r--r-- | server/helpers/image-utils.ts | 7 |
3 files changed, 64 insertions, 35 deletions
diff --git a/server/helpers/core-utils.ts b/server/helpers/core-utils.ts index b93868c12..b5bf2c92c 100644 --- a/server/helpers/core-utils.ts +++ b/server/helpers/core-utils.ts | |||
@@ -8,7 +8,7 @@ | |||
8 | import { exec, ExecOptions } from 'child_process' | 8 | import { exec, ExecOptions } from 'child_process' |
9 | import { BinaryToTextEncoding, createHash, randomBytes } from 'crypto' | 9 | import { BinaryToTextEncoding, createHash, randomBytes } from 'crypto' |
10 | import { truncate } from 'lodash' | 10 | import { truncate } from 'lodash' |
11 | import { basename, isAbsolute, join, resolve } from 'path' | 11 | import { basename, extname, isAbsolute, join, resolve } from 'path' |
12 | import * as pem from 'pem' | 12 | import * as pem from 'pem' |
13 | import { pipeline } from 'stream' | 13 | import { pipeline } from 'stream' |
14 | import { URL } from 'url' | 14 | import { URL } from 'url' |
@@ -32,6 +32,18 @@ const objectConverter = (oldObject: any, keyConverter: (e: string) => string, va | |||
32 | return newObject | 32 | return newObject |
33 | } | 33 | } |
34 | 34 | ||
35 | function mapToJSON (map: Map<any, any>) { | ||
36 | const obj: any = {} | ||
37 | |||
38 | for (const [ k, v ] of map) { | ||
39 | obj[k] = v | ||
40 | } | ||
41 | |||
42 | return obj | ||
43 | } | ||
44 | |||
45 | // --------------------------------------------------------------------------- | ||
46 | |||
35 | const timeTable = { | 47 | const timeTable = { |
36 | ms: 1, | 48 | ms: 1, |
37 | second: 1000, | 49 | second: 1000, |
@@ -110,6 +122,8 @@ export function parseBytes (value: string | number): number { | |||
110 | } | 122 | } |
111 | } | 123 | } |
112 | 124 | ||
125 | // --------------------------------------------------------------------------- | ||
126 | |||
113 | function sanitizeUrl (url: string) { | 127 | function sanitizeUrl (url: string) { |
114 | const urlObject = new URL(url) | 128 | const urlObject = new URL(url) |
115 | 129 | ||
@@ -129,6 +143,8 @@ function sanitizeHost (host: string, remoteScheme: string) { | |||
129 | return host.replace(new RegExp(`:${toRemove}$`), '') | 143 | return host.replace(new RegExp(`:${toRemove}$`), '') |
130 | } | 144 | } |
131 | 145 | ||
146 | // --------------------------------------------------------------------------- | ||
147 | |||
132 | function isTestInstance () { | 148 | function isTestInstance () { |
133 | return process.env.NODE_ENV === 'test' | 149 | return process.env.NODE_ENV === 'test' |
134 | } | 150 | } |
@@ -141,6 +157,8 @@ function getAppNumber () { | |||
141 | return process.env.NODE_APP_INSTANCE | 157 | return process.env.NODE_APP_INSTANCE |
142 | } | 158 | } |
143 | 159 | ||
160 | // --------------------------------------------------------------------------- | ||
161 | |||
144 | let rootPath: string | 162 | let rootPath: string |
145 | 163 | ||
146 | function root () { | 164 | function root () { |
@@ -154,27 +172,19 @@ function root () { | |||
154 | return rootPath | 172 | return rootPath |
155 | } | 173 | } |
156 | 174 | ||
157 | function pageToStartAndCount (page: number, itemsPerPage: number) { | 175 | function buildPath (path: string) { |
158 | const start = (page - 1) * itemsPerPage | 176 | if (isAbsolute(path)) return path |
159 | 177 | ||
160 | return { start, count: itemsPerPage } | 178 | return join(root(), path) |
161 | } | 179 | } |
162 | 180 | ||
163 | function mapToJSON (map: Map<any, any>) { | 181 | function getLowercaseExtension (filename: string) { |
164 | const obj: any = {} | 182 | const ext = extname(filename) || '' |
165 | |||
166 | for (const [ k, v ] of map) { | ||
167 | obj[k] = v | ||
168 | } | ||
169 | 183 | ||
170 | return obj | 184 | return ext.toLowerCase() |
171 | } | 185 | } |
172 | 186 | ||
173 | function buildPath (path: string) { | 187 | // --------------------------------------------------------------------------- |
174 | if (isAbsolute(path)) return path | ||
175 | |||
176 | return join(root(), path) | ||
177 | } | ||
178 | 188 | ||
179 | // Consistent with .length, lodash truncate function is not | 189 | // Consistent with .length, lodash truncate function is not |
180 | function peertubeTruncate (str: string, options: { length: number, separator?: RegExp, omission?: string }) { | 190 | function peertubeTruncate (str: string, options: { length: number, separator?: RegExp, omission?: string }) { |
@@ -189,6 +199,27 @@ function peertubeTruncate (str: string, options: { length: number, separator?: R | |||
189 | return truncate(str, options) | 199 | return truncate(str, options) |
190 | } | 200 | } |
191 | 201 | ||
202 | function pageToStartAndCount (page: number, itemsPerPage: number) { | ||
203 | const start = (page - 1) * itemsPerPage | ||
204 | |||
205 | return { start, count: itemsPerPage } | ||
206 | } | ||
207 | |||
208 | // --------------------------------------------------------------------------- | ||
209 | |||
210 | type SemVersion = { major: number, minor: number, patch: number } | ||
211 | function parseSemVersion (s: string) { | ||
212 | const parsed = s.match(/^v?(\d+)\.(\d+)\.(\d+)$/i) | ||
213 | |||
214 | return { | ||
215 | major: parseInt(parsed[1]), | ||
216 | minor: parseInt(parsed[2]), | ||
217 | patch: parseInt(parsed[3]) | ||
218 | } as SemVersion | ||
219 | } | ||
220 | |||
221 | // --------------------------------------------------------------------------- | ||
222 | |||
192 | function sha256 (str: string | Buffer, encoding: BinaryToTextEncoding = 'hex') { | 223 | function sha256 (str: string | Buffer, encoding: BinaryToTextEncoding = 'hex') { |
193 | return createHash('sha256').update(str).digest(encoding) | 224 | return createHash('sha256').update(str).digest(encoding) |
194 | } | 225 | } |
@@ -197,6 +228,8 @@ function sha1 (str: string | Buffer, encoding: BinaryToTextEncoding = 'hex') { | |||
197 | return createHash('sha1').update(str).digest(encoding) | 228 | return createHash('sha1').update(str).digest(encoding) |
198 | } | 229 | } |
199 | 230 | ||
231 | // --------------------------------------------------------------------------- | ||
232 | |||
200 | function execShell (command: string, options?: ExecOptions) { | 233 | function execShell (command: string, options?: ExecOptions) { |
201 | return new Promise<{ err?: Error, stdout: string, stderr: string }>((res, rej) => { | 234 | return new Promise<{ err?: Error, stdout: string, stderr: string }>((res, rej) => { |
202 | exec(command, options, (err, stdout, stderr) => { | 235 | exec(command, options, (err, stdout, stderr) => { |
@@ -208,6 +241,8 @@ function execShell (command: string, options?: ExecOptions) { | |||
208 | }) | 241 | }) |
209 | } | 242 | } |
210 | 243 | ||
244 | // --------------------------------------------------------------------------- | ||
245 | |||
211 | function promisify0<A> (func: (cb: (err: any, result: A) => void) => void): () => Promise<A> { | 246 | function promisify0<A> (func: (cb: (err: any, result: A) => void) => void): () => Promise<A> { |
212 | return function promisified (): Promise<A> { | 247 | return function promisified (): Promise<A> { |
213 | return new Promise<A>((resolve: (arg: A) => void, reject: (err: any) => void) => { | 248 | return new Promise<A>((resolve: (arg: A) => void, reject: (err: any) => void) => { |
@@ -233,17 +268,6 @@ function promisify2<T, U, A> (func: (arg1: T, arg2: U, cb: (err: any, result: A) | |||
233 | } | 268 | } |
234 | } | 269 | } |
235 | 270 | ||
236 | type SemVersion = { major: number, minor: number, patch: number } | ||
237 | function parseSemVersion (s: string) { | ||
238 | const parsed = s.match(/^v?(\d+)\.(\d+)\.(\d+)$/i) | ||
239 | |||
240 | return { | ||
241 | major: parseInt(parsed[1]), | ||
242 | minor: parseInt(parsed[2]), | ||
243 | patch: parseInt(parsed[3]) | ||
244 | } as SemVersion | ||
245 | } | ||
246 | |||
247 | const randomBytesPromise = promisify1<number, Buffer>(randomBytes) | 271 | const randomBytesPromise = promisify1<number, Buffer>(randomBytes) |
248 | const createPrivateKey = promisify1<number, { key: string }>(pem.createPrivateKey) | 272 | const createPrivateKey = promisify1<number, { key: string }>(pem.createPrivateKey) |
249 | const getPublicKey = promisify1<string, { publicKey: string }>(pem.getPublicKey) | 273 | const getPublicKey = promisify1<string, { publicKey: string }>(pem.getPublicKey) |
@@ -259,17 +283,21 @@ export { | |||
259 | getAppNumber, | 283 | getAppNumber, |
260 | 284 | ||
261 | objectConverter, | 285 | objectConverter, |
286 | mapToJSON, | ||
287 | |||
262 | root, | 288 | root, |
263 | pageToStartAndCount, | 289 | buildPath, |
290 | getLowercaseExtension, | ||
264 | sanitizeUrl, | 291 | sanitizeUrl, |
265 | sanitizeHost, | 292 | sanitizeHost, |
266 | buildPath, | 293 | |
267 | execShell, | 294 | execShell, |
295 | |||
296 | pageToStartAndCount, | ||
268 | peertubeTruncate, | 297 | peertubeTruncate, |
269 | 298 | ||
270 | sha256, | 299 | sha256, |
271 | sha1, | 300 | sha1, |
272 | mapToJSON, | ||
273 | 301 | ||
274 | promisify0, | 302 | promisify0, |
275 | promisify1, | 303 | promisify1, |
diff --git a/server/helpers/express-utils.ts b/server/helpers/express-utils.ts index 010c6961a..003e02818 100644 --- a/server/helpers/express-utils.ts +++ b/server/helpers/express-utils.ts | |||
@@ -1,9 +1,9 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import * as multer from 'multer' | 2 | import * as multer from 'multer' |
3 | import { extname } from 'path' | ||
4 | import { HttpStatusCode } from '../../shared/core-utils/miscs/http-error-codes' | 3 | import { HttpStatusCode } from '../../shared/core-utils/miscs/http-error-codes' |
5 | import { CONFIG } from '../initializers/config' | 4 | import { CONFIG } from '../initializers/config' |
6 | import { REMOTE_SCHEME } from '../initializers/constants' | 5 | import { REMOTE_SCHEME } from '../initializers/constants' |
6 | import { getLowercaseExtension } from './core-utils' | ||
7 | import { isArray } from './custom-validators/misc' | 7 | import { isArray } from './custom-validators/misc' |
8 | import { logger } from './logger' | 8 | import { logger } from './logger' |
9 | import { deleteFileAndCatch, generateRandomString } from './utils' | 9 | import { deleteFileAndCatch, generateRandomString } from './utils' |
@@ -79,7 +79,7 @@ function createReqFiles ( | |||
79 | 79 | ||
80 | filename: async (req, file, cb) => { | 80 | filename: async (req, file, cb) => { |
81 | let extension: string | 81 | let extension: string |
82 | const fileExtension = extname(file.originalname) | 82 | const fileExtension = getLowercaseExtension(file.originalname) |
83 | const extensionFromMimetype = getExtFromMimetype(mimeTypes, file.mimetype) | 83 | const extensionFromMimetype = getExtFromMimetype(mimeTypes, file.mimetype) |
84 | 84 | ||
85 | // Take the file extension if we don't understand the mime type | 85 | // Take the file extension if we don't understand the mime type |
diff --git a/server/helpers/image-utils.ts b/server/helpers/image-utils.ts index 6f6f8d4da..122fb009d 100644 --- a/server/helpers/image-utils.ts +++ b/server/helpers/image-utils.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import { copy, readFile, remove, rename } from 'fs-extra' | 1 | import { copy, readFile, remove, rename } from 'fs-extra' |
2 | import * as Jimp from 'jimp' | 2 | import * as Jimp from 'jimp' |
3 | import { extname } from 'path' | ||
4 | import { v4 as uuidv4 } from 'uuid' | 3 | import { v4 as uuidv4 } from 'uuid' |
4 | import { getLowercaseExtension } from './core-utils' | ||
5 | import { convertWebPToJPG, processGIF } from './ffmpeg-utils' | 5 | import { convertWebPToJPG, processGIF } from './ffmpeg-utils' |
6 | import { logger } from './logger' | 6 | import { logger } from './logger' |
7 | 7 | ||
@@ -15,7 +15,7 @@ async function processImage ( | |||
15 | newSize: { width: number, height: number }, | 15 | newSize: { width: number, height: number }, |
16 | keepOriginal = false | 16 | keepOriginal = false |
17 | ) { | 17 | ) { |
18 | const extension = extname(path) | 18 | const extension = getLowercaseExtension(path) |
19 | 19 | ||
20 | if (path === destination) { | 20 | if (path === destination) { |
21 | throw new Error('Jimp/FFmpeg needs an input path different that the output path.') | 21 | throw new Error('Jimp/FFmpeg needs an input path different that the output path.') |
@@ -61,7 +61,8 @@ async function jimpProcessor (path: string, destination: string, newSize: { widt | |||
61 | await remove(destination) | 61 | await remove(destination) |
62 | 62 | ||
63 | // Optimization if the source file has the appropriate size | 63 | // Optimization if the source file has the appropriate size |
64 | if (await skipProcessing({ jimpInstance, newSize, imageBytes: inputBuffer.byteLength, inputExt, outputExt: extname(destination) })) { | 64 | const outputExt = getLowercaseExtension(destination) |
65 | if (skipProcessing({ jimpInstance, newSize, imageBytes: inputBuffer.byteLength, inputExt, outputExt })) { | ||
65 | return copy(path, destination) | 66 | return copy(path, destination) |
66 | } | 67 | } |
67 | 68 | ||