diff --git a/apps/meteor/CHANGELOG.md b/apps/meteor/CHANGELOG.md index a3458db7863b..75ffb7f02d7a 100644 --- a/apps/meteor/CHANGELOG.md +++ b/apps/meteor/CHANGELOG.md @@ -1,5 +1,47 @@ # @rocket.chat/meteor +## 6.10.1 + +### Patch Changes + +- Bump @rocket.chat/meteor version. + +- Bump @rocket.chat/meteor version. + +- ([#32819](https://github.com/RocketChat/Rocket.Chat/pull/32819) by [@dionisio-bot](https://github.com/dionisio-bot)) Fixed issue with livechat agents not being able to leave omnichannel rooms if joining after a room has been closed by the visitor (due to race conditions) + +- ([#32894](https://github.com/RocketChat/Rocket.Chat/pull/32894)) Security Hotfix (https://docs.rocket.chat/docs/security-fixes-and-updates) + +- ([#32829](https://github.com/RocketChat/Rocket.Chat/pull/32829) by [@dionisio-bot](https://github.com/dionisio-bot)) Fixes an issue not displaying all groups in settings list + +- ([#32836](https://github.com/RocketChat/Rocket.Chat/pull/32836) by [@dionisio-bot](https://github.com/dionisio-bot)) Security Hotfix (https://docs.rocket.chat/guides/security/security-updates) + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.10.1 + - @rocket.chat/rest-typings@6.10.1 + - @rocket.chat/api-client@0.2.1 + - @rocket.chat/license@0.2.1 + - @rocket.chat/omnichannel-services@0.2.1 + - @rocket.chat/pdf-worker@0.1.1 + - @rocket.chat/presence@0.2.1 + - @rocket.chat/apps@0.1.1 + - @rocket.chat/core-services@0.4.1 + - @rocket.chat/cron@0.1.1 + - @rocket.chat/fuselage-ui-kit@8.0.1 + - @rocket.chat/gazzodown@8.0.1 + - @rocket.chat/model-typings@0.5.1 + - @rocket.chat/ui-contexts@8.0.1 + - @rocket.chat/server-cloud-communication@0.0.2 + - @rocket.chat/models@0.1.1 + - @rocket.chat/ui-theming@0.2.0 + - @rocket.chat/ui-avatar@4.0.1 + - @rocket.chat/ui-client@8.0.1 + - @rocket.chat/ui-video-conf@8.0.1 + - @rocket.chat/web-ui-registration@8.0.1 + - @rocket.chat/instance-status@0.1.1 +
+ ## 6.10.0 ### Minor Changes diff --git a/apps/meteor/app/2fa/server/methods/enable.ts b/apps/meteor/app/2fa/server/methods/enable.ts index 3b9f35dfcd9d..6b786c0743e9 100644 --- a/apps/meteor/app/2fa/server/methods/enable.ts +++ b/apps/meteor/app/2fa/server/methods/enable.ts @@ -34,6 +34,10 @@ Meteor.methods({ }); } + if (user.services?.totp?.enabled) { + throw new Meteor.Error('error-2fa-already-enabled'); + } + const secret = TOTP.generateSecret(); await Users.disable2FAAndSetTempSecretByUserId(userId, secret.base32); diff --git a/apps/meteor/app/api/server/v1/chat.ts b/apps/meteor/app/api/server/v1/chat.ts index c482e3bb784d..3ccc9caeafa0 100644 --- a/apps/meteor/app/api/server/v1/chat.ts +++ b/apps/meteor/app/api/server/v1/chat.ts @@ -18,6 +18,7 @@ import { executeUpdateMessage } from '../../../lib/server/methods/updateMessage' import { OEmbed } from '../../../oembed/server/server'; import { executeSetReaction } from '../../../reactions/server/setReaction'; import { settings } from '../../../settings/server'; +import { MessageTypes } from '../../../ui-utils/server'; import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser'; import { API } from '../api'; import { getPaginationItems } from '../helpers/getPaginationItems'; @@ -217,6 +218,10 @@ API.v1.addRoute( throw new Meteor.Error('error-invalid-params', 'The "message" parameter must be provided.'); } + if (MessageTypes.isSystemMessage(this.bodyParams.message)) { + throw new Error("Cannot send system messages using 'chat.sendMessage'"); + } + const sent = await executeSendMessage(this.userId, this.bodyParams.message as Pick, this.bodyParams.previewUrls); const [message] = await normalizeMessagesForUser([sent], this.userId); diff --git a/apps/meteor/app/api/server/v1/users.ts b/apps/meteor/app/api/server/v1/users.ts index 041ef0410df0..26ef2fa30ff2 100644 --- a/apps/meteor/app/api/server/v1/users.ts +++ b/apps/meteor/app/api/server/v1/users.ts @@ -44,6 +44,7 @@ import { setStatusText } from '../../../lib/server/functions/setStatusText'; import { setUserAvatar } from '../../../lib/server/functions/setUserAvatar'; import { setUsernameWithValidation } from '../../../lib/server/functions/setUsername'; import { validateCustomFields } from '../../../lib/server/functions/validateCustomFields'; +import { validateNameChars } from '../../../lib/server/functions/validateNameChars'; import { notifyOnUserChange, notifyOnUserChangeAsync } from '../../../lib/server/lib/notifyListener'; import { generateAccessToken } from '../../../lib/server/methods/createToken'; import { settings } from '../../../settings/server'; @@ -95,6 +96,10 @@ API.v1.addRoute( async post() { const userData = { _id: this.bodyParams.userId, ...this.bodyParams.data }; + if (userData.name && !validateNameChars(userData.name)) { + return API.v1.failure('Name contains invalid characters'); + } + await saveUser(this.userId, userData); if (this.bodyParams.data.customFields) { @@ -139,6 +144,10 @@ API.v1.addRoute( typedPassword: this.bodyParams.data.currentPassword, }; + if (userData.realname && !validateNameChars(userData.realname)) { + return API.v1.failure('Name contains invalid characters'); + } + // saveUserProfile now uses the default two factor authentication procedures, so we need to provide that const twoFactorOptions = !userData.typedPassword ? null @@ -281,6 +290,10 @@ API.v1.addRoute( this.bodyParams.joinDefaultChannels = true; } + if (this.bodyParams.name && !validateNameChars(this.bodyParams.name)) { + return API.v1.failure('Name contains invalid characters'); + } + if (this.bodyParams.customFields) { validateCustomFields(this.bodyParams.customFields); } @@ -628,16 +641,20 @@ API.v1.addRoute( }, { async post() { + const { secret: secretURL, ...params } = this.bodyParams; + if (this.userId) { return API.v1.failure('Logged in users can not register again.'); } + if (params.name && !validateNameChars(params.name)) { + return API.v1.failure('Name contains invalid characters'); + } + if (!(await checkUsernameAvailability(this.bodyParams.username))) { return API.v1.failure('Username is already in use'); } - const { secret: secretURL, ...params } = this.bodyParams; - if (this.bodyParams.customFields) { try { await validateCustomFields(this.bodyParams.customFields); diff --git a/apps/meteor/app/lib/server/functions/checkUrlForSsrf.ts b/apps/meteor/app/lib/server/functions/checkUrlForSsrf.ts new file mode 100644 index 000000000000..c90065d7ad8f --- /dev/null +++ b/apps/meteor/app/lib/server/functions/checkUrlForSsrf.ts @@ -0,0 +1,100 @@ +import { lookup } from 'dns'; + +// https://en.wikipedia.org/wiki/Reserved_IP_addresses + Alibaba Metadata IP +const ranges: string[] = [ + '0.0.0.0/8', + '10.0.0.0/8', + '100.64.0.0/10', + '127.0.0.0/8', + '169.254.0.0/16', + '172.16.0.0/12', + '192.0.0.0/24', + '192.0.2.0/24', + '192.88.99.0/24', + '192.168.0.0/16', + '198.18.0.0/15', + '198.51.100.0/24', + '203.0.113.0/24', + '224.0.0.0/4', + '240.0.0.0/4', + '255.255.255.255', + '100.100.100.200/32', +]; + +export const nslookup = async (hostname: string): Promise => { + return new Promise((resolve, reject) => { + lookup(hostname, (error, address) => { + if (error) { + reject(error); + } else { + resolve(address); + } + }); + }); +}; + +export const ipToLong = (ip: string): number => { + return ip.split('.').reduce((acc, octet) => (acc << 8) + parseInt(octet, 10), 0) >>> 0; +}; + +export const isIpInRange = (ip: string, range: string): boolean => { + const [rangeIp, subnet] = range.split('/'); + const ipLong = ipToLong(ip); + const rangeIpLong = ipToLong(rangeIp); + const mask = ~(2 ** (32 - Number(subnet)) - 1); + return (ipLong & mask) === (rangeIpLong & mask); +}; + +export const isIpInAnyRange = (ip: string): boolean => ranges.some((range) => isIpInRange(ip, range)); + +export const isValidIPv4 = (ip: string): boolean => { + const octets = ip.split('.'); + if (octets.length !== 4) return false; + return octets.every((octet) => { + const num = Number(octet); + return num >= 0 && num <= 255 && octet === num.toString(); + }); +}; + +export const isValidDomain = (domain: string): boolean => { + const domainPattern = /^(?!-)(?!.*--)[A-Za-z0-9-]{1,63}(? => { + if (!(url.startsWith('http://') || url.startsWith('https://'))) { + return false; + } + + const [, address] = url.split('://'); + const ipOrDomain = address.includes('/') ? address.split('/')[0] : address; + + if (!(isValidIPv4(ipOrDomain) || isValidDomain(ipOrDomain))) { + return false; + } + + if (isValidIPv4(ipOrDomain) && isIpInAnyRange(ipOrDomain)) { + return false; + } + + if (isValidDomain(ipOrDomain) && /metadata.google.internal/.test(ipOrDomain.toLowerCase())) { + return false; + } + + if (isValidDomain(ipOrDomain)) { + try { + const ipAddress = await nslookup(ipOrDomain); + if (isIpInAnyRange(ipAddress)) { + return false; + } + } catch (error) { + console.log(error); + return false; + } + } + + return true; +}; diff --git a/apps/meteor/app/lib/server/functions/saveUser.js b/apps/meteor/app/lib/server/functions/saveUser.js index 1931333038b6..ef6a7e9fe7bd 100644 --- a/apps/meteor/app/lib/server/functions/saveUser.js +++ b/apps/meteor/app/lib/server/functions/saveUser.js @@ -69,6 +69,13 @@ async function _sendUserEmail(subject, html, userData) { async function validateUserData(userId, userData) { const existingRoles = _.pluck(await getRoles(), '_id'); + if (userData.verified && userData._id && userId === userData._id) { + throw new Meteor.Error('error-action-not-allowed', 'Editing email verification is not allowed', { + method: 'insertOrUpdateUser', + action: 'Editing_user', + }); + } + if (userData._id && userId !== userData._id && !(await hasPermissionAsync(userId, 'edit-other-user-info'))) { throw new Meteor.Error('error-action-not-allowed', 'Editing user is not allowed', { method: 'insertOrUpdateUser', diff --git a/apps/meteor/app/lib/server/functions/setUserAvatar.ts b/apps/meteor/app/lib/server/functions/setUserAvatar.ts index b46f0ff8cd50..13ccd2de6954 100644 --- a/apps/meteor/app/lib/server/functions/setUserAvatar.ts +++ b/apps/meteor/app/lib/server/functions/setUserAvatar.ts @@ -10,6 +10,7 @@ import { hasPermissionAsync } from '../../../authorization/server/functions/hasP import { FileUpload } from '../../../file-upload/server'; import { RocketChatFile } from '../../../file/server'; import { settings } from '../../../settings/server'; +import { checkUrlForSsrf } from './checkUrlForSsrf'; export const setAvatarFromServiceWithValidation = async ( userId: string, @@ -88,8 +89,17 @@ export async function setUserAvatar( const { buffer, type } = await (async (): Promise<{ buffer: Buffer; type: string }> => { if (service === 'url' && typeof dataURI === 'string') { let response: Response; + + const isSsrfSafe = await checkUrlForSsrf(dataURI); + if (!isSsrfSafe) { + throw new Meteor.Error('error-avatar-invalid-url', `Invalid avatar URL: ${encodeURI(dataURI)}`, { + function: 'setUserAvatar', + url: dataURI, + }); + } + try { - response = await fetch(dataURI); + response = await fetch(dataURI, { redirect: 'error' }); } catch (e) { SystemLogger.info(`Not a valid response, from the avatar url: ${encodeURI(dataURI)}`); throw new Meteor.Error('error-avatar-invalid-url', `Invalid avatar URL: ${encodeURI(dataURI)}`, { diff --git a/apps/meteor/app/lib/server/functions/validateNameChars.ts b/apps/meteor/app/lib/server/functions/validateNameChars.ts new file mode 100644 index 000000000000..07330c66b762 --- /dev/null +++ b/apps/meteor/app/lib/server/functions/validateNameChars.ts @@ -0,0 +1,21 @@ +export const validateNameChars = (name: string | undefined): boolean => { + if (typeof name !== 'string') { + return false; + } + + const invalidChars = /[<>\\/]/; + if (invalidChars.test(name)) { + return false; + } + + try { + const decodedName = decodeURI(name); + if (invalidChars.test(decodedName)) { + return false; + } + } catch (err) { + return false; + } + + return true; +}; diff --git a/apps/meteor/app/lib/server/methods/sendMessage.ts b/apps/meteor/app/lib/server/methods/sendMessage.ts index a490b5c4c67f..a61ab499ce87 100644 --- a/apps/meteor/app/lib/server/methods/sendMessage.ts +++ b/apps/meteor/app/lib/server/methods/sendMessage.ts @@ -12,6 +12,7 @@ import { canSendMessageAsync } from '../../../authorization/server/functions/can import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission'; import { metrics } from '../../../metrics/server'; import { settings } from '../../../settings/server'; +import { MessageTypes } from '../../../ui-utils/server'; import { sendMessage } from '../functions/sendMessage'; import { RateLimiter } from '../lib'; @@ -78,6 +79,8 @@ export async function executeSendMessage(uid: IUser['_id'], message: AtLeast({ }); } + if (MessageTypes.isSystemMessage(message)) { + throw new Error("Cannot send system messages using 'sendMessage'"); + } + try { return await executeSendMessage(uid, message, previewUrls); } catch (error: any) { diff --git a/apps/meteor/app/livechat/imports/server/rest/sms.ts b/apps/meteor/app/livechat/imports/server/rest/sms.ts index b6669b5f0d89..6f8ce64bc635 100644 --- a/apps/meteor/app/livechat/imports/server/rest/sms.ts +++ b/apps/meteor/app/livechat/imports/server/rest/sms.ts @@ -17,6 +17,7 @@ import { Meteor } from 'meteor/meteor'; import { getFileExtension } from '../../../../../lib/utils/getFileExtension'; import { API } from '../../../../api/server'; import { FileUpload } from '../../../../file-upload/server'; +import { checkUrlForSsrf } from '../../../../lib/server/functions/checkUrlForSsrf'; import { settings } from '../../../../settings/server'; import type { ILivechatMessage } from '../../../server/lib/LivechatTyped'; import { Livechat as LivechatTyped } from '../../../server/lib/LivechatTyped'; @@ -24,7 +25,12 @@ import { Livechat as LivechatTyped } from '../../../server/lib/LivechatTyped'; const logger = new Logger('SMS'); const getUploadFile = async (details: Omit, fileUrl: string) => { - const response = await fetch(fileUrl); + const isSsrfSafe = await checkUrlForSsrf(fileUrl); + if (!isSsrfSafe) { + throw new Meteor.Error('error-invalid-url', 'Invalid URL'); + } + + const response = await fetch(fileUrl, { redirect: 'error' }); const content = Buffer.from(await response.arrayBuffer()); diff --git a/apps/meteor/ee/server/services/CHANGELOG.md b/apps/meteor/ee/server/services/CHANGELOG.md index 5061db00d075..f53b5ae10ee6 100644 --- a/apps/meteor/ee/server/services/CHANGELOG.md +++ b/apps/meteor/ee/server/services/CHANGELOG.md @@ -1,5 +1,18 @@ # rocketchat-services +## 1.2.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.10.1 + - @rocket.chat/rest-typings@6.10.1 + - @rocket.chat/core-services@0.4.1 + - @rocket.chat/model-typings@0.5.1 + - @rocket.chat/models@0.1.1 +
+ ## 1.2.0 ### Minor Changes diff --git a/apps/meteor/ee/server/services/package.json b/apps/meteor/ee/server/services/package.json index b36f89a01c3e..4c987885c9c0 100644 --- a/apps/meteor/ee/server/services/package.json +++ b/apps/meteor/ee/server/services/package.json @@ -1,7 +1,7 @@ { "name": "rocketchat-services", "private": true, - "version": "1.2.0", + "version": "1.2.1", "description": "Rocket.Chat Authorization service", "main": "index.js", "scripts": { diff --git a/apps/meteor/server/routes/avatar/room.js b/apps/meteor/server/routes/avatar/room.js index c47e58b48d0b..3482253d57d8 100644 --- a/apps/meteor/server/routes/avatar/room.js +++ b/apps/meteor/server/routes/avatar/room.js @@ -5,6 +5,9 @@ import { FileUpload } from '../../../app/file-upload/server'; import { roomCoordinator } from '../../lib/rooms/roomCoordinator'; import { renderSVGLetters, serveAvatar, wasFallbackModified, setCacheAndDispositionHeaders } from './utils'; +const MAX_ROOM_SVG_AVATAR_SIZE = 1024; +const MIN_ROOM_SVG_AVATAR_SIZE = 16; + const cookie = new Cookies(); const getRoomAvatar = async (roomId) => { const room = await Rooms.findOneById(roomId, { projection: { t: 1, prid: 1, name: 1, fname: 1, federated: 1 } }); @@ -64,7 +67,12 @@ export const roomAvatar = async function (req, res /* , next*/) { return; } - const svg = renderSVGLetters(roomName, req.query.size && parseInt(req.query.size)); + let avatarSize = req.query.size && parseInt(req.query.size); + if (avatarSize) { + avatarSize = Math.min(Math.max(avatarSize, MIN_ROOM_SVG_AVATAR_SIZE), MAX_ROOM_SVG_AVATAR_SIZE); + } + + const svg = renderSVGLetters(roomName, avatarSize); return serveAvatar(svg, req.query.format, res); }; diff --git a/apps/meteor/server/routes/avatar/user.js b/apps/meteor/server/routes/avatar/user.js index 7997a91d95a4..0d86bc4a08cf 100644 --- a/apps/meteor/server/routes/avatar/user.js +++ b/apps/meteor/server/routes/avatar/user.js @@ -4,6 +4,9 @@ import { FileUpload } from '../../../app/file-upload/server'; import { settings } from '../../../app/settings/server'; import { renderSVGLetters, serveAvatar, wasFallbackModified, setCacheAndDispositionHeaders } from './utils'; +const MAX_USER_SVG_AVATAR_SIZE = 1024; +const MIN_USER_SVG_AVATAR_SIZE = 16; + // request /avatar/@name forces returning the svg export const userAvatar = async function (req, res) { const requestUsername = decodeURIComponent(req.url.substr(1).replace(/\?.*$/, '')); @@ -14,7 +17,10 @@ export const userAvatar = async function (req, res) { return; } - const avatarSize = req.query.size && parseInt(req.query.size); + let avatarSize = req.query.size && parseInt(req.query.size); + if (avatarSize) { + avatarSize = Math.min(Math.max(avatarSize, MIN_USER_SVG_AVATAR_SIZE), MAX_USER_SVG_AVATAR_SIZE); + } setCacheAndDispositionHeaders(req, res); diff --git a/apps/meteor/tests/end-to-end/api/chat.ts b/apps/meteor/tests/end-to-end/api/chat.ts index 82a1a68955ed..2b33e15526d4 100644 --- a/apps/meteor/tests/end-to-end/api/chat.ts +++ b/apps/meteor/tests/end-to-end/api/chat.ts @@ -1152,6 +1152,27 @@ describe('[Chat]', () => { .end(done); }); + it('should fail if message is a system message', () => { + const msgId = Random.id(); + return request + .post(api('chat.sendMessage')) + .set(credentials) + .send({ + message: { + _id: msgId, + rid: 'GENERAL', + msg: 'xss', + t: 'subscription-role-added', + role: '

