Skip to content

Commit 5508993

Browse files
committed
Merge branch 'master' into develop
2 parents b842192 + c9b43ab commit 5508993

File tree

5 files changed

+12
-111
lines changed

5 files changed

+12
-111
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
Changes in [34.8.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.8.0) (2024-10-15)
2+
==================================================================================================
3+
This release removes insecure functionality, resolving CVE-2024-47080 / GHSA-4jf8-g8wp-cx7c.
4+
15
Changes in [34.7.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.7.0) (2024-10-08)
26
==================================================================================================
37
## 🦖 Deprecations

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "matrix-js-sdk",
3-
"version": "34.7.0",
3+
"version": "34.8.0",
44
"description": "Matrix Client-Server SDK for Javascript",
55
"engines": {
66
"node": ">=20.0.0"

spec/unit/models/MSC3089TreeSpace.spec.ts

Lines changed: 4 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ describe("MSC3089TreeSpace", () => {
107107
return Promise.resolve();
108108
});
109109
client.invite = fn;
110-
await tree.invite(target, false, false);
110+
await tree.invite(target, false);
111111
expect(fn).toHaveBeenCalledTimes(1);
112112
});
113113

@@ -120,7 +120,7 @@ describe("MSC3089TreeSpace", () => {
120120
return Promise.resolve();
121121
});
122122
client.invite = fn;
123-
await tree.invite(target, false, false);
123+
await tree.invite(target, false);
124124
expect(fn).toHaveBeenCalledTimes(2);
125125
});
126126

@@ -133,7 +133,7 @@ describe("MSC3089TreeSpace", () => {
133133
});
134134
client.invite = fn;
135135

136-
await expect(tree.invite(target, false, false)).rejects.toThrow("MatrixError: Sample Failure");
136+
await expect(tree.invite(target, false)).rejects.toThrow("MatrixError: Sample Failure");
137137

138138
expect(fn).toHaveBeenCalledTimes(1);
139139
});
@@ -155,61 +155,10 @@ describe("MSC3089TreeSpace", () => {
155155
{ invite: (userId) => fn(tree.roomId, userId) } as MSC3089TreeSpace,
156156
];
157157

158-
await tree.invite(target, true, false);
158+
await tree.invite(target, true);
159159
expect(fn).toHaveBeenCalledTimes(4);
160160
});
161161

162-
it("should share keys with invitees", async () => {
163-
const target = targetUser;
164-
const sendKeysFn = jest.fn().mockImplementation((inviteRoomId: string, userIds: string[]) => {
165-
expect(inviteRoomId).toEqual(roomId);
166-
expect(userIds).toMatchObject([target]);
167-
return Promise.resolve();
168-
});
169-
client.invite = () => Promise.resolve({}); // we're not testing this here - see other tests
170-
client.sendSharedHistoryKeys = sendKeysFn;
171-
172-
// Mock the history check as best as possible
173-
const historyVis = "shared";
174-
const historyFn = jest.fn().mockImplementation((eventType: string, stateKey?: string) => {
175-
// We're not expecting a super rigid test: the function that calls this internally isn't
176-
// really being tested here.
177-
expect(eventType).toEqual(EventType.RoomHistoryVisibility);
178-
expect(stateKey).toEqual("");
179-
return { getContent: () => ({ history_visibility: historyVis }) }; // eslint-disable-line camelcase
180-
});
181-
room.currentState.getStateEvents = historyFn;
182-
183-
// Note: inverse test is implicit from other tests, which disable the call stack of this
184-
// test in order to pass.
185-
await tree.invite(target, false, true);
186-
expect(sendKeysFn).toHaveBeenCalledTimes(1);
187-
expect(historyFn).toHaveBeenCalledTimes(1);
188-
});
189-
190-
it("should not share keys with invitees if inappropriate history visibility", async () => {
191-
const target = targetUser;
192-
const sendKeysFn = jest.fn().mockImplementation((inviteRoomId: string, userIds: string[]) => {
193-
expect(inviteRoomId).toEqual(roomId);
194-
expect(userIds).toMatchObject([target]);
195-
return Promise.resolve();
196-
});
197-
client.invite = () => Promise.resolve({}); // we're not testing this here - see other tests
198-
client.sendSharedHistoryKeys = sendKeysFn;
199-
200-
const historyVis = "joined"; // NOTE: Changed.
201-
const historyFn = jest.fn().mockImplementation((eventType: string, stateKey?: string) => {
202-
expect(eventType).toEqual(EventType.RoomHistoryVisibility);
203-
expect(stateKey).toEqual("");
204-
return { getContent: () => ({ history_visibility: historyVis }) }; // eslint-disable-line camelcase
205-
});
206-
room.currentState.getStateEvents = historyFn;
207-
208-
await tree.invite(target, false, true);
209-
expect(sendKeysFn).toHaveBeenCalledTimes(0);
210-
expect(historyFn).toHaveBeenCalledTimes(1);
211-
});
212-
213162
async function evaluatePowerLevels(pls: any, role: TreePermissions, expectedPl: number) {
214163
makePowerLevels(pls);
215164
const fn = jest

src/client.ts

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4085,43 +4085,6 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
40854085
await this.http.authedRequest(Method.Delete, path.path, path.queryData, undefined, { prefix: ClientPrefix.V3 });
40864086
}
40874087

