import sharp from 'sharp-lite' import { Eltro as t, assert} from 'eltro' import fs from 'fs/promises' import { fileURLToPath } from 'url' import path from 'path' import { server, resetLog } from '../helper.server.mjs' import Client from '../helper.client.mjs' import encode from '../../api/jwt/encode.mjs' let __dirname = path.dirname(fileURLToPath(import.meta.url)) function resolve(file) { return path.resolve(path.join(__dirname, file)) } t.describe('Media (API)', () => { const client = new Client() const secret = 'asdf1234' let testFiles = [] t.after(function() { return Promise.all(testFiles.map(function(file) { return fs.unlink(resolve(`../../public/${file}`)).catch(function() {}) })) }) t.timeout(10000).describe('POST /media', function temp() { t.test('should require authentication', async () => { resetLog() assert.strictEqual(server.log.error.callCount, 0) assert.strictEqual(server.log.warn.callCount, 0) let err = await assert.isRejected( client.upload('/media', resolve('test.png') ) ) assert.strictEqual(err.status, 422) assert.match(err.message, /[Tt]oken/) assert.match(err.message, /[Mm]issing/) assert.strictEqual(server.log.error.callCount, 0) assert.strictEqual(server.log.warn.callCount, 2) assert.strictEqual(typeof(server.log.warn.firstCall[0]), 'string') assert.match(server.log.warn.firstCall[0], /[Tt]oken/) assert.match(server.log.warn.firstCall[0], /[Mm]issing/) }) t.test('should verify token correctly', async () => { const assertToken = 'asdf.asdf.asdf' resetLog() assert.strictEqual(server.log.error.callCount, 0) assert.strictEqual(server.log.warn.callCount, 0) assert.strictEqual(server.log.info.callCount, 0) let err = await assert.isRejected( client.upload('/media?token=' + assertToken, resolve('test.png') ) ) assert.strictEqual(err.status, 422) assert.match(err.message, /[Tt]oken/) assert.match(err.message, /[Ii]nvalid/) assert.strictEqual(server.log.error.callCount, 1) assert.strictEqual(server.log.warn.callCount, 2) assert.strictEqual(typeof(server.log.warn.firstCall[0]), 'string') assert.match(server.log.warn.firstCall[0], /[Tt]oken/) assert.match(server.log.warn.firstCall[0], /[Ii]nvalid/) assert.ok(server.log.error.lastCall[0] instanceof Error) assert.match(server.log.error.lastCall[1], new RegExp(assertToken)) }) t.test('should upload file and create file', async () => { let token = encode(null, { iss: 'development' }, secret) let data = await assert.isFulfilled( client.upload( `/media?token=${token}`, resolve('test.png') ) ) 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', function temp() { t.test('should require authentication', async () => { resetLog() assert.strictEqual(server.log.error.callCount, 0) assert.strictEqual(server.log.warn.callCount, 0) let err = await assert.isRejected( client.upload('/media/resize', resolve('test.png') ) ) assert.strictEqual(err.status, 422) assert.match(err.message, /[Tt]oken/) assert.match(err.message, /[Mm]issing/) assert.strictEqual(server.log.error.callCount, 0) assert.strictEqual(server.log.warn.callCount, 2) assert.strictEqual(typeof(server.log.warn.firstCall[0]), 'string') assert.match(server.log.warn.firstCall[0], /[Tt]oken/) assert.match(server.log.warn.firstCall[0], /[Mm]issing/) }) t.test('should verify token correctly', async () => { const assertToken = 'asdf.asdf.asdf' resetLog() assert.strictEqual(server.log.error.callCount, 0) assert.strictEqual(server.log.warn.callCount, 0) assert.strictEqual(server.log.info.callCount, 0) let err = await assert.isRejected( client.upload('/media/resize?token=' + assertToken, resolve('test.png') ) ) assert.strictEqual(err.status, 422) assert.match(err.message, /[Tt]oken/) assert.match(err.message, /[Ii]nvalid/) assert.strictEqual(server.log.error.callCount, 1) assert.strictEqual(server.log.warn.callCount, 2) assert.strictEqual(typeof(server.log.warn.firstCall[0]), 'string') assert.match(server.log.warn.firstCall[0], /[Tt]oken/) assert.match(server.log.warn.firstCall[0], /[Ii]nvalid/) assert.ok(server.log.error.lastCall[0] instanceof Error) assert.match(server.log.error.lastCall[1], new RegExp(assertToken)) }) t.test('should upload file and create file', async () => { let token = encode(null, { iss: 'development' }, secret) let data = await assert.isFulfilled( client.upload( `/media/resize?token=${token}`, resolve('test.png'), 'POST', { } ) ) assert.ok(data) assert.ok(data.original) assert.ok(data.original.filename) assert.ok(data.original.path) testFiles.push(data.original.path) let stats = await Promise.all([ fs.stat(resolve('test.png')), fs.stat(resolve(`../../public/${data.original.path}`)), ]) assert.strictEqual(stats[0].size, stats[1].size) let img = await sharp(resolve(`../../public/${data.original.path}`)).metadata() assert.strictEqual(img.width, 600) assert.strictEqual(img.height, 700) assert.strictEqual(img.format, 'png') }) t.test('should upload file and create multiple sizes for file', async () => { let token = encode(null, { iss: 'development' }, secret) let data = await assert.isFulfilled( client.upload( `/media/resize?token=${token}`, resolve('test.png'), 'POST', { test1: { format: 'jpeg', resize: { width: 300, }, jpeg: { quality: 80, mozjpeg: true, } }, test2: { format: 'png', resize: { width: 150, }, png: { compressionLevel: 9, } }, } ) ) assert.ok(data) assert.ok(data.original) assert.ok(data.original.filename) assert.ok(data.original.path) assert.ok(data.test1.filename) assert.ok(data.test1.path) assert.ok(data.test2.filename) assert.ok(data.test2.path) testFiles.push(data.original.path) testFiles.push(data.test1.path) testFiles.push(data.test2.path) let stats = await Promise.all([ fs.stat(resolve('test.png')), fs.stat(resolve(`../../public/${data.original.path}`)), ]) assert.strictEqual(stats[0].size, stats[1].size) let img = await sharp(resolve(`../../public/${data.original.path}`)).metadata() assert.strictEqual(img.width, 600) assert.strictEqual(img.height, 700) assert.strictEqual(img.format, 'png') img = await sharp(resolve(`../../public/${data.test1.path}`)).metadata() assert.strictEqual(img.width, 300) assert.strictEqual(img.height, 350) assert.strictEqual(img.format, 'jpeg') img = await sharp(resolve(`../../public/${data.test2.path}`)).metadata() assert.strictEqual(img.width, 150) assert.strictEqual(img.height, 175) assert.strictEqual(img.format, 'png') }) t.test('should upload file and support base64 output', async () => { let token = encode(null, { iss: 'development' }, secret) let data = await assert.isFulfilled( client.upload( `/media/resize?token=${token}`, resolve('test.png'), 'POST', { outtest: { out: 'base64', format: 'jpeg', resize: { width: 10, }, jpeg: { quality: 80, mozjpeg: true, } }, } ) ) assert.ok(data) assert.ok(data.original) assert.ok(data.original.filename) assert.ok(data.original.path) assert.ok(data.outtest.base64) testFiles.push(data.original.path) let stats = await Promise.all([ fs.stat(resolve('test.png')), fs.stat(resolve(`../../public/${data.original.path}`)), ]) assert.strictEqual(stats[0].size, stats[1].size) let img = await sharp(resolve(`../../public/${data.original.path}`)).metadata() assert.strictEqual(img.width, 600) assert.strictEqual(img.height, 700) assert.strictEqual(img.format, 'png') let bufferBase64 = Buffer.from(data.outtest.base64.slice(data.outtest.base64.indexOf(',')), 'base64') img = await sharp(bufferBase64).metadata() assert.strictEqual(img.width, 10) assert.strictEqual(img.height, 12) assert.strictEqual(img.format, 'jpeg') }) }) t.describe('GET /media', function() { t.test('should require authentication', async () => { resetLog() assert.strictEqual(server.log.error.callCount, 0) assert.strictEqual(server.log.warn.callCount, 0) let err = await assert.isRejected(client.get('/media')) assert.strictEqual(err.status, 422) assert.match(err.message, /[Tt]oken/) assert.match(err.message, /[Mm]issing/) assert.strictEqual(server.log.error.callCount, 0) assert.strictEqual(server.log.warn.callCount, 2) assert.strictEqual(typeof(server.log.warn.firstCall[0]), 'string') assert.match(server.log.warn.firstCall[0], /[Tt]oken/) assert.match(server.log.warn.firstCall[0], /[Mm]issing/) }) t.test('should verify token correctly', async () => { const assertToken = 'asdf.asdf.asdf' resetLog() assert.strictEqual(server.log.error.callCount, 0) assert.strictEqual(server.log.warn.callCount, 0) assert.strictEqual(server.log.info.callCount, 0) let err = await assert.isRejected(client.get('/media?token=' + assertToken)) assert.strictEqual(err.status, 422) assert.match(err.message, /[Tt]oken/) assert.match(err.message, /[Ii]nvalid/) assert.strictEqual(server.log.error.callCount, 1) assert.strictEqual(server.log.warn.callCount, 2) assert.strictEqual(typeof(server.log.warn.firstCall[0]), 'string') assert.match(server.log.warn.firstCall[0], /[Tt]oken/) assert.match(server.log.warn.firstCall[0], /[Ii]nvalid/) assert.ok(server.log.error.lastCall[0] instanceof Error) assert.match(server.log.error.lastCall[1], new RegExp(assertToken)) }) t.test('should return list of files in specified folder', async () => { let token = encode(null, { iss: 'development' }, secret) let data = await client.get('/media?token=' + token) assert.ok(data.length) let found = false for (let file of data) { if (file.name === '.gitkeep' && file.size === 0) { found = true break } } assert.ok(found) }) }) t.describe('GET /media/:site', function() { t.test('should give 404 on invalid sites', async () => { let err = await assert.isRejected(client.get('/media/development')) assert.strictEqual(err.status, 404) err = await assert.isRejected(client.get('/media/nonexisting')) assert.strictEqual(err.status, 404) err = await assert.isRejected(client.get('/media/blabla')) assert.strictEqual(err.status, 404) }) t.test('should otherwise return list of files for a public site', async () => { let files = await client.get('/media/existing') assert.strictEqual(files[0].name, '20220105_101610_test1.jpg') assert.strictEqual(files[0].size, 15079) assert.strictEqual(files[1].name, '20220105_101610_test2.png') assert.strictEqual(files[1].size, 31705) }) }) })