diff --git a/api/media/formidable.mjs b/api/media/formidable.mjs index cdb01c8..71d7e1e 100644 --- a/api/media/formidable.mjs +++ b/api/media/formidable.mjs @@ -43,6 +43,11 @@ export function uploadFile(ctx, siteName, noprefix = false) { if (err) return rej(err) if (!files || !files.file) return rej(new HttpError(422, 'File in body was missing')) let file = files.file + let filename = file.name.replace(/ /g, '_') + .replace(/&/g, 'and') + .replace(/'/g, '') + .replace(/"/g, '') + .replace(/?/g, '') Object.keys(fields).forEach(function(key) { try { @@ -51,14 +56,14 @@ export function uploadFile(ctx, siteName, noprefix = false) { }) ctx.req.body = fields - if (!noprefix || fs.existsSync(`${config.get('uploadFolder')}/${siteName}/${prefix}${file.name}`)) { + if (!noprefix || fs.existsSync(`${config.get('uploadFolder')}/${siteName}/${prefix}${filename}`)) { prefix = getPrefix() } - fs.rename(files.file.path, `${config.get('uploadFolder')}/${siteName}/${prefix}${file.name}`, function(err) { + fs.rename(files.file.path, `${config.get('uploadFolder')}/${siteName}/${prefix}${filename}`, function(err) { if (err) return rej(err) - file.path = `${config.get('uploadFolder')}/${siteName}/${prefix}${file.name}` - file.filename = `${prefix}${file.name}` + file.path = `${config.get('uploadFolder')}/${siteName}/${prefix}${filename}` + file.filename = `${prefix}${filename}` return res(file) }) diff --git a/api/media/routes.mjs b/api/media/routes.mjs index caa07aa..931f4fb 100644 --- a/api/media/routes.mjs +++ b/api/media/routes.mjs @@ -135,7 +135,7 @@ export default class MediaRoutes { 'extend', ] - await Promise.all(keys.map(key => { + await Promise.all(keys.filter(key => ctx.req.body[key]).map(key => { return Promise.resolve() .then(async () => { let item = ctx.req.body[key] diff --git a/api/media/security.mjs b/api/media/security.mjs index 2185cdb..2ac6859 100644 --- a/api/media/security.mjs +++ b/api/media/security.mjs @@ -52,8 +52,9 @@ export function verifyBody(ctx) { } let item = ctx.req.body[key] + if (item == null) continue + if (typeof(item) !== 'object' - || !item || Array.isArray(item)) { throw new HttpError(422, `Body item ${key} was not valid`) } diff --git a/test/media/A stray'd cat asked to go & inside a shop during heatwave [oBv38cS-MbM].mp4_snapshot_00.00.164.png b/test/media/A stray'd cat asked to go & inside a shop during heatwave [oBv38cS-MbM].mp4_snapshot_00.00.164.png new file mode 100644 index 0000000..3007aa8 Binary files /dev/null and b/test/media/A stray'd cat asked to go & inside a shop during heatwave [oBv38cS-MbM].mp4_snapshot_00.00.164.png differ diff --git a/test/media/api.test.mjs b/test/media/api.test.mjs index 5f8938c..b9a0a61 100644 --- a/test/media/api.test.mjs +++ b/test/media/api.test.mjs @@ -110,6 +110,38 @@ t.describe('Media (API)', () => { assert.strictEqual(img.height, 700) assert.strictEqual(img.format, 'png') }) + + t.test('should properly replace spaces and other stuff', async () => { + let token = encode(null, { iss: 'development' }, secret) + + let data = await assert.isFulfilled( + client.upload( + `/media?token=${token}`, + resolve('A stray\'d cat asked to go & inside a shop during heatwave [oBv38cS-MbM].mp4_snapshot_00.00.164.png') + ) + ) + + testFiles.push(data.path) + + assert.ok(data) + assert.ok(data.filename) + assert.ok(data.filename.startsWith(currYear)) + assert.ok(data.path) + + assert.notOk(data.filename.includes(' ')) + assert.ok(data.filename.includes('A_strayd_cat_asked_to_go_and_inside_a_shop_during_heatwave_[oBv38cS-MbM].mp4_snapshot_00.00.164.png')) + + let stats = await Promise.all([ + fs.stat(resolve('A stray\'d cat asked to go & inside a shop during heatwave [oBv38cS-MbM].mp4_snapshot_00.00.164.png')), + fs.stat(resolve(`../../public/${data.path}`)), + ]) + assert.strictEqual(stats[0].size, stats[1].size) + + let img = await sharp(resolve(`../../public/${data.path}`)).metadata() + assert.strictEqual(img.width, 1280) + assert.strictEqual(img.height, 720) + assert.strictEqual(img.format, 'png') + }) }) t.timeout(10000).describe('POST /media/noprefix', function temp() { @@ -431,6 +463,41 @@ t.describe('Media (API)', () => { assert.strictEqual(img.height, 12) assert.strictEqual(img.format, 'jpeg') }) + + t.test('should upload file and filter out null sizes', async () => { + let token = encode(null, { iss: 'development' }, secret) + + let data = await assert.isFulfilled( + client.upload( + `/media/resize?token=${token}`, + resolve('test.png'), + 'POST', + { + outtest: null, + bla: null, + test: null, + } + ) + ) + + assert.ok(data) + assert.ok(data.filename) + assert.ok(data.path) + + + testFiles.push(data.path) + + let stats = await Promise.all([ + fs.stat(resolve('test.png')), + fs.stat(resolve(`../../public/${data.path}`)), + ]) + assert.strictEqual(stats[0].size, stats[1].size) + + let img = await sharp(resolve(`../../public/${data.path}`)).metadata() + assert.strictEqual(img.width, 600) + assert.strictEqual(img.height, 700) + assert.strictEqual(img.format, 'png') + }) }) t.timeout(10000).describe('POST /media/resize/:filename', function temp() { diff --git a/test/media/security.test.mjs b/test/media/security.test.mjs index 7cb261c..89a97ea 100644 --- a/test/media/security.test.mjs +++ b/test/media/security.test.mjs @@ -160,6 +160,12 @@ t.describe('#verifyBody()', function() { verifyBody(ctx) }) + + t.test('should succeed with null values in body', function() { + let ctx = createContext({ req: { body: { test: null } } }) + + verifyBody(ctx) + }) t.test('should fail with invalid body', function() { let ctx = createContext({ req: { body: { @@ -167,7 +173,7 @@ t.describe('#verifyBody()', function() { } } }) let tests = [ - [null, 'null'], + // [null, 'null'], ['', 'empty string'], ['asdf', 'string'], [0, 'empty number'],