chore!: Remove deprecated `rooms.upload` endpoint (#36857)

Co-authored-by: juliajforesti <juliajforesti@gmail.com>
pull/35380/merge
Martin Schoeler 4 months ago committed by Guilherme Gazzo
parent 239f4b1171
commit dccdcc5b4a
  1. 6
      .changeset/swift-ears-sparkle.md
  2. 68
      apps/meteor/app/api/server/v1/rooms.ts
  3. 24
      apps/meteor/tests/data/uploads.helper.ts
  4. 12
      apps/meteor/tests/end-to-end/api/chat.ts
  5. 340
      apps/meteor/tests/end-to-end/api/rooms.ts
  6. 14
      packages/rest-typings/src/v1/rooms.ts

@ -0,0 +1,6 @@
---
"@rocket.chat/meteor": major
"@rocket.chat/rest-typings": major
---
Removes the deprecated `/api/v1/rooms.upload` endpoint

@ -188,74 +188,6 @@ API.v1.addRoute(
},
);
API.v1.addRoute(
'rooms.upload/:rid',
{
authRequired: true,
deprecation: {
version: '8.0.0',
alternatives: ['/v1/rooms.media/:rid'],
},
},
{
async post() {
if (!(await canAccessRoomIdAsync(this.urlParams.rid, this.userId))) {
return API.v1.forbidden();
}
const file = await getUploadFormData(
{
request: this.request,
},
{ field: 'file', sizeLimit: settings.get<number>('FileUpload_MaxFileSize') },
);
if (!file) {
throw new Meteor.Error('invalid-field');
}
const { fields } = file;
let { fileBuffer } = file;
const details = {
name: file.filename,
size: fileBuffer.length,
type: file.mimetype,
rid: this.urlParams.rid,
userId: this.userId,
};
const stripExif = settings.get('Message_Attachments_Strip_Exif');
if (stripExif) {
// No need to check mime. Library will ignore any files without exif/xmp tags (like BMP, ico, PDF, etc)
fileBuffer = await Media.stripExifFromBuffer(fileBuffer);
details.size = fileBuffer.length;
}
const fileStore = FileUpload.getStore('Uploads');
const uploadedFile = await fileStore.insert(details, fileBuffer);
if ((fields.description?.length ?? 0) > settings.get<number>('Message_MaxAllowedSize')) {
throw new Meteor.Error('error-message-size-exceeded');
}
uploadedFile.description = fields.description;
delete fields.description;
await applyAirGappedRestrictionsValidation(() =>
sendFileMessage(this.userId, { roomId: this.urlParams.rid, file: uploadedFile, msgData: fields }),
);
const message = await Messages.getMessageByFileIdAndUsername(uploadedFile._id, this.userId);
return API.v1.success({
message,
});
},
},
);
API.v1.addRoute(
'rooms.media/:rid',
{ authRequired: true },

@ -165,17 +165,25 @@ export async function testFileUploads(
.end(done);
});
let fileId: string;
it('should not return thumbnails', async () => {
await request
.post(api(`rooms.upload/${testRoom._id}`))
.post(api(`rooms.media/${testRoom._id}`))
.set(credentials)
.attach('file', imgURL)
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res: Response) => {
expect(res.body).to.have.property('success', true);
fileId = res.body.file._id;
});
await request
.post(api(`rooms.mediaConfirm/${testRoom._id}/${fileId}`))
.set(credentials)
.expect('Content-Type', 'application/json')
.expect(200);
await request
.get(api(filesEndpoint))
.set(credentials)
@ -198,19 +206,25 @@ export async function testFileUploads(
it('should not return hidden files', async () => {
let msgId;
let fileId: string;
await request
.post(api(`rooms.upload/${testRoom._id}`))
.post(api(`rooms.media/${testRoom._id}`))
.set(credentials)
.attach('file', imgURL)
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res: Response) => {
expect(res.body).to.have.property('success', true);
fileId = res.body.file._id;
});
await request
.post(api(`rooms.mediaConfirm/${testRoom._id}/${fileId}`))
.set(credentials)
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res: Response) => {
expect(res.body).to.have.property('success', true);
msgId = res.body.message._id;
fileId = res.body.message.file._id;
});
await request

