diff --git a/.changeset/lovely-berries-type.md b/.changeset/lovely-berries-type.md new file mode 100644 index 0000000000000..2c7d82476f1fc --- /dev/null +++ b/.changeset/lovely-berries-type.md @@ -0,0 +1,5 @@ +--- +"@rocket.chat/meteor": patch +--- + +Allowed upload of `lst` files diff --git a/apps/meteor/app/utils/lib/mimeTypes.ts b/apps/meteor/app/utils/lib/mimeTypes.ts index dd166f17bed31..f2da185f84ba8 100644 --- a/apps/meteor/app/utils/lib/mimeTypes.ts +++ b/apps/meteor/app/utils/lib/mimeTypes.ts @@ -1,6 +1,7 @@ import mime from 'mime-type/with-db'; mime.types.wav = 'audio/wav'; +mime.types.lst = 'text/plain'; mime.define('image/vnd.microsoft.icon', { source: '', extensions: ['ico'] }, mime.dupAppend); mime.define('image/x-icon', { source: '', extensions: ['ico'] }, mime.dupAppend); mime.types.ico = 'image/x-icon'; diff --git a/apps/meteor/tests/data/interactions.ts b/apps/meteor/tests/data/interactions.ts index b7d45b99dc999..d147491811939 100644 --- a/apps/meteor/tests/data/interactions.ts +++ b/apps/meteor/tests/data/interactions.ts @@ -1,4 +1,5 @@ export const targetUser = 'rocket.cat'; export const imgURL = './public/images/logo/1024x1024.png'; +export const lstURL = './tests/e2e/fixtures/files/lst-test.lst'; export const svgLogoURL = './public/images/logo/logo.svg'; export const svgLogoFileName = 'logo.svg'; diff --git a/apps/meteor/tests/e2e/file-upload.spec.ts b/apps/meteor/tests/e2e/file-upload.spec.ts index 9b731e474078b..b382476c0a2f7 100644 --- a/apps/meteor/tests/e2e/file-upload.spec.ts +++ b/apps/meteor/tests/e2e/file-upload.spec.ts @@ -20,20 +20,24 @@ test.describe.serial('file-upload', () => { await poHomeChannel.sidenav.openChat(targetChannel); }); + test.afterAll(async ({ api }) => { + expect((await api.post('/channels.delete', { roomName: targetChannel })).status()).toBe(200); + }); + test('expect successfully cancel upload', async () => { - await poHomeChannel.content.dragAndDropFile(); + await poHomeChannel.content.dragAndDropTxtFile(); await poHomeChannel.content.btnModalCancel.click(); await expect(poHomeChannel.content.modalFilePreview).not.toBeVisible(); }); test('expect send file not show modal', async () => { - await poHomeChannel.content.dragAndDropFile(); + await poHomeChannel.content.dragAndDropTxtFile(); await poHomeChannel.content.btnModalConfirm.click(); await expect(poHomeChannel.content.modalFilePreview).not.toBeVisible(); }); test('expect send file with name/description updated', async () => { - await poHomeChannel.content.dragAndDropFile(); + await poHomeChannel.content.dragAndDropTxtFile(); await poHomeChannel.content.descriptionInput.fill('any_description'); await poHomeChannel.content.fileNameInput.fill('any_file1.txt'); await poHomeChannel.content.btnModalConfirm.click(); @@ -41,4 +45,13 @@ test.describe.serial('file-upload', () => { await expect(poHomeChannel.content.getFileDescription).toHaveText('any_description'); await expect(poHomeChannel.content.lastMessageFileName).toContainText('any_file1.txt'); }); + + test('expect send lst file succesfully', async () => { + await poHomeChannel.content.dragAndDropLstFile(); + await poHomeChannel.content.descriptionInput.fill('lst_description'); + await poHomeChannel.content.btnModalConfirm.click(); + + await expect(poHomeChannel.content.getFileDescription).toHaveText('lst_description'); + await expect(poHomeChannel.content.lastMessageFileName).toContainText('lst-test.lst'); + }); }); diff --git a/apps/meteor/tests/e2e/fixtures/files/lst-test.lst b/apps/meteor/tests/e2e/fixtures/files/lst-test.lst new file mode 100644 index 0000000000000..a62b7b221e7b4 --- /dev/null +++ b/apps/meteor/tests/e2e/fixtures/files/lst-test.lst @@ -0,0 +1,6 @@ +# Comment + +# Name Age +Tom 23 +Marcus 22 +Bryan 21 \ No newline at end of file diff --git a/apps/meteor/tests/e2e/page-objects/fragments/home-content.ts b/apps/meteor/tests/e2e/page-objects/fragments/home-content.ts index 9fd067c407b1b..e258327ef6dcb 100644 --- a/apps/meteor/tests/e2e/page-objects/fragments/home-content.ts +++ b/apps/meteor/tests/e2e/page-objects/fragments/home-content.ts @@ -216,9 +216,8 @@ export class HomeContent { await this.page.locator(`role=dialog[name="Emoji picker"] >> role=tabpanel >> role=button[name="${emoji}"]`).click(); } - async dragAndDropFile(): Promise { + async dragAndDropTxtFile(): Promise { const contract = await fs.readFile('./tests/e2e/fixtures/files/any_file.txt', 'utf-8'); - const dataTransfer = await this.page.evaluateHandle((contract) => { const data = new DataTransfer(); const file = new File([`${contract}`], 'any_file.txt', { @@ -233,6 +232,22 @@ export class HomeContent { await this.page.locator('[role=dialog][data-qa="DropTargetOverlay"]').dispatchEvent('drop', { dataTransfer }); } + async dragAndDropLstFile(): Promise { + const contract = await fs.readFile('./tests/e2e/fixtures/files/lst-test.lst', 'utf-8'); + const dataTransfer = await this.page.evaluateHandle((contract) => { + const data = new DataTransfer(); + const file = new File([`${contract}`], 'lst-test.lst', { + type: 'text/plain', + }); + data.items.add(file); + return data; + }, contract); + + await this.inputMessage.dispatchEvent('dragenter', { dataTransfer }); + + await this.page.locator('[role=dialog][data-qa="DropTargetOverlay"]').dispatchEvent('drop', { dataTransfer }); + } + async openLastMessageMenu(): Promise { await this.page.locator('[data-qa-type="message"]').last().hover(); await this.page.locator('[data-qa-type="message"]').last().locator('role=button[name="More"]').waitFor(); diff --git a/apps/meteor/tests/end-to-end/api/09-rooms.js b/apps/meteor/tests/end-to-end/api/09-rooms.js index faf9dfd29462f..e60cf8c1f6b42 100644 --- a/apps/meteor/tests/end-to-end/api/09-rooms.js +++ b/apps/meteor/tests/end-to-end/api/09-rooms.js @@ -7,7 +7,7 @@ import { after, afterEach, before, beforeEach, describe, it } from 'mocha'; import { sleep } from '../../../lib/utils/sleep'; import { getCredentials, api, request, credentials } from '../../data/api-data.js'; import { sendSimpleMessage, deleteMessage } from '../../data/chat.helper'; -import { imgURL, svgLogoFileName, svgLogoURL } from '../../data/interactions'; +import { imgURL, lstURL, svgLogoFileName, svgLogoURL } from '../../data/interactions'; import { getSettingValueById, updateEEPermission, updatePermission, updateSetting } from '../../data/permissions.helper'; import { closeRoom, createRoom, deleteRoom } from '../../data/rooms.helper'; import { password } from '../../data/user'; @@ -156,8 +156,8 @@ describe('[Rooms]', function () { let fileNewUrl; let fileOldUrl; - it('upload a file to room', (done) => { - request + it('should upload a PNG file to room', async () => { + await request .post(api(`rooms.upload/${testChannel._id}`)) .set(credentials) .attach('file', imgURL) @@ -166,16 +166,56 @@ describe('[Rooms]', function () { .expect((res) => { const { message } = res.body; expect(res.body).to.have.property('success', true); - expect(res.body).to.have.nested.property('message._id', message._id); - expect(res.body).to.have.nested.property('message.rid', testChannel._id); - expect(res.body).to.have.nested.property('message.file._id', message.file._id); - expect(res.body).to.have.nested.property('message.file.type', message.file.type); + expect(res.body).to.have.property('message'); + expect(res.body.message).to.have.property('attachments'); + expect(res.body.message.attachments).to.be.an('array').of.length(1); + expect(res.body.message.attachments[0]).to.have.property('image_type', 'image/png'); + expect(res.body.message.attachments[0]).to.have.property('title', '1024x1024.png'); + expect(res.body.message).to.have.property('files'); + expect(res.body.message.files).to.be.an('array').of.length(2); + expect(res.body.message.files[0]).to.have.property('type', 'image/png'); + expect(res.body.message.files[0]).to.have.property('name', '1024x1024.png'); + fileNewUrl = `/file-upload/${message.file._id}/${message.file.name}`; fileOldUrl = `/ufs/GridFS:Uploads/${message.file._id}/${message.file.name}`; + }); + }); + + it('should upload a LST file to room', (done) => { + request + .post(api(`rooms.upload/${testChannel._id}`)) + .set(credentials) + .attach('file', lstURL) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + expect(res.body).to.have.property('message'); + expect(res.body.message).to.have.property('attachments'); + expect(res.body.message.attachments).to.be.an('array').of.length(1); + expect(res.body.message.attachments[0]).to.have.property('format', 'LST'); + expect(res.body.message.attachments[0]).to.have.property('title', 'lst-test.lst'); + expect(res.body.message).to.have.property('files'); + expect(res.body.message.files).to.be.an('array').of.length(1); + expect(res.body.message.files[0]).to.have.property('name', 'lst-test.lst'); }) .end(done); }); + it('should not allow uploading a blocked media type to a room', async () => { + await updateSetting('FileUpload_MediaTypeBlackList', 'application/octet-stream'); + await request + .post(api(`rooms.upload/${testChannel._id}`)) + .set(credentials) + .attach('file', lstURL) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('errorType', 'error-invalid-file-type'); + }); + }); + it('should be able to get the file', async () => { await request.get(fileNewUrl).set(credentials).expect('Content-Type', 'image/png').expect(200); await request.get(fileOldUrl).set(credentials).expect('Content-Type', 'image/png').expect(200);