From df115b2c084462a97dc17e119fac20c1dc219222 Mon Sep 17 00:00:00 2001 From: Diego Sampaio Date: Fri, 26 Mar 2021 18:57:01 -0300 Subject: [PATCH 1/2] Bump version to 3.8.9 --- .docker/Dockerfile.rhel | 2 +- .github/history-manual.json | 7 ++ .github/history.json | 11 +++ .github/workflows/build_and_test.yml | 1 + .snapcraft/resources/prepareRocketChat | 2 +- .snapcraft/snap/snapcraft.yaml | 2 +- HISTORY.md | 97 ++++++++++--------- app/api/server/v1/users.js | 3 +- app/authorization/server/functions/hasRole.js | 5 +- .../server/methods/insertOrUpdateEmoji.js | 2 + .../server/methods/uploadEmojiCustom.js | 18 +++- app/lib/server/functions/setUserAvatar.js | 8 +- app/meteor-accounts-saml/server/lib/SAML.ts | 20 ++-- .../server/loginHandler.ts | 2 +- app/models/server/raw/Roles.js | 6 +- app/utils/rocketchat.info | 2 +- package-lock.json | 2 +- package.json | 2 +- server/methods/addAllUserToRoom.js | 84 ++++++++-------- 19 files changed, 158 insertions(+), 118 deletions(-) diff --git a/.docker/Dockerfile.rhel b/.docker/Dockerfile.rhel index a21c1a283cb8..ea8336afe5ff 100644 --- a/.docker/Dockerfile.rhel +++ b/.docker/Dockerfile.rhel @@ -1,6 +1,6 @@ FROM registry.access.redhat.com/rhscl/nodejs-8-rhel7 -ENV RC_VERSION 3.8.8 +ENV RC_VERSION 3.8.9 MAINTAINER buildmaster@rocket.chat diff --git a/.github/history-manual.json b/.github/history-manual.json index 0ac6c0368f7b..db7291e8a8ee 100644 --- a/.github/history-manual.json +++ b/.github/history-manual.json @@ -49,5 +49,12 @@ "contributors": [ "sampaiodiego" ] + }], + "3.8.9": [{ + "title": "[FIX] Security Hotfix (https://docs.rocket.chat/guides/security/security-updates)", + "userLogin": "sampaiodiego", + "contributors": [ + "sampaiodiego" + ] }] } diff --git a/.github/history.json b/.github/history.json index 162cfce09230..40b7d013d3b4 100644 --- a/.github/history.json +++ b/.github/history.json @@ -51892,6 +51892,17 @@ "4.0" ], "pull_requests": [] + }, + "3.8.9": { + "node_version": "12.18.4", + "npm_version": "6.14.8", + "apps_engine_version": "1.19.0", + "mongo_versions": [ + "3.4", + "3.6", + "4.0" + ], + "pull_requests": [] } } } \ No newline at end of file diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 272c40ac57d5..26826c70e19e 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -382,6 +382,7 @@ jobs: env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + AWS_DEFAULT_REGION: 'us-east-1' GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }} REDHAT_REGISTRY_PID: ${{ secrets.REDHAT_REGISTRY_PID }} REDHAT_REGISTRY_KEY: ${{ secrets.REDHAT_REGISTRY_KEY }} diff --git a/.snapcraft/resources/prepareRocketChat b/.snapcraft/resources/prepareRocketChat index d7fcc7db67d3..29ce419e74b0 100755 --- a/.snapcraft/resources/prepareRocketChat +++ b/.snapcraft/resources/prepareRocketChat @@ -1,6 +1,6 @@ #!/bin/bash -curl -SLf "https://releases.rocket.chat/3.8.8/download/" -o rocket.chat.tgz +curl -SLf "https://releases.rocket.chat/3.8.9/download/" -o rocket.chat.tgz tar xf rocket.chat.tgz --strip 1 diff --git a/.snapcraft/snap/snapcraft.yaml b/.snapcraft/snap/snapcraft.yaml index 0ff0a528efad..a228c7904428 100644 --- a/.snapcraft/snap/snapcraft.yaml +++ b/.snapcraft/snap/snapcraft.yaml @@ -7,7 +7,7 @@ # 5. `snapcraft snap` name: rocketchat-server -version: 3.8.8 +version: 3.8.9 summary: Rocket.Chat server description: Have your own Slack like online chat, built with Meteor. https://rocket.chat/ confinement: strict diff --git a/HISTORY.md b/HISTORY.md index 296e3d998dee..b27b561204d4 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,4 +1,22 @@ +# 3.8.9 +`2021-03-26 ยท 1 ๐Ÿ› ยท 1 ๐Ÿ‘ฉโ€๐Ÿ’ป๐Ÿ‘จโ€๐Ÿ’ป` + +### Engine versions +- Node: `12.18.4` +- NPM: `6.14.8` +- MongoDB: `3.4, 3.6, 4.0` +- Apps-Engine: `1.19.0` + +### ๐Ÿ› Bug fixes + + +- Security Hotfix (https://docs.rocket.chat/guides/security/security-updates) + +### ๐Ÿ‘ฉโ€๐Ÿ’ป๐Ÿ‘จโ€๐Ÿ’ป Core Team ๐Ÿค“ + +- [@sampaiodiego](https://github.com/sampaiodiego) + # 3.8.6 `2021-01-26 ยท 1 ๐Ÿ› ยท 1 ๐Ÿ‘ฉโ€๐Ÿ’ป๐Ÿ‘จโ€๐Ÿ’ป` @@ -41,8 +59,6 @@ # 3.8.4 `2020-12-18 ยท 2 ๐Ÿ› ยท 1 ๐Ÿ‘ฉโ€๐Ÿ’ป๐Ÿ‘จโ€๐Ÿ’ป` -### Important XSS Security hotfix - ### Engine versions - Node: `12.18.4` - NPM: `6.14.8` @@ -905,10 +921,8 @@ - **2FA:** Password enforcement setting and 2FA protection when saving settings or resetting E2E encryption ([#18640](https://github.com/RocketChat/Rocket.Chat/pull/18640)) - - Increase the 2FA remembering time from 5min to 30min - - - Add new setting to enforce 2FA password fallback (enabled only for new installations) - + - Increase the 2FA remembering time from 5min to 30min + - Add new setting to enforce 2FA password fallback (enabled only for new installations) - Require 2FA to save settings and reset E2E Encryption keys - **Omnichannel:** Allow set other agent status via method `livechat:changeLivechatStatus ` ([#18571](https://github.com/RocketChat/Rocket.Chat/pull/18571)) @@ -926,7 +940,7 @@ - 2FA by Email setting showing for the user even when disabled by the admin ([#18473](https://github.com/RocketChat/Rocket.Chat/pull/18473)) - The option to disable/enable the **Two-factor authentication via Email** at `Account > Security > Two Factor Authentication + The option to disable/enable the **Two-factor authentication via Email** at `Account > Security > Two Factor Authentication ` was visible even when the setting **Enable Two Factor Authentication via Email** at `Admin > Accounts > Two Factor Authentication` was disabled leading to misbehavior since the functionality was disabled. - Agents enabledDepartment attribute not set on collection ([#18614](https://github.com/RocketChat/Rocket.Chat/pull/18614) by [@paulobernardoaf](https://github.com/paulobernardoaf)) @@ -1276,16 +1290,13 @@ - Mention autocomplete UI and performance improvements ([#18309](https://github.com/RocketChat/Rocket.Chat/pull/18309)) - * New setting to configure the number of suggestions `Admin > Layout > User Interface > Number of users' autocomplete suggestions` (default 5) - - * The UI shows whenever the user is not a member of the room - - * The UI shows when the suggestion came from the last messages for quick selection/reply - - * The suggestions follow this order: - * The user with the exact username and member of the room - * The user with the exact username but not a member of the room (if allowed to list non-members) - * The users containing the text in username, name or nickname and member of the room + * New setting to configure the number of suggestions `Admin > Layout > User Interface > Number of users' autocomplete suggestions` (default 5) + * The UI shows whenever the user is not a member of the room + * The UI shows when the suggestion came from the last messages for quick selection/reply + * The suggestions follow this order: + * The user with the exact username and member of the room + * The user with the exact username but not a member of the room (if allowed to list non-members) + * The users containing the text in username, name or nickname and member of the room * The users containing the text in username, name or nickname and not a member of the room (if allowed to list non-members) - Message action styles ([#18190](https://github.com/RocketChat/Rocket.Chat/pull/18190)) @@ -1627,10 +1638,10 @@ - Split NOTIFICATIONS_SCHEDULE_DELAY into three separate variables ([#17669](https://github.com/RocketChat/Rocket.Chat/pull/17669) by [@jazztickets](https://github.com/jazztickets)) - Email notification delay can now be customized with the following environment variables: - NOTIFICATIONS_SCHEDULE_DELAY_ONLINE - NOTIFICATIONS_SCHEDULE_DELAY_AWAY - NOTIFICATIONS_SCHEDULE_DELAY_OFFLINE + Email notification delay can now be customized with the following environment variables: + NOTIFICATIONS_SCHEDULE_DELAY_ONLINE + NOTIFICATIONS_SCHEDULE_DELAY_AWAY + NOTIFICATIONS_SCHEDULE_DELAY_OFFLINE Setting the value to -1 disable notifications for that type. - Threads ([#17416](https://github.com/RocketChat/Rocket.Chat/pull/17416)) @@ -2030,11 +2041,11 @@ - **ENTERPRISE:** Omnichannel Last-Chatted Agent Preferred option ([#17666](https://github.com/RocketChat/Rocket.Chat/pull/17666)) - If activated, this feature will store the last agent that assisted each Omnichannel visitor when a conversation is taken. So, when a visitor returns(it works with any entry point, Livechat, Facebook, REST API, and so on) and starts a new chat, the routing system checks: - - 1 - The visitor object for any stored agent that the visitor has previously talked to; - 2 - If a previous agent is not found, the system will try to find a previous conversation of the same visitor. If a room is found, the system will get the previous agent from the room; - + If activated, this feature will store the last agent that assisted each Omnichannel visitor when a conversation is taken. So, when a visitor returns(it works with any entry point, Livechat, Facebook, REST API, and so on) and starts a new chat, the routing system checks: + + 1 - The visitor object for any stored agent that the visitor has previously talked to; + 2 - If a previous agent is not found, the system will try to find a previous conversation of the same visitor. If a room is found, the system will get the previous agent from the room; + After this process, if an agent has been found, the system will check the agent's availability to assist the new chat. If it's not available, then the routing system will get the next available agent in the queue. - **ENTERPRISE:** Support for custom Livechat registration form fields ([#17581](https://github.com/RocketChat/Rocket.Chat/pull/17581)) @@ -2139,12 +2150,9 @@ - Notification sounds ([#17616](https://github.com/RocketChat/Rocket.Chat/pull/17616)) - * Global CDN config was ignored when loading the sound files - - * Upload of custom sounds wasn't getting the file extension correctly - - * Some translations were missing - + * Global CDN config was ignored when loading the sound files + * Upload of custom sounds wasn't getting the file extension correctly + * Some translations were missing * Edit and delete of custom sounds were not working correctly - Omnichannel departments are not saved when the offline channel name is not defined ([#17553](https://github.com/RocketChat/Rocket.Chat/pull/17553)) @@ -2432,19 +2440,14 @@ - Better Push and Email Notification logic ([#17357](https://github.com/RocketChat/Rocket.Chat/pull/17357)) - We are still using the same logic to define which notifications every new message will generate, it takes some servers' settings, users's preferences and subscriptions' settings in consideration to determine who will receive each notification type (desktop, audio, email and mobile push), but now it doesn't check the user's status (online, away, offline) for email and mobile push notifications but send those notifications to a new queue with the following rules: - - - - When the user is online the notification is scheduled to be sent in 120 seconds - - - When the user is away the notification is scheduled to be sent in 120 seconds minus the amount of time he is away - - - When the user is offline the notification is scheduled to be sent right away - - - When the user reads a channel all the notifications for that user are removed (clear queue) - - - When a notification is processed to be sent to a user and there are other scheduled notifications: - - All the scheduled notifications for that user are rescheduled to now + We are still using the same logic to define which notifications every new message will generate, it takes some servers' settings, users's preferences and subscriptions' settings in consideration to determine who will receive each notification type (desktop, audio, email and mobile push), but now it doesn't check the user's status (online, away, offline) for email and mobile push notifications but send those notifications to a new queue with the following rules: + + - When the user is online the notification is scheduled to be sent in 120 seconds + - When the user is away the notification is scheduled to be sent in 120 seconds minus the amount of time he is away + - When the user is offline the notification is scheduled to be sent right away + - When the user reads a channel all the notifications for that user are removed (clear queue) + - When a notification is processed to be sent to a user and there are other scheduled notifications: + - All the scheduled notifications for that user are rescheduled to now - The current notification goes back to the queue to be processed ordered by creation date - Buttons to check/uncheck all users and channels on import ([#17207](https://github.com/RocketChat/Rocket.Chat/pull/17207)) @@ -2807,7 +2810,7 @@ - Translation via MS translate ([#16363](https://github.com/RocketChat/Rocket.Chat/pull/16363) by [@mrsimpson](https://github.com/mrsimpson)) - Adds Microsoft's translation service (https://translator.microsoft.com/) as a provider for translation of messages. + Adds Microsoft's translation service (https://translator.microsoft.com/) as a provider for translation of messages. In addition to implementing the interface (similar to google and DeepL), a small change has been done in order to display the translation provider on the UI. - Two Factor authentication via email ([#15949](https://github.com/RocketChat/Rocket.Chat/pull/15949)) @@ -14346,4 +14349,4 @@ - [@graywolf336](https://github.com/graywolf336) - [@marceloschmidt](https://github.com/marceloschmidt) - [@rodrigok](https://github.com/rodrigok) -- [@sampaiodiego](https://github.com/sampaiodiego) +- [@sampaiodiego](https://github.com/sampaiodiego) \ No newline at end of file diff --git a/app/api/server/v1/users.js b/app/api/server/v1/users.js index b182c3633050..4a3601a125d0 100644 --- a/app/api/server/v1/users.js +++ b/app/api/server/v1/users.js @@ -717,7 +717,8 @@ API.v1.addRoute('users.2fa.sendEmailCode', { const userId = this.userId || Users[method](emailOrUsername, { fields: { _id: 1 } })?._id; if (!userId) { - throw new Meteor.Error('error-invalid-user', 'Invalid user'); + this.logger.error('[2fa] User was not found when requesting 2fa email code'); + return API.v1.success(); } emailCheck.sendEmailCode(getUserForCheck(userId)); diff --git a/app/authorization/server/functions/hasRole.js b/app/authorization/server/functions/hasRole.js index e5d8927cbb74..545adc3f737b 100644 --- a/app/authorization/server/functions/hasRole.js +++ b/app/authorization/server/functions/hasRole.js @@ -1,7 +1,10 @@ import { Roles } from '../../../models/server/raw'; export const hasRoleAsync = async (userId, roleNames, scope) => { - roleNames = [].concat(roleNames); + if (!userId || userId === '') { + return false; + } + return Roles.isUserInRoles(userId, roleNames, scope); }; diff --git a/app/emoji-custom/server/methods/insertOrUpdateEmoji.js b/app/emoji-custom/server/methods/insertOrUpdateEmoji.js index 72a0a6a0694f..e635265e1f02 100644 --- a/app/emoji-custom/server/methods/insertOrUpdateEmoji.js +++ b/app/emoji-custom/server/methods/insertOrUpdateEmoji.js @@ -45,6 +45,8 @@ Meteor.methods({ emojiData.aliases = []; } + emojiData.extension = emojiData.extension === 'svg+xml' ? 'png' : emojiData.extension; + let matchingResults = []; if (emojiData._id) { diff --git a/app/emoji-custom/server/methods/uploadEmojiCustom.js b/app/emoji-custom/server/methods/uploadEmojiCustom.js index 1f3d4cf4d1c4..685d4f0270ae 100644 --- a/app/emoji-custom/server/methods/uploadEmojiCustom.js +++ b/app/emoji-custom/server/methods/uploadEmojiCustom.js @@ -1,13 +1,24 @@ import { Meteor } from 'meteor/meteor'; import limax from 'limax'; +import sharp from 'sharp'; import { hasPermission } from '../../../authorization'; import { RocketChatFile } from '../../../file'; import { RocketChatFileEmojiCustomInstance } from '../startup/emoji-custom'; import { api } from '../../../../server/sdk/api'; +const getFile = async (file, extension) => { + if (extension !== 'svg+xml') { + return file; + } + + return sharp(file) + .png() + .toBuffer(); +}; + Meteor.methods({ - uploadEmojiCustom(binaryContent, contentType, emojiData) { + async uploadEmojiCustom(binaryContent, contentType, emojiData) { if (!hasPermission(this.userId, 'manage-emoji')) { throw new Meteor.Error('not_authorized'); } @@ -15,7 +26,10 @@ Meteor.methods({ emojiData.name = limax(emojiData.name, { replacement: '_' }); // delete aliases for notification purposes. here, it is a string rather than an array delete emojiData.aliases; - const file = new Buffer(binaryContent, 'binary'); + + const file = await getFile(Buffer.from(binaryContent, 'binary'), emojiData.extension); + + emojiData.extension = emojiData.extension === 'svg+xml' ? 'png' : emojiData.extension; const rs = RocketChatFile.bufferToStream(file); RocketChatFileEmojiCustomInstance.deleteFile(encodeURIComponent(`${ emojiData.name }.${ emojiData.extension }`)); diff --git a/app/lib/server/functions/setUserAvatar.js b/app/lib/server/functions/setUserAvatar.js index 7229d5a294e4..bae4c45809af 100644 --- a/app/lib/server/functions/setUserAvatar.js +++ b/app/lib/server/functions/setUserAvatar.js @@ -18,13 +18,13 @@ export const setUserAvatar = function(user, dataURI, contentType, service) { try { result = HTTP.get(dataURI, { npmRequestOptions: { encoding: 'binary', rejectUnauthorized: false } }); if (!result) { - console.log(`Not a valid response, from the avatar url: ${ dataURI }`); - throw new Meteor.Error('error-avatar-invalid-url', `Invalid avatar URL: ${ dataURI }`, { function: 'setUserAvatar', url: dataURI }); + console.log(`Not a valid response, from the avatar url: ${ encodeURI(dataURI) }`); + throw new Meteor.Error('error-avatar-invalid-url', `Invalid avatar URL: ${ encodeURI(dataURI) }`, { function: 'setUserAvatar', url: dataURI }); } } catch (error) { if (!error.response || error.response.statusCode !== 404) { - console.log(`Error while handling the setting of the avatar from a url (${ dataURI }) for ${ user.username }:`, error); - throw new Meteor.Error('error-avatar-url-handling', `Error while handling avatar setting from a URL (${ dataURI }) for ${ user.username }`, { function: 'RocketChat.setUserAvatar', url: dataURI, username: user.username }); + console.log(`Error while handling the setting of the avatar from a url (${ encodeURI(dataURI) }) for ${ user.username }:`, error); + throw new Meteor.Error('error-avatar-url-handling', `Error while handling avatar setting from a URL (${ encodeURI(dataURI) }) for ${ user.username }`, { function: 'RocketChat.setUserAvatar', url: dataURI, username: user.username }); } } diff --git a/app/meteor-accounts-saml/server/lib/SAML.ts b/app/meteor-accounts-saml/server/lib/SAML.ts index b17bb3d32611..6a26567ca683 100644 --- a/app/meteor-accounts-saml/server/lib/SAML.ts +++ b/app/meteor-accounts-saml/server/lib/SAML.ts @@ -48,7 +48,7 @@ export class SAML { case 'authorize': return this.processAuthorizeAction(res, service, samlObject); case 'validate': - return this.processValidateAction(req, res, service, samlObject); + return this.processValidateAction(req, res, service); default: throw new Error(`Unexpected SAML action ${ samlObject.actionName }`); } @@ -373,7 +373,7 @@ export class SAML { }); } - private static processValidateAction(req: IIncomingMessage, res: ServerResponse, service: IServiceProviderOptions, samlObject: ISAMLAction): void { + private static processValidateAction(req: IIncomingMessage, res: ServerResponse, service: IServiceProviderOptions): void { const serviceProvider = new SAMLServiceProvider(service); SAMLUtils.relayState = req.body.RelayState; serviceProvider.validateResponse(req.body.SAMLResponse, (err, profile/* , loggedOut*/) => { @@ -387,21 +387,15 @@ export class SAML { throw new Error('No user data collected from IdP response.'); } - let credentialToken = (profile.inResponseToId && profile.inResponseToId.value) || profile.inResponseToId || profile.InResponseTo || samlObject.credentialToken; + // create a random token to store the login result + // to test an IdP initiated login on localhost, use the following URL (assuming SimpleSAMLPHP on localhost:8080): + // http://localhost:8080/simplesaml/saml2/idp/SSOService.php?spentityid=http://localhost:3000/_saml/metadata/test-sp + const credentialToken = Random.id(); + const loginResult = { profile, }; - if (!credentialToken) { - // If the login was initiated by the IDP, then we don't have a credentialToken as there was no AuthorizeRequest on our side - // so we create a random token now to use the same url to end the login - // - // to test an IdP initiated login on localhost, use the following URL (assuming SimpleSAMLPHP on localhost:8080): - // http://localhost:8080/simplesaml/saml2/idp/SSOService.php?spentityid=http://localhost:3000/_saml/metadata/test-sp - credentialToken = Random.id(); - SAMLUtils.log('[SAML] Using random credentialToken: ', credentialToken); - } - this.storeCredential(credentialToken, loginResult); const url = `${ Meteor.absoluteUrl('home') }?saml_idp_credentialToken=${ credentialToken }`; res.writeHead(302, { diff --git a/app/meteor-accounts-saml/server/loginHandler.ts b/app/meteor-accounts-saml/server/loginHandler.ts index 0dcec76d04c3..84beec3091aa 100644 --- a/app/meteor-accounts-saml/server/loginHandler.ts +++ b/app/meteor-accounts-saml/server/loginHandler.ts @@ -11,7 +11,7 @@ const makeError = (message: string): Record => ({ }); Accounts.registerLoginHandler('saml', function(loginRequest) { - if (!loginRequest.saml || !loginRequest.credentialToken) { + if (!loginRequest.saml || !loginRequest.credentialToken || typeof loginRequest.credentialToken !== 'string') { return undefined; } diff --git a/app/models/server/raw/Roles.js b/app/models/server/raw/Roles.js index 523aa968057d..de771bcad9b0 100644 --- a/app/models/server/raw/Roles.js +++ b/app/models/server/raw/Roles.js @@ -8,13 +8,15 @@ export class RolesRaw extends BaseRaw { } async isUserInRoles(userId, roles, scope) { - roles = [].concat(roles); + if (!Array.isArray(roles)) { + roles = [roles]; + } for (let i = 0, total = roles.length; i < total; i++) { const roleName = roles[i]; // eslint-disable-next-line no-await-in-loop - const role = await this.findOne({ _id: roleName }); + const role = await this.findOne({ _id: roleName }, { scope: 1 }); const roleScope = (role && role.scope) || 'Users'; const model = this.models[roleScope]; diff --git a/app/utils/rocketchat.info b/app/utils/rocketchat.info index ff9110393bf7..5702658314c2 100644 --- a/app/utils/rocketchat.info +++ b/app/utils/rocketchat.info @@ -1,3 +1,3 @@ { - "version": "3.8.8" + "version": "3.8.9" } diff --git a/package-lock.json b/package-lock.json index 540d86c9c0ca..db13ef3ab824 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "Rocket.Chat", - "version": "3.8.8", + "version": "3.8.9", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index e0aa61b612a8..e0c36a894005 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "Rocket.Chat", "description": "The Ultimate Open Source WebChat Platform", - "version": "3.8.8", + "version": "3.8.9", "author": { "name": "Rocket.Chat", "url": "https://rocket.chat/" diff --git a/server/methods/addAllUserToRoom.js b/server/methods/addAllUserToRoom.js index d8379b2030c7..83dffa5abc9e 100644 --- a/server/methods/addAllUserToRoom.js +++ b/server/methods/addAllUserToRoom.js @@ -11,52 +11,54 @@ Meteor.methods({ check(rid, String); check(activeUsersOnly, Boolean); - if (hasRole(this.userId, 'admin') === true) { - const userCount = Users.find().count(); - if (userCount > settings.get('API_User_Limit')) { - throw new Meteor.Error('error-user-limit-exceeded', 'User Limit Exceeded', { - method: 'addAllToRoom', - }); - } + if (!hasRole(this.userId, 'admin')) { + throw new Meteor.Error(403, 'Access to Method Forbidden', { + method: 'addAllToRoom', + }); + } - const room = Rooms.findOneById(rid); - if (room == null) { - throw new Meteor.Error('error-invalid-room', 'Invalid room', { - method: 'addAllToRoom', - }); - } + const userFilter = {}; + if (activeUsersOnly === true) { + userFilter.active = true; + } - const userFilter = {}; - if (activeUsersOnly === true) { - userFilter.active = true; - } + const userCursor = Users.find(userFilter); + const usersCount = userCursor.count(); + if (usersCount > settings.get('API_User_Limit')) { + throw new Meteor.Error('error-user-limit-exceeded', 'User Limit Exceeded', { + method: 'addAllToRoom', + }); + } - const users = Users.find(userFilter).fetch(); - const now = new Date(); - users.forEach(function(user) { - const subscription = Subscriptions.findOneByRoomIdAndUserId(rid, user._id); - if (subscription != null) { - return; - } - callbacks.run('beforeJoinRoom', user, room); - Subscriptions.createWithRoomAndUser(room, user, { - ts: now, - open: true, - alert: true, - unread: 1, - userMentions: 1, - groupMentions: 0, - }); - Messages.createUserJoinWithRoomIdAndUser(rid, user, { - ts: now, - }); - Meteor.defer(function() {}); - return callbacks.run('afterJoinRoom', user, room); + const room = Rooms.findOneById(rid); + if (!room) { + throw new Meteor.Error('error-invalid-room', 'Invalid room', { + method: 'addAllToRoom', }); - return true; } - throw new Meteor.Error(403, 'Access to Method Forbidden', { - method: 'addAllToRoom', + + const users = userCursor.fetch(); + const now = new Date(); + users.forEach(function(user) { + const subscription = Subscriptions.findOneByRoomIdAndUserId(rid, user._id); + if (subscription != null) { + return; + } + callbacks.run('beforeJoinRoom', user, room); + Subscriptions.createWithRoomAndUser(room, user, { + ts: now, + open: true, + alert: true, + unread: 1, + userMentions: 1, + groupMentions: 0, + }); + Messages.createUserJoinWithRoomIdAndUser(rid, user, { + ts: now, + }); + Meteor.defer(function() {}); + return callbacks.run('afterJoinRoom', user, room); }); + return true; }, }); From 3eaafd56f5e27363b4b0f9cff8ab82c8b90507d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20J=C3=A4gle?= Date: Tue, 30 Mar 2021 08:08:10 +0200 Subject: [PATCH 2/2] Fix Github CI (downport from 3.12) --- .github/workflows/build_and_test.yml | 79 +++++++++++++--------------- 1 file changed, 36 insertions(+), 43 deletions(-) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index c91621dbc0e9..8bb1d069b23a 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -31,7 +31,7 @@ jobs: cat $GITHUB_EVENT_PATH - name: Use Node.js 12.18.4 - uses: actions/setup-node@v1 + uses: actions/setup-node@v2 with: node-version: "12.18.4" @@ -51,7 +51,7 @@ jobs: - name: Cache cypress id: cache-cypress - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: /home/runner/.cache/Cypress key: ${{ runner.OS }}-cache-cypress-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('.github/workflows/build_and_test.yml') }} @@ -59,19 +59,19 @@ jobs: - name: Cache node modules if: steps.cache-cypress.outputs.cache-hit == 'true' id: cache-nodemodules - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: node_modules key: ${{ runner.OS }}-node_modules-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('.github/workflows/build_and_test.yml') }} - name: Cache meteor local - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ./.meteor/local key: ${{ runner.OS }}-meteor_cache-${{ hashFiles('.meteor/versions') }}-${{ hashFiles('.github/workflows/build_and_test.yml') }} - name: Cache meteor - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ~/.meteor key: ${{ runner.OS }}-meteor-${{ hashFiles('.meteor/release') }}-${{ hashFiles('.github/workflows/build_and_test.yml') }} @@ -122,6 +122,12 @@ jobs: - run: meteor npm run typecheck + - name: Build Storybook to sanity check components + run: npm run build-storybook ; rm -rf ./storybook-static + env: + NODE_OPTIONS: --max_old_space_size=8192 + + # To reduce memory need during actual build, build the packages solely first # - name: Build a Meteor cache # run: | @@ -137,6 +143,13 @@ jobs: run: | meteor reset + - name: Try building micro services + run: | + cd ./ee/server/services + npm i + npm run build + rm -rf dist/ + - name: Build Rocket.Chat From Pull Request if: startsWith(github.ref, 'refs/pull/') == true env: @@ -160,13 +173,13 @@ jobs: tar czf Rocket.Chat.test.tar.gz ./build-test - name: Store build for tests - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v2 with: name: build-test path: /tmp/Rocket.Chat.test.tar.gz - name: Store build - uses: actions/upload-artifact@v1 + uses: actions/upload-artifact@v2 with: name: build path: /tmp/build @@ -187,7 +200,7 @@ jobs: mongoDBVersion: ${{ matrix.mongodb-version }} --noprealloc --smallfiles --replSet=rs0 - name: Restore build for tests - uses: actions/download-artifact@v1 + uses: actions/download-artifact@v2 with: name: build-test path: /tmp @@ -199,7 +212,7 @@ jobs: cd - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 + uses: actions/setup-node@v2 with: node-version: ${{ matrix.node-version }} @@ -216,7 +229,7 @@ jobs: - name: Cache cypress id: cache-cypress - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: /home/runner/.cache/Cypress key: ${{ runner.OS }}-cache-cypress-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('.github/workflows/build_and_test.yml') }} @@ -224,7 +237,7 @@ jobs: - name: Cache node modules if: steps.cache-cypress.outputs.cache-hit == 'true' id: cache-nodemodules - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: node_modules key: ${{ runner.OS }}-build-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('.github/workflows/build_and_test.yml') }} @@ -282,25 +295,25 @@ jobs: - name: Cache node modules id: cache-nodemodules - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: node_modules key: ${{ runner.OS }}-node_modules-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('.github/workflows/build_and_test.yml') }} - name: Cache meteor local - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ./.meteor/local key: ${{ runner.OS }}-meteor_cache-${{ hashFiles('.meteor/versions') }}-${{ hashFiles('.github/workflows/build_and_test.yml') }} - name: Cache meteor - uses: actions/cache@v1 + uses: actions/cache@v2 with: path: ~/.meteor key: ${{ runner.OS }}-meteor-${{ hashFiles('.meteor/release') }}-${{ hashFiles('.github/workflows/build_and_test.yml') }} - name: Use Node.js 12.18.4 - uses: actions/setup-node@v1 + uses: actions/setup-node@v2 with: node-version: "12.18.4" @@ -331,7 +344,6 @@ jobs: meteor npm --versions meteor node -v git version - echo $GITHUB_REF - name: npm install if: steps.cache-nodemodules.outputs.cache-hit != 'true' @@ -363,26 +375,7 @@ jobs: docker login -u "${DOCKER_USER}" -p "${DOCKER_PASS}" - - name: Publish assets - env: - AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - AWS_DEFAULT_REGION: 'us-east-1' - GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }} - REDHAT_REGISTRY_PID: ${{ secrets.REDHAT_REGISTRY_PID }} - REDHAT_REGISTRY_KEY: ${{ secrets.REDHAT_REGISTRY_KEY }} - UPDATE_TOKEN: ${{ secrets.UPDATE_TOKEN }} - run: | - if [[ '${{ github.event_name }}' = 'release' ]]; then - export CIRCLE_TAG="${GITHUB_REF#*tags/}" - export CIRCLE_BRANCH="" - else - export CIRCLE_TAG="" - export CIRCLE_BRANCH="${GITHUB_REF#*heads/}" - fi; - - export CIRCLE_SHA1=$GITHUB_SHA - export CIRCLE_BUILD_NUM=$GITHUB_SHA + cp $GITHUB_WORKSPACE/.docker/Dockerfile . export LOWERCASE_REPOSITORY=$(echo "$GITHUB_REPOSITORY" | tr "[:upper:]" "[:lower:]") @@ -414,7 +407,7 @@ jobs: password: ${{ secrets.DOCKER_PASS }} - name: Restore build - uses: actions/download-artifact@v1 + uses: actions/download-artifact@v2 with: name: build path: /tmp/build @@ -440,22 +433,22 @@ jobs: if: github.event_name == 'release' run: | cd /tmp/build - CIRCLE_TAG="${GITHUB_REF#*tags/}" + GIT_TAG="${GITHUB_REF#*tags/}" if [[ '${{ matrix.release }}' = 'preview' ]]; then IMAGE="${IMAGE}.preview" fi; - docker build -t ${IMAGE}:$CIRCLE_TAG . - docker push ${IMAGE}:$CIRCLE_TAG + docker build -t ${IMAGE}:$GIT_TAG . + docker push ${IMAGE}:$GIT_TAG - if echo "$CIRCLE_TAG" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' ; then + if echo "$GIT_TAG" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' ; then RELEASE="latest" - elif echo "$CIRCLE_TAG" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$' ; then + elif echo "$GIT_TAG" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$' ; then RELEASE="release-candidate" fi - docker tag ${IMAGE}:$CIRCLE_TAG ${IMAGE}:${RELEASE} + docker tag ${IMAGE}:$GIT_TAG ${IMAGE}:${RELEASE} docker push ${IMAGE}:${RELEASE} - name: Build Docker image for develop