XSS', + }, + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + }); + }); + describe('customFields', () => { async function testMessageSending({ customFields, diff --git a/apps/meteor/tests/end-to-end/api/methods.ts b/apps/meteor/tests/end-to-end/api/methods.ts index d03b83854b28..e1ca05d1fbf2 100644 --- a/apps/meteor/tests/end-to-end/api/methods.ts +++ b/apps/meteor/tests/end-to-end/api/methods.ts @@ -1,5 +1,6 @@ import type { Credentials } from '@rocket.chat/api-client'; import type { IMessage, IRoom, IThreadMessage, IUser } from '@rocket.chat/core-typings'; +import { Random } from '@rocket.chat/random'; import { expect } from 'chai'; import { after, before, beforeEach, describe, it } from 'mocha'; @@ -1979,6 +1980,46 @@ describe('Meteor.methods', () => { }) .end(done); }); + + it('should not send message if it is a system message', async () => { + const msgId = Random.id(); + await request + .post(methodCall('sendMessage')) + .set(credentials) + .send({ + message: JSON.stringify({ + method: 'sendMessage', + params: [ + { + _id: msgId, + rid: 'GENERAL', + msg: 'xss', + t: 'subscription-role-added', + role: '

XSS', + }, + ], + id: 1000, + msg: 'method', + }), + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + const data = JSON.parse(res.body.message); + expect(data).to.not.have.a.property('result').that.is.an('object'); + expect(data).to.have.a.property('error').that.is.an('object'); + }); + await request + .get(api('chat.getMessage')) + .set(credentials) + .query({ msgId }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + }); + }); }); describe('[@updateMessage]', () => { @@ -3180,4 +3221,78 @@ describe('Meteor.methods', () => { }); }); }); + + describe('@insertOrUpdateUser', () => { + let testUser: TestUser; + let testUserCredentials: Credentials; + + before(async () => { + testUser = await createUser(); + testUserCredentials = await login(testUser.username, password); + }); + + after(() => Promise.all([deleteUser(testUser)])); + + it('should fail if user tries to verify their own email via insertOrUpdateUser', (done) => { + void request + .post(methodCall('insertOrUpdateUser')) + .set(testUserCredentials) + .send({ + message: JSON.stringify({ + method: 'insertOrUpdateUser', + params: [ + { + _id: testUserCredentials['X-User-Id'], + email: 'manager@rocket.chat', + verified: true, + }, + ], + id: '52', + msg: 'method', + }), + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.a.property('success', true); + expect(res.body).to.have.a.property('message').that.is.a('string'); + const data = JSON.parse(res.body.message); + expect(data).to.have.a.property('msg', 'result'); + expect(data).to.have.a.property('id', '52'); + expect(data.error).to.have.property('error', 'error-action-not-allowed'); + }) + .end(done); + }); + + it('should pass if a user with the right permissions tries to verify the email of another user', (done) => { + void request + .post(methodCall('insertOrUpdateUser')) + .set(credentials) + .send({ + message: JSON.stringify({ + method: 'insertOrUpdateUser', + params: [ + { + _id: testUserCredentials['X-User-Id'], + email: 'testuser@rocket.chat', + verified: true, + }, + ], + id: '52', + msg: 'method', + }), + }) + .expect('Content-Type', 'application/json') + .expect(200) + .expect((res) => { + expect(res.body).to.have.a.property('success', true); + expect(res.body).to.have.a.property('message').that.is.a('string'); + const data = JSON.parse(res.body.message); + expect(data).to.have.a.property('msg', 'result'); + expect(data).to.have.a.property('id', '52'); + expect(data).to.have.a.property('result', true); + }) + .end(done); + }); + }); }); diff --git a/apps/meteor/tests/end-to-end/api/methods/2fa-enable.ts b/apps/meteor/tests/end-to-end/api/methods/2fa-enable.ts new file mode 100644 index 000000000000..a2bd9dfeb3a7 --- /dev/null +++ b/apps/meteor/tests/end-to-end/api/methods/2fa-enable.ts @@ -0,0 +1,158 @@ +import type { IUser } from '@rocket.chat/core-typings'; +import { Random } from '@rocket.chat/random'; +import { expect } from 'chai'; +import { before, describe, it, after } from 'mocha'; +import speakeasy from 'speakeasy'; + +import { getCredentials, methodCall, request } from '../../../data/api-data'; +import { password } from '../../../data/user'; +import { createUser, deleteUser, login } from '../../../data/users.helper'; + +describe('2fa:enable', function () { + this.retries(0); + let totpSecret: string; + let user1: IUser; + let user2: IUser; + let user3: IUser; + let user1Credentials: { 'X-Auth-Token': string; 'X-User-Id': string }; + let user2Credentials: { 'X-Auth-Token': string; 'X-User-Id': string }; + let user3Credentials: { 'X-Auth-Token': string; 'X-User-Id': string }; + + before((done) => getCredentials(done)); + + before('create user', async () => { + [user1, user2, user3] = await Promise.all([ + createUser({ username: Random.id(), email: `${Random.id()}@example.com`, verified: true }), + createUser({ username: Random.id(), email: `${Random.id()}@example.com}`, verified: true }), + createUser({ username: Random.id(), email: `${Random.id()}@example.com}`, verified: false }), + ]); + [user1Credentials, user2Credentials, user3Credentials] = await Promise.all([ + login(user1.username, password), + login(user2.username, password), + login(user3.username, password), + ]); + }); + + after('remove user', async () => Promise.all([deleteUser(user1), deleteUser(user2), deleteUser(user3)])); + + it('should return error when user is not logged in', async () => { + await request + .post(methodCall('2fa:enable')) + .send({ + message: JSON.stringify({ + msg: 'method', + id: 'id1', + method: '2fa:enable', + params: [], + }), + }) + .expect(401) + .expect((res) => { + expect(res.body).to.have.property('status', 'error'); + }); + }); + + it('should return error when user is not verified', async () => { + await request + .post(methodCall('2fa:enable')) + .set(user3Credentials) + .send({ + message: JSON.stringify({ + msg: 'method', + id: 'id1', + method: '2fa:enable', + params: [], + }), + }) + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('message'); + const result = JSON.parse(res.body.message); + expect(result).to.have.property('error'); + expect(result.error).to.not.have.property('errpr', 'error-invalid-user'); + }); + }); + + it('should return secret and qr code url when 2fa is disabled on user', async () => { + await request + .post(methodCall('2fa:enable')) + .set(user1Credentials) + .send({ + message: JSON.stringify({ + msg: 'method', + id: 'id1', + method: '2fa:enable', + params: [], + }), + }) + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + const parsedBody = JSON.parse(res.body.message); + expect(parsedBody).to.have.property('result'); + expect(parsedBody.result).to.have.property('secret').of.a('string'); + expect(parsedBody.result) + .to.have.property('url') + .of.a('string') + .match(/^otpauth:\/\//); + }); + }); + + it('should enable 2fa on the user', async () => { + const enableResponse = await request + .post(methodCall('2fa:enable')) + .set(user2Credentials) + .send({ + message: JSON.stringify({ + msg: 'method', + id: 'id2', + method: '2fa:enable', + params: [], + }), + }) + .expect(200); + + const enableData = JSON.parse(enableResponse.body.message); + totpSecret = enableData.result.secret; + + await request + .post(methodCall('2fa:validateTempToken')) + .set(user2Credentials) + .send({ + message: JSON.stringify({ + msg: 'method', + id: 'id3', + method: '2fa:validateTempToken', + params: [speakeasy.totp({ secret: totpSecret, encoding: 'base32' })], + }), + }) + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + const parsedBody = JSON.parse(res.body.message); + expect(parsedBody).to.have.property('result'); + expect(parsedBody.result).to.have.property('codes').of.a('array'); + }); + }); + + it('should return error when 2fa is already enabled on the user', async () => { + await request + .post(methodCall('2fa:enable')) + .set(user2Credentials) + .send({ + message: JSON.stringify({ + msg: 'method', + id: 'id4', + method: '2fa:enable', + params: [], + }), + }) + .expect(200) + .expect((res) => { + expect(res.body).to.have.property('success', true); + const parsedBody = JSON.parse(res.body.message); + expect(parsedBody).to.have.property('error'); + expect(parsedBody).to.not.have.property('result'); + }); + }); +}); diff --git a/apps/meteor/tests/end-to-end/api/users.ts b/apps/meteor/tests/end-to-end/api/users.ts index 8a4c89973008..7045126192e9 100644 --- a/apps/meteor/tests/end-to-end/api/users.ts +++ b/apps/meteor/tests/end-to-end/api/users.ts @@ -622,6 +622,23 @@ describe('[Users]', () => { }) .end(done); }); + it("should return an error when registering a user's name with invalid characters: >, <, /, or \\", (done) => { + request + .post(api('users.register')) + .send({ + email, + name: '', + username, + pass: 'test', + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + expect(res.body).to.have.property('error').and.to.be.equal('Name contains invalid characters'); + }) + .end(done); + }); }); describe('[/users.info]', () => { @@ -1325,6 +1342,21 @@ describe('[Users]', () => { }); }); }); + it('should prevent users from passing server-side request forgery (SSRF) payloads as avatarUrl', (done) => { + request + .post(api('users.setAvatar')) + .set(credentials) + .send({ + userId: userCredentials['X-User-Id'], + avatarUrl: 'http://169.254.169.254/', + }) + .expect('Content-Type', 'application/json') + .expect(400) + .expect((res) => { + expect(res.body).to.have.property('success', false); + }) + .end(done); + }); }); describe('[/users.resetAvatar]', () => { diff --git a/apps/meteor/tests/unit/app/lib/server/lib/checkUrlForSsrf.tests.ts b/apps/meteor/tests/unit/app/lib/server/lib/checkUrlForSsrf.tests.ts new file mode 100644 index 000000000000..9cb7f1cd288c --- /dev/null +++ b/apps/meteor/tests/unit/app/lib/server/lib/checkUrlForSsrf.tests.ts @@ -0,0 +1,52 @@ +import { expect } from 'chai'; + +import { checkUrlForSsrf } from '../../../../../../app/lib/server/functions/checkUrlForSsrf'; + +describe('checkUrlForSsrf', () => { + it('should return false if the URL does not start with http:// or https://', async () => { + const result = await checkUrlForSsrf('ftp://example.com'); + expect(result).to.be.false; + }); + + it('should return false if the domain is not valid', async () => { + const result = await checkUrlForSsrf('https://www_google_com'); + expect(result).to.be.false; + }); + + it('should return false if the IP is not in a valid IPv4 format', async () => { + const result = await checkUrlForSsrf('https://127.1'); + expect(result).to.be.false; + }); + + it('should return false if the IP is in a restricted range', async () => { + const result = await checkUrlForSsrf('http://127.0.0.1'); + expect(result).to.be.false; + }); + + it('should return false if the domain is metadata.google.internal', async () => { + const result = await checkUrlForSsrf('http://metadata.google.internal'); + expect(result).to.be.false; + }); + + it('should return false if DNS resolves to an IP in the restricted range', async () => { + const result = await checkUrlForSsrf('http://169.254.169.254.nip.io'); + expect(result).to.be.false; + }); + + it('should return true if valid domain', async () => { + const result = await checkUrlForSsrf('https://www.google.com/'); + expect(result).to.be.true; + }); + + it('should return true if valid IP', async () => { + const result = await checkUrlForSsrf('http://216.58.214.174'); + expect(result).to.be.true; + }); + + it('should return true if valid URL', async () => { + const result = await checkUrlForSsrf( + 'https://upload.wikimedia.org/wikipedia/commons/thumb/1/15/Cat_August_2010-4.jpg/2560px-Cat_August_2010-4.jpg', + ); + expect(result).to.be.true; + }); +}); diff --git a/apps/meteor/tests/unit/app/lib/server/lib/validateNameChars.tests.ts b/apps/meteor/tests/unit/app/lib/server/lib/validateNameChars.tests.ts new file mode 100644 index 000000000000..a78a0cbc3322 --- /dev/null +++ b/apps/meteor/tests/unit/app/lib/server/lib/validateNameChars.tests.ts @@ -0,0 +1,56 @@ +import { expect } from 'chai'; + +import { validateNameChars } from '../../../../../../app/lib/server/functions/validateNameChars'; + +describe('validateNameChars', () => { + it('should return false for undefined input', () => { + expect(validateNameChars(undefined)).to.be.false; + }); + + it('should return false for non-string input', () => { + expect(validateNameChars(123 as any)).to.be.false; + expect(validateNameChars({} as any)).to.be.false; + expect(validateNameChars([] as any)).to.be.false; + }); + + it('should return false for names with invalid characters', () => { + expect(validateNameChars('name<')).to.be.false; + expect(validateNameChars('name>')).to.be.false; + expect(validateNameChars('name/')).to.be.false; + expect(validateNameChars('name\\')).to.be.false; + }); + + it('should return false for names with invalid characters after decoding', () => { + expect(validateNameChars('name%3E')).to.be.false; + expect(validateNameChars('name%5C')).to.be.false; + expect(validateNameChars('name%3C')).to.be.false; + }); + + it('should return false for malicious HTML payloads', () => { + expect(validateNameChars('')).to.be.false; + expect(validateNameChars('%3Cscript%3Ealert%28%27XSS%27%29%3C%2Fscript%3E')).to.be.false; + expect( + validateNameChars( + '
', + ), + ).to.be.false; + expect( + validateNameChars( + '%3Cform%20action%3D%22http%3A%2F%2Fmalicious.site%22%20method%3D%22post%22%3E%3Cinput%20type%3D%22text%22%20name%3D%22username%22%20value%3D%22Enter%20username%22%3E%3Cinput%20type%3D%22password%22%20name%3D%22password%22%20value%3D%22Enter%20password%22%3E%3Cinput%20type%3D%22submit%22%20value%3D%22Submit%22%3E%3C%2Fform%3E', + ), + ).to.be.false; + }); + + it('should return false if decodeURI throws an error', () => { + expect(validateNameChars('%')).to.be.false; + expect(validateNameChars('%E0%A4%A')).to.be.false; + }); + + it('should return true for valid names', () => { + expect(validateNameChars('name')).to.be.true; + expect(validateNameChars('valid_name')).to.be.true; + expect(validateNameChars('valid-name')).to.be.true; + expect(validateNameChars('valid.name')).to.be.true; + expect(validateNameChars('valid name')).to.be.true; + }); +}); diff --git a/ee/apps/account-service/CHANGELOG.md b/ee/apps/account-service/CHANGELOG.md index 88e9f42c4464..238e83e92d97 100644 --- a/ee/apps/account-service/CHANGELOG.md +++ b/ee/apps/account-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/account-service +## 0.4.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.10.1 + - @rocket.chat/rest-typings@6.10.1 + - @rocket.chat/core-services@0.4.1 + - @rocket.chat/model-typings@0.5.1 + - @rocket.chat/models@0.1.1 +
+ ## 0.4.0 ### Minor Changes diff --git a/ee/apps/account-service/package.json b/ee/apps/account-service/package.json index 194a3e1760e5..d52253fa2f94 100644 --- a/ee/apps/account-service/package.json +++ b/ee/apps/account-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/account-service", "private": true, - "version": "0.4.0", + "version": "0.4.1", "description": "Rocket.Chat Account service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/authorization-service/CHANGELOG.md b/ee/apps/authorization-service/CHANGELOG.md index 9d7701e2ab0f..f216f11428d8 100644 --- a/ee/apps/authorization-service/CHANGELOG.md +++ b/ee/apps/authorization-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/authorization-service +## 0.4.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.10.1 + - @rocket.chat/rest-typings@6.10.1 + - @rocket.chat/core-services@0.4.1 + - @rocket.chat/model-typings@0.5.1 + - @rocket.chat/models@0.1.1 +
+ ## 0.4.0 ### Minor Changes diff --git a/ee/apps/authorization-service/package.json b/ee/apps/authorization-service/package.json index 6b4830f918d6..6eef0c30f9a7 100644 --- a/ee/apps/authorization-service/package.json +++ b/ee/apps/authorization-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/authorization-service", "private": true, - "version": "0.4.0", + "version": "0.4.1", "description": "Rocket.Chat Authorization service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/ddp-streamer/CHANGELOG.md b/ee/apps/ddp-streamer/CHANGELOG.md index f19a4a40be4a..f43ecec49734 100644 --- a/ee/apps/ddp-streamer/CHANGELOG.md +++ b/ee/apps/ddp-streamer/CHANGELOG.md @@ -1,5 +1,20 @@ # @rocket.chat/ddp-streamer +## 0.3.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.10.1 + - @rocket.chat/rest-typings@6.10.1 + - @rocket.chat/core-services@0.4.1 + - @rocket.chat/model-typings@0.5.1 + - @rocket.chat/ui-contexts@8.0.1 + - @rocket.chat/models@0.1.1 + - @rocket.chat/instance-status@0.1.1 +
+ ## 0.3.0 ### Minor Changes diff --git a/ee/apps/ddp-streamer/package.json b/ee/apps/ddp-streamer/package.json index b20066036c20..19d69091e453 100644 --- a/ee/apps/ddp-streamer/package.json +++ b/ee/apps/ddp-streamer/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/ddp-streamer", "private": true, - "version": "0.3.0", + "version": "0.3.1", "description": "Rocket.Chat DDP-Streamer service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/omnichannel-transcript/CHANGELOG.md b/ee/apps/omnichannel-transcript/CHANGELOG.md index 935b90c2bc3c..4666d1a632d9 100644 --- a/ee/apps/omnichannel-transcript/CHANGELOG.md +++ b/ee/apps/omnichannel-transcript/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-transcript +## 0.4.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.10.1 + - @rocket.chat/omnichannel-services@0.2.1 + - @rocket.chat/pdf-worker@0.1.1 + - @rocket.chat/core-services@0.4.1 + - @rocket.chat/model-typings@0.5.1 + - @rocket.chat/models@0.1.1 +
+ ## 0.4.0 ### Minor Changes diff --git a/ee/apps/omnichannel-transcript/package.json b/ee/apps/omnichannel-transcript/package.json index 5acae19a3660..cbbfeedda398 100644 --- a/ee/apps/omnichannel-transcript/package.json +++ b/ee/apps/omnichannel-transcript/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/omnichannel-transcript", "private": true, - "version": "0.4.0", + "version": "0.4.1", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/presence-service/CHANGELOG.md b/ee/apps/presence-service/CHANGELOG.md index 54d88fa70219..338c584f29da 100644 --- a/ee/apps/presence-service/CHANGELOG.md +++ b/ee/apps/presence-service/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/presence-service +## 0.4.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.10.1 + - @rocket.chat/presence@0.2.1 + - @rocket.chat/core-services@0.4.1 + - @rocket.chat/model-typings@0.5.1 + - @rocket.chat/models@0.1.1 +
+ ## 0.4.0 ### Minor Changes diff --git a/ee/apps/presence-service/package.json b/ee/apps/presence-service/package.json index 850cc96c3429..2bc89c48fdaf 100644 --- a/ee/apps/presence-service/package.json +++ b/ee/apps/presence-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/presence-service", "private": true, - "version": "0.4.0", + "version": "0.4.1", "description": "Rocket.Chat Presence service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/queue-worker/CHANGELOG.md b/ee/apps/queue-worker/CHANGELOG.md index 636ec40b1c23..ccda9ae96e56 100644 --- a/ee/apps/queue-worker/CHANGELOG.md +++ b/ee/apps/queue-worker/CHANGELOG.md @@ -1,5 +1,18 @@ # @rocket.chat/queue-worker +## 0.4.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.10.1 + - @rocket.chat/omnichannel-services@0.2.1 + - @rocket.chat/core-services@0.4.1 + - @rocket.chat/model-typings@0.5.1 + - @rocket.chat/models@0.1.1 +
+ ## 0.4.0 ### Minor Changes diff --git a/ee/apps/queue-worker/package.json b/ee/apps/queue-worker/package.json index d4737556e665..be7ac1376935 100644 --- a/ee/apps/queue-worker/package.json +++ b/ee/apps/queue-worker/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/queue-worker", "private": true, - "version": "0.4.0", + "version": "0.4.1", "description": "Rocket.Chat service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/apps/stream-hub-service/CHANGELOG.md b/ee/apps/stream-hub-service/CHANGELOG.md index 4fa60570b11c..cf5790099785 100644 --- a/ee/apps/stream-hub-service/CHANGELOG.md +++ b/ee/apps/stream-hub-service/CHANGELOG.md @@ -1,5 +1,17 @@ # @rocket.chat/stream-hub-service +## 0.4.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.10.1 + - @rocket.chat/core-services@0.4.1 + - @rocket.chat/model-typings@0.5.1 + - @rocket.chat/models@0.1.1 +
+ ## 0.4.0 ### Minor Changes diff --git a/ee/apps/stream-hub-service/package.json b/ee/apps/stream-hub-service/package.json index 5b7f0d15d7fc..e75f32b27d43 100644 --- a/ee/apps/stream-hub-service/package.json +++ b/ee/apps/stream-hub-service/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/stream-hub-service", "private": true, - "version": "0.4.0", + "version": "0.4.1", "description": "Rocket.Chat Stream Hub service", "scripts": { "build": "tsc -p tsconfig.json", diff --git a/ee/packages/api-client/CHANGELOG.md b/ee/packages/api-client/CHANGELOG.md index 613f4f79cda6..d8c8b8a88e86 100644 --- a/ee/packages/api-client/CHANGELOG.md +++ b/ee/packages/api-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/api-client +## 0.2.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.10.1 + - @rocket.chat/rest-typings@6.10.1 +
+ ## 0.2.0 ### Minor Changes diff --git a/ee/packages/api-client/package.json b/ee/packages/api-client/package.json index 043733fe9a62..0e17632218e2 100644 --- a/ee/packages/api-client/package.json +++ b/ee/packages/api-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/api-client", - "version": "0.2.0", + "version": "0.2.1", "devDependencies": { "@swc/core": "^1.3.95", "@swc/jest": "^0.2.29", diff --git a/ee/packages/ddp-client/CHANGELOG.md b/ee/packages/ddp-client/CHANGELOG.md index c75ce3f978b1..38a500223ce2 100644 --- a/ee/packages/ddp-client/CHANGELOG.md +++ b/ee/packages/ddp-client/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/ddp-client +## 0.3.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/rest-typings@6.10.1 + - @rocket.chat/api-client@0.2.1 +
+ ## 0.3.0 ### Minor Changes diff --git a/ee/packages/ddp-client/package.json b/ee/packages/ddp-client/package.json index 394a0b436180..9daeb0414ffe 100644 --- a/ee/packages/ddp-client/package.json +++ b/ee/packages/ddp-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ddp-client", - "version": "0.3.0", + "version": "0.3.1", "devDependencies": { "@swc/core": "^1.3.95", "@swc/jest": "^0.2.29", diff --git a/ee/packages/license/CHANGELOG.md b/ee/packages/license/CHANGELOG.md index e8ca375a5559..b4f56765a6bf 100644 --- a/ee/packages/license/CHANGELOG.md +++ b/ee/packages/license/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/license +## 0.2.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.10.1 +
+ ## 0.2.0 ### Minor Changes diff --git a/ee/packages/license/package.json b/ee/packages/license/package.json index 45e2d7b7d810..9edae84c766d 100644 --- a/ee/packages/license/package.json +++ b/ee/packages/license/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/license", - "version": "0.2.0", + "version": "0.2.1", "private": true, "devDependencies": { "@swc/core": "^1.3.95", diff --git a/ee/packages/omnichannel-services/CHANGELOG.md b/ee/packages/omnichannel-services/CHANGELOG.md index 6439fa133a75..2e6e007ee6da 100644 --- a/ee/packages/omnichannel-services/CHANGELOG.md +++ b/ee/packages/omnichannel-services/CHANGELOG.md @@ -1,5 +1,19 @@ # @rocket.chat/omnichannel-services +## 0.2.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.10.1 + - @rocket.chat/rest-typings@6.10.1 + - @rocket.chat/pdf-worker@0.1.1 + - @rocket.chat/core-services@0.4.1 + - @rocket.chat/model-typings@0.5.1 + - @rocket.chat/models@0.1.1 +
+ ## 0.2.0 ### Minor Changes diff --git a/ee/packages/omnichannel-services/package.json b/ee/packages/omnichannel-services/package.json index 58e339b6310a..77f06f3354a6 100644 --- a/ee/packages/omnichannel-services/package.json +++ b/ee/packages/omnichannel-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/omnichannel-services", - "version": "0.2.0", + "version": "0.2.1", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/ee/packages/pdf-worker/CHANGELOG.md b/ee/packages/pdf-worker/CHANGELOG.md index f96576a0f479..303b1439c8ce 100644 --- a/ee/packages/pdf-worker/CHANGELOG.md +++ b/ee/packages/pdf-worker/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/pdf-worker +## 0.1.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.10.1 +
+ ## 0.1.0 ### Minor Changes diff --git a/ee/packages/pdf-worker/package.json b/ee/packages/pdf-worker/package.json index 14560ccbf260..a2232520921d 100644 --- a/ee/packages/pdf-worker/package.json +++ b/ee/packages/pdf-worker/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/pdf-worker", - "version": "0.1.0", + "version": "0.1.1", "private": true, "devDependencies": { "@storybook/addon-essentials": "~6.5.16", diff --git a/ee/packages/presence/CHANGELOG.md b/ee/packages/presence/CHANGELOG.md index 07cbc3e223f9..22ea508bd15c 100644 --- a/ee/packages/presence/CHANGELOG.md +++ b/ee/packages/presence/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/presence +## 0.2.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.10.1 + - @rocket.chat/core-services@0.4.1 + - @rocket.chat/models@0.1.1 +
+ ## 0.2.0 ### Minor Changes diff --git a/ee/packages/presence/package.json b/ee/packages/presence/package.json index 0ff069768423..8f65fb638eaf 100644 --- a/ee/packages/presence/package.json +++ b/ee/packages/presence/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/presence", - "version": "0.2.0", + "version": "0.2.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/packages/apps/CHANGELOG.md b/packages/apps/CHANGELOG.md index c0ee3cb0d943..606c404b9dc7 100644 --- a/packages/apps/CHANGELOG.md +++ b/packages/apps/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/apps +## 0.1.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.10.1 + - @rocket.chat/model-typings@0.5.1 +
+ ## 0.1.0 ### Minor Changes diff --git a/packages/apps/package.json b/packages/apps/package.json index 3387deeea23a..a2f0e1c0c8d0 100644 --- a/packages/apps/package.json +++ b/packages/apps/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/apps", - "version": "0.1.0", + "version": "0.1.1", "private": true, "devDependencies": { "@types/jest": "~29.5.7", diff --git a/packages/core-services/CHANGELOG.md b/packages/core-services/CHANGELOG.md index e505865721ec..ae47a828656c 100644 --- a/packages/core-services/CHANGELOG.md +++ b/packages/core-services/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/core-services +## 0.4.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.10.1 + - @rocket.chat/rest-typings@6.10.1 + - @rocket.chat/models@0.1.1 +
+ ## 0.4.0 ### Minor Changes diff --git a/packages/core-services/package.json b/packages/core-services/package.json index 4b7ce783ac8c..6ab8444cd5a7 100644 --- a/packages/core-services/package.json +++ b/packages/core-services/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/core-services", - "version": "0.4.0", + "version": "0.4.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", diff --git a/packages/core-typings/CHANGELOG.md b/packages/core-typings/CHANGELOG.md index ca75dd912ec0..40578e341608 100644 --- a/packages/core-typings/CHANGELOG.md +++ b/packages/core-typings/CHANGELOG.md @@ -1,5 +1,7 @@ # @rocket.chat/core-typings +## 6.10.1 + ## 6.10.0 ### Minor Changes diff --git a/packages/cron/CHANGELOG.md b/packages/cron/CHANGELOG.md index adf3a4197bb7..1ec9a7497714 100644 --- a/packages/cron/CHANGELOG.md +++ b/packages/cron/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/cron +## 0.1.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.10.1 + - @rocket.chat/models@0.1.1 +
+ ## 0.1.0 ### Minor Changes diff --git a/packages/cron/package.json b/packages/cron/package.json index ae38acb7a799..5f44c96d58a6 100644 --- a/packages/cron/package.json +++ b/packages/cron/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/cron", - "version": "0.1.0", + "version": "0.1.1", "private": true, "devDependencies": { "@types/jest": "~29.5.7", diff --git a/packages/fuselage-ui-kit/CHANGELOG.md b/packages/fuselage-ui-kit/CHANGELOG.md index 6e7cf8afed99..d96d8d2bc1ee 100644 --- a/packages/fuselage-ui-kit/CHANGELOG.md +++ b/packages/fuselage-ui-kit/CHANGELOG.md @@ -1,5 +1,18 @@ # Change Log +## 8.0.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.10.1 + - @rocket.chat/gazzodown@8.0.1 + - @rocket.chat/ui-contexts@8.0.1 + - @rocket.chat/ui-avatar@4.0.1 + - @rocket.chat/ui-video-conf@8.0.1 +
+ ## 8.0.0 ### Minor Changes diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index 57f59f2bceca..61a0a9a93fba 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/fuselage-ui-kit", "private": true, - "version": "8.0.0", + "version": "8.0.1", "description": "UiKit elements for Rocket.Chat Apps built under Fuselage design system", "homepage": "https://rocketchat.github.io/Rocket.Chat.Fuselage/", "author": { @@ -50,10 +50,10 @@ "@rocket.chat/icons": "*", "@rocket.chat/prettier-config": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "4.0.0", - "@rocket.chat/ui-contexts": "8.0.0", + "@rocket.chat/ui-avatar": "4.0.1", + "@rocket.chat/ui-contexts": "8.0.1", "@rocket.chat/ui-kit": "0.35.0", - "@rocket.chat/ui-video-conf": "8.0.0", + "@rocket.chat/ui-video-conf": "8.0.1", "@tanstack/react-query": "*", "react": "*", "react-dom": "*" diff --git a/packages/gazzodown/CHANGELOG.md b/packages/gazzodown/CHANGELOG.md index b6aecd837384..44d587ce6b5a 100644 --- a/packages/gazzodown/CHANGELOG.md +++ b/packages/gazzodown/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/gazzodown +## 8.0.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.10.1 + - @rocket.chat/ui-contexts@8.0.1 + - @rocket.chat/ui-client@8.0.1 +
+ ## 8.0.0 ### Minor Changes diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index 5c36a430d233..c90bc13b6367 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/gazzodown", - "version": "8.0.0", + "version": "8.0.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -71,8 +71,8 @@ "@rocket.chat/fuselage-tokens": "*", "@rocket.chat/message-parser": "0.31.29", "@rocket.chat/styled": "*", - "@rocket.chat/ui-client": "8.0.0", - "@rocket.chat/ui-contexts": "8.0.0", + "@rocket.chat/ui-client": "8.0.1", + "@rocket.chat/ui-contexts": "8.0.1", "katex": "*", "react": "*" }, diff --git a/packages/i18n/src/locales/en.i18n.json b/packages/i18n/src/locales/en.i18n.json index 27c8f2ecec62..523888f0912a 100644 --- a/packages/i18n/src/locales/en.i18n.json +++ b/packages/i18n/src/locales/en.i18n.json @@ -6117,6 +6117,7 @@ "registration.component.form.emailOrUsername": "Email or username", "registration.component.form.username": "Username", "registration.component.form.name": "Name", + "registration.component.form.nameContainsInvalidChars": "Name contains invalid characters", "registration.component.form.nameOptional": "Name optional", "registration.component.form.createAnAccount": "Create an account", "registration.component.form.userAlreadyExist": "Username already exists. Please try another username.", diff --git a/packages/i18n/src/locales/pt-BR.i18n.json b/packages/i18n/src/locales/pt-BR.i18n.json index 6e5a59bda0a5..282feecbc42c 100644 --- a/packages/i18n/src/locales/pt-BR.i18n.json +++ b/packages/i18n/src/locales/pt-BR.i18n.json @@ -4906,6 +4906,7 @@ "registration.component.resetPassword": "Redefinir senha", "registration.component.form.username": "Nome de usuário", "registration.component.form.name": "Nome", + "registration.component.form.nameContainsInvalidChars": "O nome contém caracteres inválidos", "registration.component.form.userAlreadyExist": "O nome de usuário já existe. Tente outro nome de usuário.", "registration.component.form.emailAlreadyExists": "E-mail já existe", "registration.component.form.usernameAlreadyExists": "O nome de usuário já existe. Tente outro nome de usuário.", diff --git a/packages/i18n/src/locales/pt.i18n.json b/packages/i18n/src/locales/pt.i18n.json index 96575d48ef72..74cf2a3f9b08 100644 --- a/packages/i18n/src/locales/pt.i18n.json +++ b/packages/i18n/src/locales/pt.i18n.json @@ -3161,6 +3161,7 @@ "registration.component.form.emailOrUsername": "Email ou nome de utilizador", "registration.component.form.username": "Nome de utilizador", "registration.component.form.name": "Nome", + "registration.component.form.nameContainsInvalidChars": "O nome contém caracteres inválidos", "registration.component.form.userAlreadyExist": "O nome de utilizador já existe. Por favor, tente outro nome de utilizador.", "registration.component.form.emailAlreadyExists": "Email já registado", "registration.component.form.usernameAlreadyExists": "O nome de utilizador já existe. Por favor, tente outro nome de utilizador.", diff --git a/packages/instance-status/CHANGELOG.md b/packages/instance-status/CHANGELOG.md index c87456b36a80..094ad838096a 100644 --- a/packages/instance-status/CHANGELOG.md +++ b/packages/instance-status/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/instance-status +## 0.1.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/models@0.1.1 +
+ ## 0.1.0 ### Minor Changes diff --git a/packages/instance-status/package.json b/packages/instance-status/package.json index 61a3b3121be9..1da979b011a1 100644 --- a/packages/instance-status/package.json +++ b/packages/instance-status/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/instance-status", - "version": "0.1.0", + "version": "0.1.1", "private": true, "devDependencies": { "@rocket.chat/eslint-config": "workspace:^", diff --git a/packages/livechat/CHANGELOG.md b/packages/livechat/CHANGELOG.md index e8c8140ae8a3..293cc48779c0 100644 --- a/packages/livechat/CHANGELOG.md +++ b/packages/livechat/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/livechat Change Log +## 1.18.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/gazzodown@8.0.1 +
+ ## 1.18.0 ### Minor Changes diff --git a/packages/livechat/package.json b/packages/livechat/package.json index 7ab28ca30366..418c927a5ce8 100644 --- a/packages/livechat/package.json +++ b/packages/livechat/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/livechat", - "version": "1.18.0", + "version": "1.18.1", "files": [ "/build" ], diff --git a/packages/model-typings/CHANGELOG.md b/packages/model-typings/CHANGELOG.md index 97399d02988f..0b8121fc77a1 100644 --- a/packages/model-typings/CHANGELOG.md +++ b/packages/model-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/model-typings +## 0.5.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.10.1 +
+ ## 0.5.0 ### Minor Changes diff --git a/packages/model-typings/package.json b/packages/model-typings/package.json index 372bde3257cb..3127475ad161 100644 --- a/packages/model-typings/package.json +++ b/packages/model-typings/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/model-typings", - "version": "0.5.0", + "version": "0.5.1", "private": true, "devDependencies": { "@types/jest": "~29.5.7", diff --git a/packages/models/CHANGELOG.md b/packages/models/CHANGELOG.md index 4b30b3f974ce..3bb8885897be 100644 --- a/packages/models/CHANGELOG.md +++ b/packages/models/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/models +## 0.1.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/model-typings@0.5.1 +
+ ## 0.1.0 ### Minor Changes diff --git a/packages/models/package.json b/packages/models/package.json index c5e9cfff578e..89197d6796aa 100644 --- a/packages/models/package.json +++ b/packages/models/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/models", - "version": "0.1.0", + "version": "0.1.1", "private": true, "devDependencies": { "@swc/core": "^1.3.95", diff --git a/packages/rest-typings/CHANGELOG.md b/packages/rest-typings/CHANGELOG.md index 00affd2f294b..5bb9404f1b0a 100644 --- a/packages/rest-typings/CHANGELOG.md +++ b/packages/rest-typings/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/rest-typings +## 6.10.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.10.1 +
+ ## 6.10.0 ### Minor Changes diff --git a/packages/ui-avatar/CHANGELOG.md b/packages/ui-avatar/CHANGELOG.md index f45e6241438a..8b37dbb7fd02 100644 --- a/packages/ui-avatar/CHANGELOG.md +++ b/packages/ui-avatar/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-avatar +## 4.0.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@8.0.1 +
+ ## 4.0.0 ### Minor Changes diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index 69f06db62d82..2c3a4d75b018 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-avatar", - "version": "4.0.0", + "version": "4.0.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -31,7 +31,7 @@ ], "peerDependencies": { "@rocket.chat/fuselage": "*", - "@rocket.chat/ui-contexts": "8.0.0", + "@rocket.chat/ui-contexts": "8.0.1", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-client/CHANGELOG.md b/packages/ui-client/CHANGELOG.md index 2da8d9c6ca9a..c5cd6a2cce8f 100644 --- a/packages/ui-client/CHANGELOG.md +++ b/packages/ui-client/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/ui-client +## 8.0.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@8.0.1 +
+ ## 8.0.0 ### Minor Changes diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index ca94d3e2fac8..9b73e9814f8c 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-client", - "version": "8.0.0", + "version": "8.0.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -63,7 +63,7 @@ "@rocket.chat/fuselage": "*", "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", - "@rocket.chat/ui-contexts": "8.0.0", + "@rocket.chat/ui-contexts": "8.0.1", "react": "~17.0.2" }, "volta": { diff --git a/packages/ui-contexts/CHANGELOG.md b/packages/ui-contexts/CHANGELOG.md index 90e106d411f1..9315b5fbe66a 100644 --- a/packages/ui-contexts/CHANGELOG.md +++ b/packages/ui-contexts/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/ui-contexts +## 8.0.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/core-typings@6.10.1 + - @rocket.chat/rest-typings@6.10.1 + - @rocket.chat/ddp-client@0.3.1 +
+ ## 8.0.0 ### Minor Changes diff --git a/packages/ui-contexts/package.json b/packages/ui-contexts/package.json index c7d7e31780f3..06311c2b501a 100644 --- a/packages/ui-contexts/package.json +++ b/packages/ui-contexts/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-contexts", - "version": "8.0.0", + "version": "8.0.1", "private": true, "devDependencies": { "@rocket.chat/core-typings": "workspace:^", diff --git a/packages/ui-video-conf/CHANGELOG.md b/packages/ui-video-conf/CHANGELOG.md index 0eecd8aa3072..0849b46fc58b 100644 --- a/packages/ui-video-conf/CHANGELOG.md +++ b/packages/ui-video-conf/CHANGELOG.md @@ -1,5 +1,15 @@ # @rocket.chat/ui-video-conf +## 8.0.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@8.0.1 + - @rocket.chat/ui-avatar@4.0.1 +
+ ## 8.0.0 ### Minor Changes diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index 5d5a04916f2c..dd34ff30d7a5 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/ui-video-conf", - "version": "8.0.0", + "version": "8.0.1", "private": true, "devDependencies": { "@babel/core": "~7.22.20", @@ -36,8 +36,8 @@ "@rocket.chat/fuselage-hooks": "*", "@rocket.chat/icons": "*", "@rocket.chat/styled": "*", - "@rocket.chat/ui-avatar": "4.0.0", - "@rocket.chat/ui-contexts": "8.0.0", + "@rocket.chat/ui-avatar": "4.0.1", + "@rocket.chat/ui-contexts": "8.0.1", "react": "^17.0.2", "react-dom": "^17.0.2" }, diff --git a/packages/uikit-playground/CHANGELOG.md b/packages/uikit-playground/CHANGELOG.md index 43bc6d935488..7750377da8a2 100644 --- a/packages/uikit-playground/CHANGELOG.md +++ b/packages/uikit-playground/CHANGELOG.md @@ -1,5 +1,16 @@ # @rocket.chat/uikit-playground +## 0.3.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/fuselage-ui-kit@8.0.1 + - @rocket.chat/ui-contexts@8.0.1 + - @rocket.chat/ui-avatar@4.0.1 +
+ ## 0.3.0 ### Minor Changes diff --git a/packages/uikit-playground/package.json b/packages/uikit-playground/package.json index 310d39181379..d33cba9aeebc 100644 --- a/packages/uikit-playground/package.json +++ b/packages/uikit-playground/package.json @@ -1,7 +1,7 @@ { "name": "@rocket.chat/uikit-playground", "private": true, - "version": "0.3.0", + "version": "0.3.1", "type": "module", "scripts": { "dev": "vite", diff --git a/packages/web-ui-registration/CHANGELOG.md b/packages/web-ui-registration/CHANGELOG.md index ad91395df6f8..447b861cc456 100644 --- a/packages/web-ui-registration/CHANGELOG.md +++ b/packages/web-ui-registration/CHANGELOG.md @@ -1,5 +1,14 @@ # @rocket.chat/web-ui-registration +## 8.0.1 + +### Patch Changes + +-
Updated dependencies []: + + - @rocket.chat/ui-contexts@8.0.1 +
+ ## 8.0.0 ### Minor Changes diff --git a/packages/web-ui-registration/package.json b/packages/web-ui-registration/package.json index bb5d48340d0c..f4e462649679 100644 --- a/packages/web-ui-registration/package.json +++ b/packages/web-ui-registration/package.json @@ -1,6 +1,6 @@ { "name": "@rocket.chat/web-ui-registration", - "version": "8.0.0", + "version": "8.0.1", "private": true, "homepage": "https://rocket.chat", "main": "./dist/index.js", @@ -51,7 +51,7 @@ "peerDependencies": { "@rocket.chat/layout": "*", "@rocket.chat/tools": "0.2.1", - "@rocket.chat/ui-contexts": "8.0.0", + "@rocket.chat/ui-contexts": "8.0.1", "@tanstack/react-query": "*", "react": "*", "react-hook-form": "*", diff --git a/packages/web-ui-registration/src/RegisterForm.tsx b/packages/web-ui-registration/src/RegisterForm.tsx index 0eda77879be7..57cf9378ab72 100644 --- a/packages/web-ui-registration/src/RegisterForm.tsx +++ b/packages/web-ui-registration/src/RegisterForm.tsx @@ -94,14 +94,15 @@ export const RegisterForm = ({ setLoginRoute }: { setLoginRoute: DispatchLoginRo if (error.errorType === 'error-user-already-exists') { setError('username', { type: 'user-already-exists', message: t('registration.component.form.usernameAlreadyExists') }); } - if (/Email already exists/.test(error.error)) { setError('email', { type: 'email-already-exists', message: t('registration.component.form.emailAlreadyExists') }); } - if (/Username is already in use/.test(error.error)) { setError('username', { type: 'username-already-exists', message: t('registration.component.form.userAlreadyExist') }); } + if (/Name contains invalid characters/.test(error.error)) { + setError('name', { type: 'name-contains-invalid-chars', message: t('registration.component.form.nameContainsInvalidChars') }); + } if (/error-too-many-requests/.test(error.error)) { dispatchToastMessage({ type: 'error', message: error.error }); }