Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/videoconf-persistent-chat-forced-e2ee.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@rocket.chat/meteor': patch
'@rocket.chat/i18n': patch
---

Fixed video calls failing to start when **Force end-to-end encryption on private rooms** and video conference persistent chat were both enabled. The persistent chat discussion is created unencrypted, so room creation was rejected by the encryption policy, and because that step runs before the call URL, start message and notifications, the call was aborted and left an unusable conference record behind — with direct calls stuck ringing. The persistent chat discussion is now skipped when encryption is enforced on private rooms, and the call starts normally. The **Force end-to-end encryption on private rooms** setting also warns that it is not compatible with video conference persistent chat.
19 changes: 17 additions & 2 deletions apps/meteor/server/services/video-conference/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Apps } from '@rocket.chat/apps';
import type { AppVideoConfProviderManager } from '@rocket.chat/apps/dist/server/managers/AppVideoConfProviderManager';
import type { VideoConfData, VideoConfDataExtended } from '@rocket.chat/apps-engine/definition/videoConfProviders';
import type { IVideoConfService, VideoConferenceJoinOptions } from '@rocket.chat/core-services';
import { api, ServiceClassInternal, Room } from '@rocket.chat/core-services';
import { api, ServiceClassInternal, Room, isMeteorError } from '@rocket.chat/core-services';
import type {
IDirectVideoConference,
ILivechatVideoConference,
Expand Down Expand Up @@ -1150,7 +1150,22 @@ export class VideoConfService extends ServiceClassInternal implements IVideoConf
displayName = `${date} ${name}`;
}

await this.createDiscussionForConference(displayName, call, createdBy);
try {
await this.createDiscussionForConference(displayName, call, createdBy);
} catch (err) {
// The persistent chat discussion is always created unencrypted, so it is rejected when the workspace
// enforces encryption on private rooms. Those two features are incompatible by design, so skip the
// discussion instead of aborting the call. Any other failure is unexpected and must still surface.
if (!isMeteorError(err) || err.error !== 'error-encrypted-private-rooms-enforced') {
throw err;
}

logger.warn({
name: 'Skipped the persistent chat discussion of a conference because encryption is enforced on private rooms',
callId,
rid: call.rid,
});
}
}

private async getRoomForDiscussion(
Expand Down
1 change: 1 addition & 0 deletions apps/meteor/server/settings/e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const createE2ESettings = () =>
type: 'boolean',
i18nLabel: 'Force_Encryption_For_Private_Rooms',
i18nDescription: 'Force_Encryption_For_Private_Rooms_Description',
alert: 'Force_Encryption_For_Private_Rooms_Alert',
public: true,
enableQuery: { _id: 'E2E_Enable', value: true },
});
Expand Down
58 changes: 58 additions & 0 deletions apps/meteor/tests/end-to-end/apps/video-conferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -602,6 +602,64 @@ describe('Apps - Video Conferences', () => {
});
});

describe('[Persistent Chat provider with the persistent chat feature enabled and encryption forced on private rooms]', () => {
let callId: string | undefined;

before(async () => {
if (!process.env.IS_EE) {
return;
}

await updateSetting('VideoConf_Default_Provider', 'persistentchat');
await updateSetting('Discussion_enabled', true);
await updateSetting('VideoConf_Enable_Persistent_Chat', true);
await Promise.all([updateSetting('E2E_Enable', true), updateSetting('E2E_Force_Encryption_For_Private_Rooms', true)]);

const res = await request.post(api('video-conference.start')).set(credentials).send({
roomId,
});

callId = res.body.data?.callId;
});

after(async () => {
if (!process.env.IS_EE) {
return;
}

await Promise.all([updateSetting('E2E_Enable', false), updateSetting('E2E_Force_Encryption_For_Private_Rooms', false)]);
});

it('should start the call even though the persistent chat discussion can not be created', async function () {
if (!process.env.IS_EE) {
this.skip();
}

expect(callId).to.be.a('string');

await request
.get(api('video-conference.info'))
.set(credentials)
.query({
callId,
})
.expect(200)
.expect((res: Response) => {
expect(res.body.success).to.be.equal(true);
expect(res.body).to.have.a.property('_id').equal(callId);
expect(res.body).to.have.a.property('rid').equal(roomId);
// the call must be fully started: an unencrypted persistent chat discussion can not be
// created while encryption is enforced on private rooms, but that must not abort the call
expect(res.body).to.have.a.property('url').that.is.a('string');
expect(res.body).to.have.a.property('status').equal(1);
expect(res.body).to.have.a.property('messages').that.is.an('object');
expect(res.body.messages).to.have.a.property('started').that.is.a('string');
// persistent chat is skipped
expect(res.body).to.not.have.a.property('discussionRid');
});
});
});

describe('[Persistent Chat provider with the persistent chat feature enabled and custom discussion names]', () => {
let callId: string | undefined;
let discussionRid: string | undefined;
Expand Down
1 change: 1 addition & 0 deletions packages/i18n/src/locales/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -2998,6 +2998,7 @@
"Force_Disable_OpLog_For_Cache": "Force Disable OpLog for Cache",
"Force_Disable_OpLog_For_Cache_Description": "Will not use OpLog to sync cache even when it's available",
"Force_Encryption_For_Private_Rooms": "Force end-to-end encryption on private rooms",
"Force_Encryption_For_Private_Rooms_Alert": "<b>Not compatible with video conference persistent chat</b><br/>Calls started in private rooms and direct messages will not create a persistent chat discussion, since those discussions are unencrypted. The calls themselves are not affected.",
"Force_Encryption_For_Private_Rooms_Description": "When enabled, all newly created private rooms will be encrypted by default, and users will not be able to disable encryption for them.",
"Force_Screen_Lock": "Force screen lock",
"Force_Screen_Lock_After": "Force screen lock after",
Expand Down
Loading