Skip to content

Commit

Permalink
Merge branch 'develop' of github.com:RocketChat/Rocket.Chat into fetc…
Browse files Browse the repository at this point in the history
…hAvatarById

* 'develop' of github.com:RocketChat/Rocket.Chat:
  fix: Infinite loading when uploading a private app (#33181)
  chore: publish preview github pages (#33248)
  chore: move playground (#33260)
  chore: E2EE setting warning update (#33224)
  fix: message parser being slow to process very long messages with too many symbols (#33227)
  chore: fix ui-playground build (#33250)
  feat: Option to disable 2FA for OAuth users (#32945)
  fix: Allow to use the token from `room.v` when requesting transcript instead of finding visitor (#33211)
  • Loading branch information
gabriellsh committed Sep 11, 2024
2 parents f8ec5c5 + fa8ac7a commit a6a7a58
Show file tree
Hide file tree
Showing 249 changed files with 810 additions and 178 deletions.
5 changes: 5 additions & 0 deletions .changeset/four-cherries-kneel.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

Allow to use the token from `room.v` when requesting transcript instead of visitor token. Visitors may change their tokens at any time, rendering old conversations impossible to access for them (or for APIs depending on token) as the visitor token won't match the `room.v` token.
6 changes: 6 additions & 0 deletions .changeset/short-drinks-itch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@rocket.chat/message-parser': patch
'@rocket.chat/peggy-loader': patch
---

Improved the performance of the message parser
6 changes: 6 additions & 0 deletions .changeset/tiny-geckos-kiss.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@rocket.chat/i18n': minor
'@rocket.chat/meteor': minor
---

Added a new setting which allows workspace admins to disable email two factor authentication for SSO (OAuth) users. If enabled, SSO users won't be asked for email two factor authentication.
5 changes: 5 additions & 0 deletions .changeset/wet-hats-walk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@rocket.chat/meteor": patch
---

Fixed issue that caused an infinite loading state when uploading a private app to Rocket.Chat
44 changes: 44 additions & 0 deletions .github/workflows/ci-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# .github/workflows/ci-preview.yml
name: Deploy PR previews
concurrency: preview-${{ github.ref }}
on:
pull_request:
types:
- opened
- reopened
- synchronize
- closed
push:
branches:
- main
- master
- develop
jobs:
deploy-preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- uses: rharkor/caching-for-turbo@v1.5
if: github.event.action != 'closed'

- name: Setup NodeJS
uses: ./.github/actions/setup-node
if: github.event.action != 'closed'
with:
node-version: 14.21.3
cache-modules: true
install: true

- name: Build
if: github.event.action != 'closed'
run: |
yarn turbo run build-preview
yarn turbo run .:build-preview-move
- uses: rossjrw/pr-preview-action@v1
with:
source-dir: .preview
preview-branch: gh-pages
umbrella-dir: pr-preview
action: auto
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ yarn-error.log*
.history
.envrc

.preview

*.sublime-workspace

**/.vim/
Expand Down
1 change: 1 addition & 0 deletions _templates/package/new/package.json.ejs.t
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ to: packages/<%= name %>/package.json
"test": "jest",
"build": "rm -rf dist && tsc -p tsconfig.json",
"dev": "tsc -p tsconfig.json --watch --preserveWatchOutput"
"build-preview": "mkdir -p ../../.preview && cp -r ./dist ../../.preview/<%= name.toLowerCase() %>"
},
"main": "./dist/index.js",
"typings": "./dist/index.d.ts",
Expand Down
70 changes: 70 additions & 0 deletions apps/meteor/app/2fa/server/code/EmailCheck.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { expect } from 'chai';
import { describe, it } from 'mocha';
import proxyquire from 'proxyquire';
import sinon from 'sinon';

const settingsMock = sinon.stub();

const { EmailCheck } = proxyquire.noCallThru().load('./EmailCheck', {
'@rocket.chat/models': {
Users: {},
},
'meteor/accounts-base': {
Accounts: {
_bcryptRounds: () => '123',
},
},
'../../../../server/lib/i18n': {
i18n: {
t: (key: string) => key,
},
},
'../../../mailer/server/api': {
send: () => undefined,
},
'../../../settings/server': {
settings: {
get: settingsMock,
},
},
});

const normalUserMock = { services: { email2fa: { enabled: true } }, emails: [{ email: 'abc@gmail.com', verified: true }] };
const normalUserWithUnverifiedEmailMock = {
services: { email2fa: { enabled: true } },
emails: [{ email: 'abc@gmail.com', verified: false }],
};
const OAuthUserMock = { services: { google: {} }, emails: [{ email: 'abc@gmail.com', verified: true }] };

describe('EmailCheck', () => {
let emailCheck: typeof EmailCheck;
beforeEach(() => {
settingsMock.reset();

emailCheck = new EmailCheck();
});

it('should return EmailCheck is enabled for a normal user', () => {
settingsMock.returns(true);

const isEmail2FAEnabled = emailCheck.isEnabled(normalUserMock);

expect(isEmail2FAEnabled).to.be.equal(true);
});

it('should return EmailCheck is not enabled for a normal user with unverified email', () => {
settingsMock.returns(true);

const isEmail2FAEnabled = emailCheck.isEnabled(normalUserWithUnverifiedEmailMock);

expect(isEmail2FAEnabled).to.be.equal(false);
});

it('should return EmailCheck is not enabled for a OAuth user with setting being false', () => {
settingsMock.returns(true);

const isEmail2FAEnabled = emailCheck.isEnabled(OAuthUserMock);

expect(isEmail2FAEnabled).to.be.equal(false);
});
});
6 changes: 5 additions & 1 deletion apps/meteor/app/2fa/server/code/EmailCheck.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { IUser } from '@rocket.chat/core-typings';
import { isOAuthUser, type IUser } from '@rocket.chat/core-typings';
import { Users } from '@rocket.chat/models';
import { Random } from '@rocket.chat/random';
import bcrypt from 'bcrypt';
Expand All @@ -24,6 +24,10 @@ export class EmailCheck implements ICodeCheck {
return false;
}

if (!settings.get('Accounts_twoFactorAuthentication_email_available_for_OAuth_users') && isOAuthUser(user)) {
return false;
}

if (!user.services?.email2fa?.enabled) {
return false;
}
Expand Down
12 changes: 4 additions & 8 deletions apps/meteor/app/2fa/server/code/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,10 @@ function getAvailableMethodNames(user: IUser): string[] {
export async function getUserForCheck(userId: string): Promise<IUser | null> {
return Users.findOneById(userId, {
projection: {
'emails': 1,
'language': 1,
'createdAt': 1,
'services.totp': 1,
'services.email2fa': 1,
'services.emailCode': 1,
'services.password': 1,
'services.resume.loginTokens': 1,
emails: 1,
language: 1,
createdAt: 1,
services: 1,
},
});
}
Expand Down
14 changes: 9 additions & 5 deletions apps/meteor/app/api/server/v1/misc.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import crypto from 'crypto';

import type { IUser } from '@rocket.chat/core-typings';
import { isOAuthUser, type IUser } from '@rocket.chat/core-typings';
import { Settings, Users } from '@rocket.chat/models';
import {
isShieldSvgProps,
Expand All @@ -26,7 +26,7 @@ import { hasPermissionAsync } from '../../../authorization/server/functions/hasP
import { passwordPolicy } from '../../../lib/server';
import { notifyOnSettingChangedById } from '../../../lib/server/lib/notifyListener';
import { settings } from '../../../settings/server';
import { getDefaultUserFields } from '../../../utils/server/functions/getDefaultUserFields';
import { getBaseUserFields } from '../../../utils/server/functions/getBaseUserFields';
import { isSMTPConfigured } from '../../../utils/server/functions/isSMTPConfigured';
import { getURL } from '../../../utils/server/getURL';
import { API } from '../api';
Expand Down Expand Up @@ -176,15 +176,19 @@ API.v1.addRoute(
{ authRequired: true },
{
async get() {
const fields = getDefaultUserFields();
const { services, ...user } = (await Users.findOneById(this.userId, { projection: fields })) as IUser;
const userFields = { ...getBaseUserFields(), services: 1 };
const { services, ...user } = (await Users.findOneById(this.userId, { projection: userFields })) as IUser;

return API.v1.success(
await getUserInfo({
...user,
isOAuthUser: isOAuthUser({ ...user, services }),
...(services && {
services: {
...services,
...(services.github && { github: services.github }),
...(services.gitlab && { gitlab: services.gitlab }),
...(services.email2fa?.enabled && { email2fa: { enabled: services.email2fa.enabled } }),
...(services.totp?.enabled && { totp: { enabled: services.totp.enabled } }),
password: {
// The password hash shouldn't be leaked but the client may need to know if it exists.
exists: Boolean(services?.password?.bcrypt),
Expand Down
17 changes: 7 additions & 10 deletions apps/meteor/app/livechat/server/lib/sendTranscript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import {
type IUser,
type MessageTypesValues,
type IOmnichannelSystemMessage,
type ILivechatVisitor,
isFileAttachment,
isFileImageAttachment,
} from '@rocket.chat/core-typings';
import colors from '@rocket.chat/fuselage-tokens/colors';
import { Logger } from '@rocket.chat/logger';
import { LivechatRooms, LivechatVisitors, Messages, Uploads, Users } from '@rocket.chat/models';
import { LivechatRooms, Messages, Uploads, Users } from '@rocket.chat/models';
import { check } from 'meteor/check';
import moment from 'moment-timezone';

Expand Down Expand Up @@ -41,16 +42,12 @@ export async function sendTranscript({

const room = await LivechatRooms.findOneById(rid);

const visitor = await LivechatVisitors.getVisitorByToken(token, {
projection: { _id: 1, token: 1, language: 1, username: 1, name: 1 },
});

if (!visitor) {
throw new Error('error-invalid-token');
const visitor = room?.v as ILivechatVisitor;
if (token !== visitor?.token) {
throw new Error('error-invalid-visitor');
}

// @ts-expect-error - Visitor typings should include language?
const userLanguage = visitor?.language || settings.get('Language') || 'en';
const userLanguage = settings.get<string>('Language') || 'en';
const timezone = getTimezone(user);
logger.debug(`Transcript will be sent using ${timezone} as timezone`);

Expand All @@ -59,7 +56,7 @@ export async function sendTranscript({
}

// allow to only user to send transcripts from their own chats
if (room.t !== 'l' || !room.v || room.v.token !== token) {
if (room.t !== 'l') {
throw new Error('error-invalid-room');
}

Expand Down
34 changes: 34 additions & 0 deletions apps/meteor/app/utils/server/functions/getBaseUserFields.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
type UserFields = {
[k: string]: number;
};

export const getBaseUserFields = (): UserFields => ({
'name': 1,
'username': 1,
'nickname': 1,
'emails': 1,
'status': 1,
'statusDefault': 1,
'statusText': 1,
'statusConnection': 1,
'bio': 1,
'avatarOrigin': 1,
'utcOffset': 1,
'language': 1,
'settings': 1,
'enableAutoAway': 1,
'idleTimeLimit': 1,
'roles': 1,
'active': 1,
'defaultRoom': 1,
'customFields': 1,
'requirePasswordChange': 1,
'requirePasswordChangeReason': 1,
'statusLivechat': 1,
'banners': 1,
'oauth.authorizedClients': 1,
'_updatedAt': 1,
'avatarETag': 1,
'extension': 1,
'openBusinessHours': 1,
});
35 changes: 5 additions & 30 deletions apps/meteor/app/utils/server/functions/getDefaultUserFields.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,14 @@
type DefaultUserFields = {
import { getBaseUserFields } from './getBaseUserFields';

type UserFields = {
[k: string]: number;
};

export const getDefaultUserFields = (): DefaultUserFields => ({
'name': 1,
'username': 1,
'nickname': 1,
'emails': 1,
'status': 1,
'statusDefault': 1,
'statusText': 1,
'statusConnection': 1,
'bio': 1,
'avatarOrigin': 1,
'utcOffset': 1,
'language': 1,
'settings': 1,
'enableAutoAway': 1,
'idleTimeLimit': 1,
'roles': 1,
'active': 1,
'defaultRoom': 1,
'customFields': 1,
'requirePasswordChange': 1,
'requirePasswordChangeReason': 1,
export const getDefaultUserFields = (): UserFields => ({
...getBaseUserFields(),
'services.github': 1,
'services.gitlab': 1,
'services.password.bcrypt': 1,
'services.totp.enabled': 1,
'services.email2fa.enabled': 1,
'statusLivechat': 1,
'banners': 1,
'oauth.authorizedClients': 1,
'_updatedAt': 1,
'avatarETag': 1,
'extension': 1,
'openBusinessHours': 1,
});
Loading

0 comments on commit a6a7a58

Please sign in to comment.