Skip to content

Commit

Permalink
Merge pull request #27261 from RocketChat/release-5.3.1
Browse files Browse the repository at this point in the history
  • Loading branch information
ggazzo authored Nov 14, 2022
2 parents eb12200 + 26a8a75 commit a639f20
Show file tree
Hide file tree
Showing 31 changed files with 543 additions and 170 deletions.
77 changes: 77 additions & 0 deletions .github/history.json
Original file line number Diff line number Diff line change
Expand Up @@ -95549,6 +95549,83 @@
"5.0"
],
"pull_requests": []
},
"5.3.1": {
"node_version": "14.19.3",
"npm_version": "6.14.17",
"mongo_versions": [
"4.2",
"4.4",
"5.0"
],
"pull_requests": [
{
"pr": "27243",
"title": "[FIX] Multi instance error message",
"userLogin": "sampaiodiego",
"milestone": "5.3.1",
"contributors": [
"sampaiodiego",
"kodiakhq[bot]",
"web-flow"
]
},
{
"pr": "27240",
"title": "[FIX] Next schedule check for Apps",
"userLogin": "sampaiodiego",
"milestone": "5.3.1",
"contributors": [
"sampaiodiego"
]
},
{
"pr": "27151",
"title": "[FIX] Hide system messages setting not being respected.",
"userLogin": "gabriellsh",
"description": "There was a query missing the parameters in the client.\r\n\r\nAlso added a few tests to help reduce the risk of this happening again.",
"milestone": "5.3.1",
"contributors": [
"gabriellsh",
"ggazzo",
"web-flow",
"kodiakhq[bot]"
]
},
{
"pr": "27229",
"title": "Chore: Check for Cloud client secret to check if workspace is registered",
"userLogin": "sampaiodiego",
"milestone": "5.3.1",
"contributors": [
"sampaiodiego"
]
},
{
"pr": "27105",
"title": "[FIX] File upload receiving whole file to apply limits",
"userLogin": "sampaiodiego",
"milestone": "5.3.1",
"contributors": [
"sampaiodiego",
"web-flow",
"ggazzo",
"casalsgh"
]
},
{
"pr": "27167",
"title": "[FIX] User merge by e-mail on OAuth is case-sensitive",
"userLogin": "matheusbsilva137",
"description": "- Ignore case when searching for a user by email.",
"milestone": "5.3.1",
"contributors": [
"matheusbsilva137",
"kodiakhq[bot]",
"web-flow"
]
}
]
}
}
}
45 changes: 44 additions & 1 deletion HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,49 @@

# 5.3.1
`2022-11-14 · 5 🐛 · 1 🔍 · 5 👩‍💻👨‍💻`

### Engine versions
- Node: `14.19.3`
- NPM: `6.14.17`
- MongoDB: `4.2, 4.4, 5.0`

### 🐛 Bug fixes