4088-
/**
4089-
* Share shared-history decryption keys with the given users.
4090-
*
4091-
* @param roomId - the room for which keys should be shared.
4092-
* @param userIds - a list of users to share with. The keys will be sent to
4093-
* all of the user's current devices.
4094-
*
4095-
* @deprecated Do not use this method. It does not work with the Rust crypto stack, and even with the legacy
4096-
* stack it introduces a security vulnerability.
4097-
*/
4098-
public async sendSharedHistoryKeys(roomId: string, userIds: string[]): Promise<void> {
4099-
if (!this.crypto) {
4100-
throw new Error("End-to-end encryption disabled");
4101-
}
4102-
4103-
const roomEncryption = this.crypto?.getRoomEncryption(roomId);
4104-
if (!roomEncryption) {
4105-
// unknown room, or unencrypted room
4106-
this.logger.error("Unknown room. Not sharing decryption keys");
4107-
return;
4108-
}
4109-
4110-
const deviceInfos = await this.crypto.downloadKeys(userIds);
4111-
const devicesByUser: Map<string, DeviceInfo[]> = new Map();
4112-
for (const [userId, devices] of deviceInfos) {
4113-
devicesByUser.set(userId, Array.from(devices.values()));
4114-
}
4115-
4116-
// XXX: Private member access
4117-
const alg = this.crypto.getRoomDecryptor(roomId, roomEncryption.algorithm);
4118-
if (alg.sendSharedHistoryInboundSessions) {
4119-
await alg.sendSharedHistoryInboundSessions(devicesByUser);
4120-
} else {
4121-
this.logger.warn("Algorithm does not support sharing previous keys", roomEncryption.algorithm);
4122-
}
4123-
}
4124-
41254088
/**
41264089
* Get the config for the media repository.
41274090
* @returns Promise which resolves with an object containing the config.

src/models/MSC3089TreeSpace.ts

Lines changed: 3 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ import {
3030
simpleRetryOperation,
3131
} from "../utils.ts";
3232
import { MSC3089Branch } from "./MSC3089Branch.ts";
33-
import { isRoomSharedHistory } from "../crypto/algorithms/megolm.ts";
3433
import { ISendEventResponse } from "../@types/requests.ts";
3534
import { FileType } from "../http-api/index.ts";
3635
import { KnownMembership } from "../@types/membership.ts";
@@ -136,28 +135,14 @@ export class MSC3089TreeSpace {
136135
* @param userId - The user ID to invite.
137136
* @param andSubspaces - True (default) to invite the user to all
138137
* directories/subspaces too, recursively.
139-
* @param shareHistoryKeys - True (default) to share encryption keys
140-
* with the invited user. This will allow them to decrypt the events (files)
141-
* in the tree. Keys will not be shared if the room is lacking appropriate
142-
* history visibility (by default, history visibility is "shared" in trees,
143-
* which is an appropriate visibility for these purposes).
144138
* @returns Promise which resolves when complete.
145139
*/
146-
public async invite(userId: string, andSubspaces = true, shareHistoryKeys = true): Promise<void> {
140+
public async invite(userId: string, andSubspaces = true): Promise<void> {
147141
const promises: Promise<void>[] = [this.retryInvite(userId)];
148142
if (andSubspaces) {
149-
promises.push(...this.getDirectories().map((d) => d.invite(userId, andSubspaces, shareHistoryKeys)));
143+
promises.push(...this.getDirectories().map((d) => d.invite(userId, andSubspaces)));
150144
}
151-
return Promise.all(promises).then(() => {
152-
// Note: key sharing is default on because for file trees it is relatively important that the invite
153-
// target can actually decrypt the files. The implied use case is that by inviting a user to the tree
154-
// it means the sender would like the receiver to view/download the files contained within, much like
155-
// sharing a folder in other circles.
156-
if (shareHistoryKeys && isRoomSharedHistory(this.room)) {
157-
// noinspection JSIgnoredPromiseFromCall - we aren't concerned as much if this fails.
158-
this.client.sendSharedHistoryKeys(this.roomId, [userId]);
159-
}
160-
});
145+
await Promise.all(promises);
161146
}
162147

163148
private retryInvite(userId: string): Promise<void> {

0 commit comments

Comments
 (0)