Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 579b0dd

Browse files
authored
ElementR: Cross user verification (#11364)
The hard work has been done in previous PRs in the js-sdk, so this is now just a case of updating a few call sites to use the new APIs.
1 parent e887c6d commit 579b0dd

File tree

8 files changed

+33
-31
lines changed

8 files changed

+33
-31
lines changed

cypress/e2e/crypto/crypto.spec.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ describe("Cryptography", function () {
259259
}
260260

261261
it("creating a DM should work, being e2e-encrypted / user verification", function (this: CryptoTestContext) {
262-
skipIfRustCrypto();
262+
skipIfRustCrypto(); // needs working event shields
263263
cy.bootstrapCrossSigning(aliceCredentials);
264264
startDMWithBob.call(this);
265265
// send first message
@@ -281,7 +281,6 @@ describe("Cryptography", function () {
281281
});
282282

283283
it("should allow verification when there is no existing DM", function (this: CryptoTestContext) {
284-
skipIfRustCrypto();
285284
cy.bootstrapCrossSigning(aliceCredentials);
286285
autoJoin(this.bob);
287286

src/DeviceListener.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ export default class DeviceListener {
307307

308308
// cross signing isn't enabled - nag to enable it
309309
// There are 3 different toasts for:
310-
if (!(await crypto.getCrossSigningKeyId()) && cli.getStoredCrossSigningForUser(cli.getSafeUserId())) {
310+
if (!(await crypto.getCrossSigningKeyId()) && (await crypto.userHasCrossSigningKeys())) {
311311
// Cross-signing on account but this device doesn't trust the master key (verify this session)
312312
showSetupEncryptionToast(SetupKind.VERIFY_THIS_SESSION);
313313
this.checkKeyBackupStatus();

src/components/views/right_panel/EncryptionPanel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ const EncryptionPanel: React.FC<IProps> = (props: IProps) => {
110110
if (!roomId) {
111111
throw new Error("Unable to create Room for verification");
112112
}
113-
verificationRequest_ = await cli.requestVerificationDM(member.userId, roomId);
113+
verificationRequest_ = await cli.getCrypto()!.requestVerificationDM(member.userId, roomId);
114114
} catch (e) {
115115
console.error("Error starting verification", e);
116116
setRequesting(false);

src/components/views/right_panel/UserInfo.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,15 @@ export const disambiguateDevices = (devices: IDevice[]): void => {
105105
}
106106
};
107107

108-
export const getE2EStatus = async (cli: MatrixClient, userId: string, devices: IDevice[]): Promise<E2EStatus> => {
108+
export const getE2EStatus = async (
109+
cli: MatrixClient,
110+
userId: string,
111+
devices: IDevice[],
112+
): Promise<E2EStatus | undefined> => {
113+
const crypto = cli.getCrypto();
114+
if (!crypto) return undefined;
109115
const isMe = userId === cli.getUserId();
110-
const userTrust = cli.checkUserTrust(userId);
116+
const userTrust = await crypto.getUserVerificationStatus(userId);
111117
if (!userTrust.isCrossSigningVerified()) {
112118
return userTrust.wasCrossSigningVerified() ? E2EStatus.Warning : E2EStatus.Normal;
113119
}
@@ -119,7 +125,7 @@ export const getE2EStatus = async (cli: MatrixClient, userId: string, devices: I
119125
// cross-signing so that other users can then safely trust you.
120126
// For other people's devices, the more general verified check that
121127
// includes locally verified devices can be used.
122-
const deviceTrust = await cli.getCrypto()?.getDeviceVerificationStatus(userId, deviceId);
128+
const deviceTrust = await crypto.getDeviceVerificationStatus(userId, deviceId);
123129
return isMe ? !deviceTrust?.crossSigningVerified : !deviceTrust?.isVerified();
124130
});
125131
return anyDeviceUnverified ? E2EStatus.Warning : E2EStatus.Verified;
@@ -152,11 +158,7 @@ function useHasCrossSigningKeys(
152158
}
153159
setUpdating(true);
154160
try {
155-
// We call it to populate the user keys and devices
156-
await cli.getCrypto()?.getUserDeviceInfo([member.userId], true);
157-
const xsi = cli.getStoredCrossSigningForUser(member.userId);
158-
const key = xsi && xsi.getId();
159-
return !!key;
161+
return await cli.getCrypto()?.userHasCrossSigningKeys(member.userId, true);
160162
} finally {
161163
setUpdating(false);
162164
}

src/utils/ShieldUtils.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,15 @@ export async function shieldStatusForRoom(client: MatrixClient, room: Room): Pro
3737

3838
const verified: string[] = [];
3939
const unverified: string[] = [];
40-
members
41-
.filter((userId) => userId !== client.getUserId())
42-
.forEach((userId) => {
43-
(client.checkUserTrust(userId).isCrossSigningVerified() ? verified : unverified).push(userId);
44-
});
40+
for (const userId of members) {
41+
if (userId === client.getUserId()) continue;
42+
const userTrust = await crypto.getUserVerificationStatus(userId);
4543

46-
/* Alarm if any unverified users were verified before. */
47-
for (const userId of unverified) {
48-
if (client.checkUserTrust(userId).wasCrossSigningVerified()) {
44+
/* Alarm if any unverified users were verified before. */
45+
if (userTrust.wasCrossSigningVerified() && !userTrust.isCrossSigningVerified()) {
4946
return E2EStatus.Warning;
5047
}
48+
(userTrust.isCrossSigningVerified() ? verified : unverified).push(userId);
5149
}
5250

5351
/* Check all verified user devices. */

test/DeviceListener-test.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import {
2525
ClientStoppedError,
2626
} from "matrix-js-sdk/src/matrix";
2727
import { logger } from "matrix-js-sdk/src/logger";
28-
import { CrossSigningInfo } from "matrix-js-sdk/src/crypto/CrossSigning";
2928
import { CryptoEvent } from "matrix-js-sdk/src/crypto";
3029
import { IKeyBackupInfo } from "matrix-js-sdk/src/crypto/keybackup";
3130

@@ -92,6 +91,7 @@ describe("DeviceListener", () => {
9291
getUserDeviceInfo: jest.fn().mockResolvedValue(new Map()),
9392
isCrossSigningReady: jest.fn().mockResolvedValue(true),
9493
isSecretStorageReady: jest.fn().mockResolvedValue(true),
94+
userHasCrossSigningKeys: jest.fn(),
9595
} as unknown as Mocked<CryptoApi>;
9696
mockClient = getMockClientWithEventEmitter({
9797
isGuest: jest.fn(),
@@ -102,7 +102,6 @@ describe("DeviceListener", () => {
102102
isVersionSupported: jest.fn().mockResolvedValue(true),
103103
isInitialSyncComplete: jest.fn().mockReturnValue(true),
104104
getKeyBackupEnabled: jest.fn(),
105-
getStoredCrossSigningForUser: jest.fn(),
106105
waitForClientWellKnown: jest.fn(),
107106
isRoomEncrypted: jest.fn(),
108107
getClientWellKnown: jest.fn(),
@@ -324,7 +323,7 @@ describe("DeviceListener", () => {
324323
});
325324

326325
it("shows verify session toast when account has cross signing", async () => {
327-
mockClient!.getStoredCrossSigningForUser.mockReturnValue(new CrossSigningInfo(userId));
326+
mockCrypto!.userHasCrossSigningKeys.mockResolvedValue(true);
328327
await createAndStart();
329328

330329
expect(mockCrypto!.getUserDeviceInfo).toHaveBeenCalled();
@@ -335,7 +334,7 @@ describe("DeviceListener", () => {
335334

336335
it("checks key backup status when when account has cross signing", async () => {
337336
mockCrypto!.getCrossSigningKeyId.mockResolvedValue(null);
338-
mockClient!.getStoredCrossSigningForUser.mockReturnValue(new CrossSigningInfo(userId));
337+
mockCrypto!.userHasCrossSigningKeys.mockResolvedValue(true);
339338
await createAndStart();
340339

341340
expect(mockClient!.getKeyBackupEnabled).toHaveBeenCalled();

test/components/views/right_panel/UserInfo-test.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import {
3737
import { UserTrustLevel } from "matrix-js-sdk/src/crypto/CrossSigning";
3838
import { defer } from "matrix-js-sdk/src/utils";
3939
import { EventEmitter } from "events";
40+
import { UserVerificationStatus } from "matrix-js-sdk/src/crypto-api";
4041

4142
import UserInfo, {
4243
BanToggleButton,
@@ -134,6 +135,8 @@ beforeEach(() => {
134135
mockCrypto = mocked({
135136
getDeviceVerificationStatus: jest.fn(),
136137
getUserDeviceInfo: jest.fn(),
138+
userHasCrossSigningKeys: jest.fn().mockResolvedValue(false),
139+
getUserVerificationStatus: jest.fn(),
137140
} as unknown as CryptoApi);
138141

139142
mockClient = mocked({
@@ -161,7 +164,6 @@ beforeEach(() => {
161164
setPowerLevel: jest.fn(),
162165
downloadKeys: jest.fn(),
163166
getCrypto: jest.fn().mockReturnValue(mockCrypto),
164-
getStoredCrossSigningForUser: jest.fn(),
165167
} as unknown as MatrixClient);
166168

167169
jest.spyOn(MatrixClientPeg, "get").mockReturnValue(mockClient);
@@ -378,6 +380,7 @@ describe("<UserInfo />", () => {
378380

379381
it("renders unverified user info", async () => {
380382
mockClient.checkUserTrust.mockReturnValue(new UserTrustLevel(false, false, false));
383+
mockCrypto.getUserVerificationStatus.mockResolvedValue(new UserVerificationStatus(false, false, false));
381384
renderComponent({ room: mockRoom });
382385
await act(flushPromises);
383386

@@ -389,6 +392,7 @@ describe("<UserInfo />", () => {
389392

390393
it("renders verified user info", async () => {
391394
mockClient.checkUserTrust.mockReturnValue(new UserTrustLevel(true, false, false));
395+
mockCrypto.getUserVerificationStatus.mockResolvedValue(new UserVerificationStatus(true, false, false));
392396
renderComponent({ room: mockRoom });
393397
await act(flushPromises);
394398

test/utils/ShieldUtils-test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ limitations under the License.
1515
*/
1616

1717
import { MatrixClient, Room } from "matrix-js-sdk/src/matrix";
18+
import { UserVerificationStatus } from "matrix-js-sdk/src/crypto-api";
1819

1920
import { shieldStatusForRoom } from "../../src/utils/ShieldUtils";
2021
import DMRoomMap from "../../src/utils/DMRoomMap";
@@ -30,10 +31,8 @@ function mkClient(selfTrust = false) {
3031
getUserDeviceInfo: async (userIds: string[]) => {
3132
return new Map(userIds.map((u) => [u, new Map([["DEVICE", {}]])]));
3233
},
33-
}),
34-
checkUserTrust: (userId: string) => ({
35-
isCrossSigningVerified: () => userId[1] == "T",
36-
wasCrossSigningVerified: () => userId[1] == "T" || userId[1] == "W",
34+
getUserVerificationStatus: async (userId: string): Promise<UserVerificationStatus> =>
35+
new UserVerificationStatus(userId[1] == "T", userId[1] == "T" || userId[1] == "W", false),
3736
}),
3837
} as unknown as MatrixClient;
3938
}
@@ -50,8 +49,9 @@ describe("mkClient self-test", function () {
5049
["@TF:h", true],
5150
["@FT:h", false],
5251
["@FF:h", false],
53-
])("behaves well for user trust %s", (userId, trust) => {
54-
expect(mkClient().checkUserTrust(userId).isCrossSigningVerified()).toBe(trust);
52+
])("behaves well for user trust %s", async (userId, trust) => {
53+
const status = await mkClient().getCrypto()?.getUserVerificationStatus(userId);
54+
expect(status!.isCrossSigningVerified()).toBe(trust);
5555
});
5656

5757
test.each([

0 commit comments

Comments
 (0)