- File upload receiving whole file to apply limits ([#27105](https://github.com/RocketChat/Rocket.Chat/pull/27105))

- Hide system messages setting not being respected. ([#27151](https://github.com/RocketChat/Rocket.Chat/pull/27151))

There was a query missing the parameters in the client.

Also added a few tests to help reduce the risk of this happening again.

- Multi instance error message ([#27243](https://github.com/RocketChat/Rocket.Chat/pull/27243))

- Next schedule check for Apps ([#27240](https://github.com/RocketChat/Rocket.Chat/pull/27240))

- User merge by e-mail on OAuth is case-sensitive ([#27167](https://github.com/RocketChat/Rocket.Chat/pull/27167))

- Ignore case when searching for a user by email.

<details>
<summary>🔍 Minor changes</summary>


- Chore: Check for Cloud client secret to check if workspace is registered ([#27229](https://github.com/RocketChat/Rocket.Chat/pull/27229))

</details>

### 👩‍💻👨‍💻 Core Team 🤓

- [@casalsgh](https://github.com/casalsgh)
- [@gabriellsh](https://github.com/gabriellsh)
- [@ggazzo](https://github.com/ggazzo)
- [@matheusbsilva137](https://github.com/matheusbsilva137)
- [@sampaiodiego](https://github.com/sampaiodiego)

# 5.3.0
`2022-10-31 · 3 🎉 · 4 🚀 · 13 🐛 · 23 🔍 · 23 👩‍💻👨‍💻`
`2022-11-01 · 3 🎉 · 4 🚀 · 13 🐛 · 23 🔍 · 23 👩‍💻👨‍💻`

### Engine versions
- Node: `14.19.3`
Expand Down
2 changes: 1 addition & 1 deletion apps/meteor/.docker/Dockerfile.rhel
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM registry.access.redhat.com/ubi8/nodejs-12

ENV RC_VERSION 5.3.0
ENV RC_VERSION 5.3.1

MAINTAINER buildmaster@rocket.chat

Expand Down
157 changes: 100 additions & 57 deletions apps/meteor/app/api/server/lib/getUploadFormData.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
import type { Readable } from 'stream';

import { Meteor } from 'meteor/meteor';
import type { Request } from 'express';
import busboy from 'busboy';
import type { ValidateFunction } from 'ajv';

type UploadResult = {
file: Readable;
import { MeteorError } from '../../../../server/sdk/errors';

type UploadResult<K> = {
file: Readable & { truncated: boolean };
fieldname: string;
filename: string;
encoding: string;
mimetype: string;
fileBuffer: Buffer;
fields: K;
};

export const getUploadFormData = async <
export async function getUploadFormData<
T extends string,
K extends Record<string, string> = Record<string, string>,
V extends ValidateFunction<K> = ValidateFunction<K>,
Expand All @@ -22,63 +25,103 @@ export const getUploadFormData = async <
options: {
field?: T;
validate?: V;
sizeLimit?: number;
} = {},
): Promise<[UploadResult, K, T]> =>
new Promise((resolve, reject) => {
const bb = busboy({ headers: request.headers, defParamCharset: 'utf8' });
const fields = Object.create(null) as K;

let uploadedFile: UploadResult | undefined;

let assetName: T | undefined;

bb.on(
'file',
(
fieldname: string,
file: Readable,
{ filename, encoding, mimeType: mimetype }: { filename: string; encoding: string; mimeType: string },
) => {
const fileData: Uint8Array[] = [];

file.on('data', (data: any) => fileData.push(data));

file.on('end', () => {
if (uploadedFile) {
return reject('Just 1 file is allowed');
}
if (options.field && fieldname !== options.field) {
return reject(new Meteor.Error('invalid-field'));
}
uploadedFile = {
file,
filename,
encoding,
mimetype,
fileBuffer: Buffer.concat(fileData),
};

assetName = fieldname as T;
});
},
);

bb.on('field', (fieldname: keyof K, value: K[keyof K]) => {
fields[fieldname] = value;
): Promise<UploadResult<K>> {
const limits = {
files: 1,
...(options.sizeLimit && options.sizeLimit > -1 && { fileSize: options.sizeLimit }),
};

const bb = busboy({ headers: request.headers, defParamCharset: 'utf8', limits });
const fields = Object.create(null) as K;

let uploadedFile: UploadResult<K> | undefined;

let returnResult = (_value: UploadResult<K>) => {
// noop
};
let returnError = (_error?: Error | string | null | undefined) => {
// noop
};

function onField(fieldname: keyof K, value: K[keyof K]) {
fields[fieldname] = value;
}

function onEnd() {
if (!uploadedFile) {
return returnError(new MeteorError('No file uploaded'));
}
if (options.validate !== undefined && !options.validate(fields)) {
return returnError(new MeteorError(`Invalid fields ${options.validate.errors?.join(', ')}`));
}
return returnResult(uploadedFile);
}

function onFile(
fieldname: string,
file: Readable & { truncated: boolean },
{ filename, encoding, mimeType: mimetype }: { filename: string; encoding: string; mimeType: string },
) {
if (options.field && fieldname !== options.field) {
file.resume();
return returnError(new MeteorError('invalid-field'));
}

const fileChunks: Uint8Array[] = [];
file.on('data', function (chunk) {
fileChunks.push(chunk);
});

bb.on('finish', () => {
if (!uploadedFile || !assetName) {
return reject('No file uploaded');
}
if (options.validate === undefined) {
return resolve([uploadedFile, fields, assetName]);
}
if (!options.validate(fields)) {
return reject(`Invalid fields${options.validate.errors?.join(', ')}`);
file.on('end', function () {
if (file.truncated) {
fileChunks.length = 0;
return returnError(new MeteorError('error-file-too-large'));
}
return resolve([uploadedFile, fields, assetName]);

uploadedFile = {
file,
filename,
encoding,
mimetype,
fieldname,
fields,
fileBuffer: Buffer.concat(fileChunks),
};
});
}

function cleanup() {
request.unpipe(bb);
request.on('readable', request.read.bind(request));
bb.removeAllListeners();
}

bb.on('field', onField);
bb.on('file', onFile);
bb.on('close', cleanup);
bb.on('end', onEnd);
bb.on('finish', onEnd);

bb.on('error', function (err: Error) {
returnError(err);
});

bb.on('partsLimit', function () {
returnError();
});
bb.on('filesLimit', function () {
returnError('Just 1 file is allowed');
});
bb.on('fieldsLimit', function () {
returnError();
});

request.pipe(bb);

request.pipe(bb);
return new Promise((resolve, reject) => {
returnResult = resolve;
returnError = reject;
});
}
13 changes: 9 additions & 4 deletions apps/meteor/app/api/server/v1/assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,33 @@ import { isAssetsUnsetAssetProps } from '@rocket.chat/rest-typings';
import { RocketChatAssets } from '../../../assets/server';
import { API } from '../api';
import { getUploadFormData } from '../lib/getUploadFormData';
import { settings } from '../../../settings/server';

API.v1.addRoute(
'assets.setAsset',
{ authRequired: true },
{
async post() {
const [asset, { refreshAllClients, assetName: customName }, fileName] = await getUploadFormData(
const asset = await getUploadFormData(
{
request: this.request,
},
{ field: 'asset' },
{ field: 'asset', sizeLimit: settings.get('FileUpload_MaxFileSize') },
);

const assetName = customName || fileName;
const { fileBuffer, fields, filename, mimetype } = asset;

const { refreshAllClients, assetName: customName } = fields;

const assetName = customName || filename;
const assetsKeys = Object.keys(RocketChatAssets.assets);

const isValidAsset = assetsKeys.includes(assetName);
if (!isValidAsset) {
throw new Meteor.Error('error-invalid-asset', 'Invalid asset');
}

Meteor.call('setAsset', asset.fileBuffer, asset.mimetype, assetName);
Meteor.call('setAsset', fileBuffer, mimetype, assetName);
if (refreshAllClients) {
Meteor.call('refreshClients');
}
Expand Down
Loading

0 comments on commit a639f20

Please sign in to comment.