Skip to content

Commit 204272c

Browse files
KevLehmanggazzomatheusbsilva137
committed
feat!: Allow E2EE rooms to reset its room key (#33328)
Co-authored-by: Guilherme Gazzo <[email protected]> Co-authored-by: Matheus Barbosa Silva <[email protected]>
1 parent e699af9 commit 204272c

File tree

20 files changed

+514
-42
lines changed

20 files changed

+514
-42
lines changed

.changeset/smooth-horses-draw.md

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
"@rocket.chat/meteor": major
3+
"@rocket.chat/core-services": patch
4+
"@rocket.chat/core-typings": patch
5+
"@rocket.chat/ddp-client": patch
6+
"@rocket.chat/i18n": patch
7+
"@rocket.chat/model-typings": patch
8+
"@rocket.chat/rest-typings": patch
9+
---
10+
11+
Allows authorized users to reset the encryption key for end-to-end encrypted rooms. This aims to prevent situations where all users of a room have lost the encryption key, and as such, the access to the room.

apps/meteor/app/api/server/v1/e2e.ts

+42
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,23 @@ import {
77
ise2eUpdateGroupKeyParamsPOST,
88
isE2EProvideUsersGroupKeyProps,
99
isE2EFetchUsersWaitingForGroupKeyProps,
10+
isE2EResetRoomKeyProps,
1011
} from '@rocket.chat/rest-typings';
12+
import ExpiryMap from 'expiry-map';
1113
import { Meteor } from 'meteor/meteor';
1214

15+
import { canAccessRoomIdAsync } from '../../../authorization/server/functions/canAccessRoom';
16+
import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';
1317
import { handleSuggestedGroupKey } from '../../../e2e/server/functions/handleSuggestedGroupKey';
1418
import { provideUsersSuggestedGroupKeys } from '../../../e2e/server/functions/provideUsersSuggestedGroupKeys';
19+
import { resetRoomKey } from '../../../e2e/server/functions/resetRoomKey';
1520
import { settings } from '../../../settings/server';
1621
import { API } from '../api';
1722

23+
// After 10s the room lock will expire, meaning that if for some reason the process never completed
24+
// The next reset will be available 10s after
25+
const LockMap = new ExpiryMap<string, boolean>(10000);
26+
1827
API.v1.addRoute(
1928
'e2e.fetchMyKeys',
2029
{
@@ -284,3 +293,36 @@ API.v1.addRoute(
284293
},
285294
},
286295
);
296+
297+
// This should have permissions
298+
API.v1.addRoute(
299+
'e2e.resetRoomKey',
300+
{ authRequired: true, validateParams: isE2EResetRoomKeyProps },
301+
{
302+
async post() {
303+
const { rid, e2eKey, e2eKeyId } = this.bodyParams;
304+
if (!(await hasPermissionAsync(this.userId, 'toggle-room-e2e-encryption', rid))) {
305+
return API.v1.unauthorized();
306+
}
307+
if (LockMap.has(rid)) {
308+
throw new Error('error-e2e-key-reset-in-progress');
309+
}
310+
311+
LockMap.set(rid, true);
312+
313+
if (!(await canAccessRoomIdAsync(rid, this.userId))) {
314+
throw new Error('error-not-allowed');
315+
}
316+
317+
try {
318+
await resetRoomKey(rid, this.userId, e2eKey, e2eKeyId);
319+
return API.v1.success();
320+
} catch (e) {
321+
console.error(e);
322+
return API.v1.failure('error-e2e-key-reset-failed');
323+
} finally {
324+
LockMap.delete(rid);
325+
}
326+
},
327+
},
328+
);

apps/meteor/app/e2e/client/helper.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,14 @@ export async function generateMnemonicPhrase(n, sep = ' ') {
147147
return result.join(sep);
148148
}
149149

150-
export async function createSha256Hash(data) {
150+
export async function createSha256HashFromText(data) {
151151
const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(data));
152152
return Array.from(new Uint8Array(hash))
153153
.map((b) => b.toString(16).padStart(2, '0'))
154154
.join('');
155155
}
156+
157+
export async function sha256HashFromArrayBuffer(arrayBuffer) {
158+
const hashArray = Array.from(new Uint8Array(await crypto.subtle.digest('SHA-256', arrayBuffer)));
159+
return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
160+
}

0 commit comments

Comments
 (0)