@ -7,7 +7,6 @@ import type { Response } from 'supertest';
import { getCredentials, api, request, credentials, apiUrl } from '../../data/api-data';
import { followMessage, sendSimpleMessage, deleteMessage } from '../../data/chat.helper';
import { imgURL } from '../../data/interactions';
import { updatePermission, updateSetting } from '../../data/permissions.helper';
import { addUserToRoom, createRoom, deleteRoom, getSubscriptionByRoomId } from '../../data/rooms.helper';
import { password } from '../../data/user';
@ -1423,17 +1422,6 @@ describe('[Chat]', () => {
.expect(statusCode)
.expect(testCb);
await (
customFields
? request.post(api(`rooms.upload/${testChannel._id}`)).field('customFields', JSON.stringify(customFields))
: request.post(api(`rooms.upload/${testChannel._id}`))
)
.set(credentials)
.attach('file', imgURL)
.expect('Content-Type', 'application/json')
.expect(statusCode)
.expect(testCb);
await request
.post(api('chat.postMessage'))
.set(credentials)

@ -32,7 +32,6 @@ import { createUser, deleteUser, login } from '../../data/users.helper';
import { IS_EE } from '../../e2e/config/constants';
const lstURL = './tests/e2e/fixtures/files/lst-test.lst';
const drawioURL = './tests/e2e/fixtures/files/diagram.drawio';
const svgLogoURL = './public/images/logo/logo.svg';
const svgLogoFileName = 'logo.svg';
@ -100,320 +99,6 @@ describe('[Rooms]', () => {
});
});
describe('/rooms.upload', () => {
let testChannel: IRoom;
let user: TestUser<IUser>;
let userCredentials: Credentials;
const testChannelName = `channel.test.upload.${Date.now()}-${Math.random()}`;
let blockedMediaTypes: SettingValue;
let testPrivateChannel: IRoom;
before(async () => {
user = await createUser({ joinDefaultChannels: false });
userCredentials = await login(user.username, password);
testChannel = (await createRoom({ type: 'c', name: testChannelName })).body.channel;
testPrivateChannel = (await createRoom({ type: 'p', name: `channel.test.private.${Date.now()}-${Math.random()}` })).body.group;
blockedMediaTypes = await getSettingValueById('FileUpload_MediaTypeBlackList');
const newBlockedMediaTypes = (blockedMediaTypes as string)
.split(',')
.filter((type) => type !== 'image/svg+xml')
.join(',');
await updateSetting('FileUpload_MediaTypeBlackList', newBlockedMediaTypes);
});
after(() =>
Promise.all([
deleteRoom({ type: 'c', roomId: testChannel._id }),
deleteUser(user),
updateSetting('FileUpload_Restrict_to_room_members', true),
updateSetting('FileUpload_Restrict_to_users_who_can_access_room', false),
updateSetting('FileUpload_ProtectFiles', true),
updateSetting('FileUpload_MediaTypeBlackList', blockedMediaTypes),
deleteRoom({ roomId: testPrivateChannel._id, type: 'p' }),
]),
);
it("don't upload a file to room with file field other than file", (done) => {
void request
.post(api(`rooms.upload/${testChannel._id}`))
.set(credentials)
.attach('test', imgURL)
.expect('Content-Type', 'application/json')
.expect(400)
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body).to.have.property('error', '[invalid-field]');
expect(res.body).to.have.property('errorType', 'invalid-field');
})
.end(done);
});
it("don't upload a file to room with empty file", (done) => {
void request
.post(api(`rooms.upload/${testChannel._id}`))
.set(credentials)
.attach('file', '')
.expect('Content-Type', 'application/json')
.expect(400)
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body).to.have.property('error', res.body.error);
})
.end(done);
});
it("don't upload a file to room with more than 1 file", (done) => {
void request
.post(api(`rooms.upload/${testChannel._id}`))
.set(credentials)
.attach('file', imgURL)
.attach('file', imgURL)
.expect('Content-Type', 'application/json')
.expect(400)
.expect((res) => {
expect(res.body).to.have.property('success', false);
expect(res.body).to.have.property('error', 'Just 1 file is allowed');
})
.end(done);
});
let fileNewUrl: string;
let fileOldUrl: string;
it('should upload a PNG file to room', async () => {
await request
.post(api(`rooms.upload/${testChannel._id}`))
.set(credentials)
.attach('file', imgURL)
.expect('Content-Type', 'application/json')
.expect(200)
.expect((res) => {
const message = res.body.message as IMessage;
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('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');
assert.isDefined(message.file);
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', () => {
return 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');
expect(res.body.message.files[0]).to.have.property('type', 'text/plain');
});
});
it('should upload a DRAWIO file (unknown media type) to room', () => {
return request
.post(api(`rooms.upload/${testChannel._id}`))
.set(credentials)
.attach('file', drawioURL)
.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', 'DRAWIO');
expect(res.body.message.attachments[0]).to.have.property('title', 'diagram.drawio');
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', 'diagram.drawio');
expect(res.body.message.files[0]).to.have.property('type', 'application/octet-stream');
});
});
it('should not allow uploading a blocked media type to a room', async () => {
await updateSetting('FileUpload_MediaTypeBlackList', 'text/plain');
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 not allow uploading an unknown media type to a room if the default one is blocked', async () => {
await updateSetting('FileUpload_MediaTypeBlackList', 'application/octet-stream');
await request
.post(api(`rooms.upload/${testChannel._id}`))
.set(credentials)
.attach('file', drawioURL)
.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);
});
it('should be able to get the file when no access to the room if setting allows it', async () => {
await updateSetting('FileUpload_Restrict_to_room_members', false);
await updateSetting('FileUpload_Restrict_to_users_who_can_access_room', false);
await request.get(fileNewUrl).set(userCredentials).expect('Content-Type', 'image/png').expect(200);
await request.get(fileOldUrl).set(userCredentials).expect('Content-Type', 'image/png').expect(200);
});
it('should not be able to get the file when no access to the room if setting blocks', async () => {
await updateSetting('FileUpload_Restrict_to_room_members', true);
await request.get(fileNewUrl).set(userCredentials).expect(403);
await request.get(fileOldUrl).set(userCredentials).expect(403);
});
it('should be able to get the file if member and setting blocks outside access', async () => {
await updateSetting('FileUpload_Restrict_to_room_members', true);
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);
});
it('should be able to get the file if not member but can access room if setting allows', async () => {
await updateSetting('FileUpload_Restrict_to_room_members', false);
await updateSetting('FileUpload_Restrict_to_users_who_can_access_room', true);
await request.get(fileNewUrl).set(userCredentials).expect('Content-Type', 'image/png').expect(200);
await request.get(fileOldUrl).set(userCredentials).expect('Content-Type', 'image/png').expect(200);
});
it('should not be able to get the file if not member and cannot access room', async () => {
const { body } = await request
.post(api(`rooms.upload/${testPrivateChannel._id}`))
.set(credentials)
.attach('file', imgURL)
.expect('Content-Type', 'application/json')
.expect(200);
const fileUrl = `/file-upload/${body.message.file._id}/${body.message.file.name}`;
await request.get(fileUrl).set(userCredentials).expect(403);
});
it('should respect the setting with less permissions when both are true', async () => {
await updateSetting('FileUpload_ProtectFiles', true);
await updateSetting('FileUpload_Restrict_to_room_members', true);
await updateSetting('FileUpload_Restrict_to_users_who_can_access_room', true);
await request.get(fileNewUrl).set(userCredentials).expect(403);
await request.get(fileOldUrl).set(userCredentials).expect(403);
});
it('should not be able to get the file without credentials', async () => {
await request.get(fileNewUrl).attach('file', imgURL).expect(403);
await request.get(fileOldUrl).attach('file', imgURL).expect(403);
});
it('should be able to get the file without credentials if setting allows', async () => {
await updateSetting('FileUpload_ProtectFiles', false);
await request.get(fileNewUrl).expect('Content-Type', 'image/png').expect(200);
await request.get(fileOldUrl).expect('Content-Type', 'image/png').expect(200);
});
it('should generate thumbnail for SVG files correctly', async () => {
const expectedFileName = `thumb-${svgLogoFileName}`;
const res = await request
.post(api(`rooms.upload/${testChannel._id}`))
.set(credentials)
.attach('file', svgLogoURL)
.expect('Content-Type', 'application/json')
.expect(200);
const message = res.body.message as IMessage;
const { files, attachments } = message;
expect(files).to.be.an('array');
const hasThumbFile = files?.some((file) => file.type === 'image/png' && file.name === expectedFileName);
expect(hasThumbFile).to.be.true;
expect(attachments).to.be.an('array');
const thumbAttachment = attachments?.find((attachment) => attachment.title === svgLogoFileName);
assert.isDefined(thumbAttachment);
expect(thumbAttachment).to.be.an('object');
const thumbUrl = (thumbAttachment as ImageAttachmentProps).image_url;
await request.get(thumbUrl).set(credentials).expect('Content-Type', 'image/png');
});
it('should generate thumbnail for JPEG files correctly', async () => {
const expectedFileName = `thumb-sample-jpeg.jpg`;
const res = await request
.post(api(`rooms.upload/${testChannel._id}`))
.set(credentials)
.attach('file', fs.createReadStream(path.join(__dirname, '../../mocks/files/sample-jpeg.jpg')))
.expect('Content-Type', 'application/json')
.expect(200);
const message = res.body.message as IMessage;
const { files, attachments } = message;
expect(files).to.be.an('array');
assert.isDefined(files);
const hasThumbFile = files.some((file) => file.type === 'image/jpeg' && file.name === expectedFileName);
expect(hasThumbFile).to.be.true;
expect(attachments).to.be.an('array');
assert.isDefined(attachments);
const thumbAttachment = attachments.find((attachment) => attachment.title === `sample-jpeg.jpg`);
expect(thumbAttachment).to.be.an('object');
const thumbUrl = (thumbAttachment as ImageAttachmentProps).image_url;
await request.get(thumbUrl).set(credentials).expect('Content-Type', 'image/jpeg');
});
// Support legacy behavior (not encrypting file)
it('should correctly save file description and properties with type e2e', async () => {
await request
.post(api(`rooms.upload/${testChannel._id}`))
.set(credentials)
.field('description', 'some_file_description')
.attach('file', imgURL)
.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('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');
expect(res.body.message.attachments[0]).to.have.property('description', 'some_file_description');
});
});
});
describe('/rooms.media', () => {
let testChannel: IRoom;
let user: TestUser<IUser>;
@ -1142,7 +827,7 @@ describe('[Rooms]', () => {
});
it('should successfully delete an image and thumbnail from public channel', (done) => {
void request
.post(api(`rooms.upload/${publicChannel._id}`))
.post(api(`rooms.media/${publicChannel._id}`))
.set(credentials)
.attach('file', imgURL)
.expect('Content-Type', 'application/json')
@ -2962,14 +2647,29 @@ describe('[Rooms]', () => {
});
const uploadFile = async ({ roomId, file }: { roomId: IRoom['_id']; file: Buffer | fs.ReadStream | string | boolean | number }) => {
const { body } = await request
.post(api(`rooms.upload/${roomId}`))
let fileId;
await request
.post(api(`rooms.media/${roomId}`))
.set(credentials)
.attach('file', file)
.expect('Content-Type', 'application/json')
.expect(200);
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
expect(res.body).to.have.property('file');
expect(res.body.file).to.have.property('_id');
fileId = res.body.file._id;
});
const res = await request
.post(api(`rooms.mediaConfirm/${roomId}/${fileId}`))
.set(credentials)
.expect(200)
.expect((res) => {
expect(res.body).to.have.property('success', true);
});
return body.message.attachments[0];
return res.body.message.attachments[0];
};
const getIdFromImgPath = (link: string) => {

@ -782,20 +782,6 @@ export type RoomsEndpoints = {
};
};
'/v1/rooms.upload/:rid': {
POST: (params: {
file: File;
description?: string;
avatar?: string;
emoji?: string;
alias?: string;
groupable?: boolean;
msg?: string;
tmid?: string;
customFields?: string;
}) => { message: IMessage | null };
};
'/v1/rooms.media/:rid': {
POST: (params: { file: File }) => { file: { url: string } };
};

Loading…
Cancel
Save