aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/helpers
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2021-06-08 09:33:03 +0200
committerChocobozzz <me@florianbigard.com>2021-06-08 10:01:50 +0200
commitea54cd04c1ff0e55651cd5fb1a83672acde68604 (patch)
tree4e10fea658e72a9f79375d0e9b23d08915d3d0b2 /server/helpers
parent295106516277581ba4967199fa5580264a90ae2c (diff)
downloadPeerTube-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.ts88
-rw-r--r--server/helpers/express-utils.ts4
-rw-r--r--server/helpers/image-utils.ts7
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 @@
8import { exec, ExecOptions } from 'child_process' 8import { exec, ExecOptions } from 'child_process'
9import { BinaryToTextEncoding, createHash, randomBytes } from 'crypto' 9import { BinaryToTextEncoding, createHash, randomBytes } from 'crypto'
10import { truncate } from 'lodash' 10import { truncate } from 'lodash'
11import { basename, isAbsolute, join, resolve } from 'path' 11import { basename, extname, isAbsolute, join, resolve } from 'path'
12import * as pem from 'pem' 12import * as pem from 'pem'
13import { pipeline } from 'stream' 13import { pipeline } from 'stream'
14import { URL } from 'url' 14import { 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
35function 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
35const timeTable = { 47const 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
113function sanitizeUrl (url: string) { 127function 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
132function isTestInstance () { 148function 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
144let rootPath: string 162let rootPath: string
145 163
146function root () { 164function root () {
@@ -154,27 +172,19 @@ function root () {
154 return rootPath 172 return rootPath
155} 173}
156 174
157function pageToStartAndCount (page: number, itemsPerPage: number) { 175function 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
163function mapToJSON (map: Map<any, any>) { 181function 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
173function 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
180function peertubeTruncate (str: string, options: { length: number, separator?: RegExp, omission?: string }) { 190function 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
202function pageToStartAndCount (page: number, itemsPerPage: number) {
203 const start = (page - 1) * itemsPerPage
204
205 return { start, count: itemsPerPage }
206}
207
208// ---------------------------------------------------------------------------
209
210type SemVersion = { major: number, minor: number, patch: number }
211function 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
192function sha256 (str: string | Buffer, encoding: BinaryToTextEncoding = 'hex') { 223function 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
200function execShell (command: string, options?: ExecOptions) { 233function 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
211function promisify0<A> (func: (cb: (err: any, result: A) => void) => void): () => Promise<A> { 246function 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
236type SemVersion = { major: number, minor: number, patch: number }
237function 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
247const randomBytesPromise = promisify1<number, Buffer>(randomBytes) 271const randomBytesPromise = promisify1<number, Buffer>(randomBytes)
248const createPrivateKey = promisify1<number, { key: string }>(pem.createPrivateKey) 272const createPrivateKey = promisify1<number, { key: string }>(pem.createPrivateKey)
249const getPublicKey = promisify1<string, { publicKey: string }>(pem.getPublicKey) 273const 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 @@
1import * as express from 'express' 1import * as express from 'express'
2import * as multer from 'multer' 2import * as multer from 'multer'
3import { extname } from 'path'
4import { HttpStatusCode } from '../../shared/core-utils/miscs/http-error-codes' 3import { HttpStatusCode } from '../../shared/core-utils/miscs/http-error-codes'
5import { CONFIG } from '../initializers/config' 4import { CONFIG } from '../initializers/config'
6import { REMOTE_SCHEME } from '../initializers/constants' 5import { REMOTE_SCHEME } from '../initializers/constants'
6import { getLowercaseExtension } from './core-utils'
7import { isArray } from './custom-validators/misc' 7import { isArray } from './custom-validators/misc'
8import { logger } from './logger' 8import { logger } from './logger'
9import { deleteFileAndCatch, generateRandomString } from './utils' 9import { 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 @@
1import { copy, readFile, remove, rename } from 'fs-extra' 1import { copy, readFile, remove, rename } from 'fs-extra'
2import * as Jimp from 'jimp' 2import * as Jimp from 'jimp'
3import { extname } from 'path'
4import { v4 as uuidv4 } from 'uuid' 3import { v4 as uuidv4 } from 'uuid'
4import { getLowercaseExtension } from './core-utils'
5import { convertWebPToJPG, processGIF } from './ffmpeg-utils' 5import { convertWebPToJPG, processGIF } from './ffmpeg-utils'
6import { logger } from './logger' 6import { 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