You've already forked matrix-react-sdk
mirror of
https://github.com/matrix-org/matrix-react-sdk.git
synced 2025-08-07 21:23:00 +03:00
Replace uses of checkDeviceTrust
with getDeviceVerificationStatus
(#10663)
matrix-org/matrix-js-sdk#3287 and matrix-org/matrix-js-sdk#3303 added a new API called getDeviceVerificationStatus. Let's use it.
This commit is contained in:
committed by
GitHub
parent
aa8c0f5cc7
commit
d7bb8043ea
@@ -15,10 +15,10 @@ limitations under the License.
|
||||
*/
|
||||
|
||||
import { Mocked, mocked } from "jest-mock";
|
||||
import { MatrixEvent, Room, MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import { MatrixEvent, Room, MatrixClient, DeviceVerificationStatus, CryptoApi } from "matrix-js-sdk/src/matrix";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { DeviceInfo } from "matrix-js-sdk/src/crypto/deviceinfo";
|
||||
import { CrossSigningInfo, DeviceTrustLevel } from "matrix-js-sdk/src/crypto/CrossSigning";
|
||||
import { CrossSigningInfo } from "matrix-js-sdk/src/crypto/CrossSigning";
|
||||
import { CryptoEvent } from "matrix-js-sdk/src/crypto";
|
||||
import { IKeyBackupInfo } from "matrix-js-sdk/src/crypto/keybackup";
|
||||
|
||||
@@ -60,6 +60,7 @@ const flushPromises = async () => await new Promise(process.nextTick);
|
||||
|
||||
describe("DeviceListener", () => {
|
||||
let mockClient: Mocked<MatrixClient> | undefined;
|
||||
let mockCrypto: Mocked<CryptoApi> | undefined;
|
||||
|
||||
// spy on various toasts' hide and show functions
|
||||
// easier than mocking
|
||||
@@ -75,6 +76,11 @@ describe("DeviceListener", () => {
|
||||
mockPlatformPeg({
|
||||
getAppVersion: jest.fn().mockResolvedValue("1.2.3"),
|
||||
});
|
||||
mockCrypto = {
|
||||
getDeviceVerificationStatus: jest.fn().mockResolvedValue({
|
||||
crossSigningVerified: false,
|
||||
}),
|
||||
} as unknown as Mocked<CryptoApi>;
|
||||
mockClient = getMockClientWithEventEmitter({
|
||||
isGuest: jest.fn(),
|
||||
getUserId: jest.fn().mockReturnValue(userId),
|
||||
@@ -97,7 +103,7 @@ describe("DeviceListener", () => {
|
||||
setAccountData: jest.fn(),
|
||||
getAccountData: jest.fn(),
|
||||
deleteAccountData: jest.fn(),
|
||||
checkDeviceTrust: jest.fn().mockReturnValue(new DeviceTrustLevel(false, false, false, false)),
|
||||
getCrypto: jest.fn().mockReturnValue(mockCrypto),
|
||||
});
|
||||
jest.spyOn(MatrixClientPeg, "get").mockReturnValue(mockClient);
|
||||
jest.spyOn(SettingsStore, "getValue").mockReturnValue(false);
|
||||
@@ -391,14 +397,14 @@ describe("DeviceListener", () => {
|
||||
const device2 = new DeviceInfo("d2");
|
||||
const device3 = new DeviceInfo("d3");
|
||||
|
||||
const deviceTrustVerified = new DeviceTrustLevel(true, false, false, false);
|
||||
const deviceTrustUnverified = new DeviceTrustLevel(false, false, false, false);
|
||||
const deviceTrustVerified = new DeviceVerificationStatus({ crossSigningVerified: true });
|
||||
const deviceTrustUnverified = new DeviceVerificationStatus({});
|
||||
|
||||
beforeEach(() => {
|
||||
mockClient!.isCrossSigningReady.mockResolvedValue(true);
|
||||
mockClient!.getStoredDevicesForUser.mockReturnValue([currentDevice, device2, device3]);
|
||||
// all devices verified by default
|
||||
mockClient!.checkDeviceTrust.mockReturnValue(deviceTrustVerified);
|
||||
mockCrypto!.getDeviceVerificationStatus.mockResolvedValue(deviceTrustVerified);
|
||||
mockClient!.deviceId = currentDevice.deviceId;
|
||||
jest.spyOn(SettingsStore, "getValue").mockImplementation(
|
||||
(settingName) => settingName === UIFeature.BulkUnverifiedSessionsReminder,
|
||||
@@ -423,7 +429,7 @@ describe("DeviceListener", () => {
|
||||
jest.spyOn(SettingsStore, "getValue").mockReturnValue(false);
|
||||
// currentDevice, device2 are verified, device3 is unverified
|
||||
// ie if reminder was enabled it should be shown
|
||||
mockClient!.checkDeviceTrust.mockImplementation((_userId, deviceId) => {
|
||||
mockCrypto!.getDeviceVerificationStatus.mockImplementation(async (_userId, deviceId) => {
|
||||
switch (deviceId) {
|
||||
case currentDevice.deviceId:
|
||||
case device2.deviceId:
|
||||
@@ -438,7 +444,7 @@ describe("DeviceListener", () => {
|
||||
|
||||
it("hides toast when current device is unverified", async () => {
|
||||
// device2 verified, current and device3 unverified
|
||||
mockClient!.checkDeviceTrust.mockImplementation((_userId, deviceId) => {
|
||||
mockCrypto!.getDeviceVerificationStatus.mockImplementation(async (_userId, deviceId) => {
|
||||
switch (deviceId) {
|
||||
case device2.deviceId:
|
||||
return deviceTrustVerified;
|
||||
@@ -454,7 +460,7 @@ describe("DeviceListener", () => {
|
||||
it("hides toast when reminder is snoozed", async () => {
|
||||
mocked(isBulkUnverifiedDeviceReminderSnoozed).mockReturnValue(true);
|
||||
// currentDevice, device2 are verified, device3 is unverified
|
||||
mockClient!.checkDeviceTrust.mockImplementation((_userId, deviceId) => {
|
||||
mockCrypto!.getDeviceVerificationStatus.mockImplementation(async (_userId, deviceId) => {
|
||||
switch (deviceId) {
|
||||
case currentDevice.deviceId:
|
||||
case device2.deviceId:
|
||||
@@ -470,7 +476,7 @@ describe("DeviceListener", () => {
|
||||
|
||||
it("shows toast with unverified devices at app start", async () => {
|
||||
// currentDevice, device2 are verified, device3 is unverified
|
||||
mockClient!.checkDeviceTrust.mockImplementation((_userId, deviceId) => {
|
||||
mockCrypto!.getDeviceVerificationStatus.mockImplementation(async (_userId, deviceId) => {
|
||||
switch (deviceId) {
|
||||
case currentDevice.deviceId:
|
||||
case device2.deviceId:
|
||||
@@ -488,7 +494,7 @@ describe("DeviceListener", () => {
|
||||
|
||||
it("hides toast when unverified sessions at app start have been dismissed", async () => {
|
||||
// currentDevice, device2 are verified, device3 is unverified
|
||||
mockClient!.checkDeviceTrust.mockImplementation((_userId, deviceId) => {
|
||||
mockCrypto!.getDeviceVerificationStatus.mockImplementation(async (_userId, deviceId) => {
|
||||
switch (deviceId) {
|
||||
case currentDevice.deviceId:
|
||||
case device2.deviceId:
|
||||
@@ -510,7 +516,7 @@ describe("DeviceListener", () => {
|
||||
|
||||
it("hides toast when unverified sessions are added after app start", async () => {
|
||||
// currentDevice, device2 are verified, device3 is unverified
|
||||
mockClient!.checkDeviceTrust.mockImplementation((_userId, deviceId) => {
|
||||
mockCrypto!.getDeviceVerificationStatus.mockImplementation(async (_userId, deviceId) => {
|
||||
switch (deviceId) {
|
||||
case currentDevice.deviceId:
|
||||
case device2.deviceId:
|
||||
|
@@ -18,9 +18,18 @@ import React from "react";
|
||||
import { fireEvent, render, screen, waitFor, cleanup, act, within } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { Mocked, mocked } from "jest-mock";
|
||||
import { Room, User, MatrixClient, RoomMember, MatrixEvent, EventType } from "matrix-js-sdk/src/matrix";
|
||||
import {
|
||||
Room,
|
||||
User,
|
||||
MatrixClient,
|
||||
RoomMember,
|
||||
MatrixEvent,
|
||||
EventType,
|
||||
CryptoApi,
|
||||
DeviceVerificationStatus,
|
||||
} from "matrix-js-sdk/src/matrix";
|
||||
import { Phase, VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
||||
import { DeviceTrustLevel, UserTrustLevel } from "matrix-js-sdk/src/crypto/CrossSigning";
|
||||
import { UserTrustLevel } from "matrix-js-sdk/src/crypto/CrossSigning";
|
||||
import { DeviceInfo } from "matrix-js-sdk/src/crypto/deviceinfo";
|
||||
import { defer } from "matrix-js-sdk/src/utils";
|
||||
|
||||
@@ -79,6 +88,7 @@ const defaultUser = new User(defaultUserId);
|
||||
let mockRoom: Mocked<Room>;
|
||||
let mockSpace: Mocked<Room>;
|
||||
let mockClient: Mocked<MatrixClient>;
|
||||
let mockCrypto: Mocked<CryptoApi>;
|
||||
|
||||
beforeEach(() => {
|
||||
mockRoom = mocked({
|
||||
@@ -115,6 +125,10 @@ beforeEach(() => {
|
||||
getEventReadUpTo: jest.fn(),
|
||||
} as unknown as Room);
|
||||
|
||||
mockCrypto = mocked({
|
||||
getDeviceVerificationStatus: jest.fn(),
|
||||
} as unknown as CryptoApi);
|
||||
|
||||
mockClient = mocked({
|
||||
getUser: jest.fn(),
|
||||
isGuest: jest.fn().mockReturnValue(false),
|
||||
@@ -134,13 +148,13 @@ beforeEach(() => {
|
||||
currentState: {
|
||||
on: jest.fn(),
|
||||
},
|
||||
checkDeviceTrust: jest.fn(),
|
||||
checkUserTrust: jest.fn(),
|
||||
getRoom: jest.fn(),
|
||||
credentials: {},
|
||||
setPowerLevel: jest.fn(),
|
||||
downloadKeys: jest.fn(),
|
||||
getStoredDevicesForUser: jest.fn(),
|
||||
getCrypto: jest.fn().mockReturnValue(mockCrypto),
|
||||
} as unknown as MatrixClient);
|
||||
|
||||
jest.spyOn(MatrixClientPeg, "get").mockReturnValue(mockClient);
|
||||
@@ -251,7 +265,6 @@ describe("<UserInfo />", () => {
|
||||
beforeEach(() => {
|
||||
mockClient.isCryptoEnabled.mockReturnValue(true);
|
||||
mockClient.checkUserTrust.mockReturnValue(new UserTrustLevel(false, false, false));
|
||||
mockClient.checkDeviceTrust.mockReturnValue(new DeviceTrustLevel(false, false, false, false));
|
||||
|
||||
const device1 = DeviceInfo.fromStorage(
|
||||
{
|
||||
@@ -370,10 +383,10 @@ describe("<DeviceItem />", () => {
|
||||
mockClient.checkUserTrust.mockReturnValue({ isVerified: () => isVerified } as UserTrustLevel);
|
||||
};
|
||||
const setMockDeviceTrust = (isVerified = false, isCrossSigningVerified = false) => {
|
||||
mockClient.checkDeviceTrust.mockReturnValue({
|
||||
mockCrypto.getDeviceVerificationStatus.mockResolvedValue({
|
||||
isVerified: () => isVerified,
|
||||
isCrossSigningVerified: () => isCrossSigningVerified,
|
||||
} as DeviceTrustLevel);
|
||||
crossSigningVerified: isCrossSigningVerified,
|
||||
} as DeviceVerificationStatus);
|
||||
};
|
||||
|
||||
const mockVerifyDevice = jest.spyOn(mockVerification, "verifyDevice");
|
||||
@@ -384,7 +397,7 @@ describe("<DeviceItem />", () => {
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockClient.checkDeviceTrust.mockReset();
|
||||
mockCrypto.getDeviceVerificationStatus.mockReset();
|
||||
mockClient.checkUserTrust.mockReset();
|
||||
mockVerifyDevice.mockClear();
|
||||
});
|
||||
@@ -393,32 +406,36 @@ describe("<DeviceItem />", () => {
|
||||
mockVerifyDevice.mockRestore();
|
||||
});
|
||||
|
||||
it("with unverified user and device, displays button without a label", () => {
|
||||
it("with unverified user and device, displays button without a label", async () => {
|
||||
renderComponent();
|
||||
await act(flushPromises);
|
||||
|
||||
expect(screen.getByRole("button", { name: device.getDisplayName()! })).toBeInTheDocument;
|
||||
expect(screen.queryByText(/trusted/i)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("with verified user only, displays button with a 'Not trusted' label", () => {
|
||||
it("with verified user only, displays button with a 'Not trusted' label", async () => {
|
||||
setMockUserTrust(true);
|
||||
renderComponent();
|
||||
await act(flushPromises);
|
||||
|
||||
expect(screen.getByRole("button", { name: `${device.getDisplayName()} Not trusted` })).toBeInTheDocument;
|
||||
});
|
||||
|
||||
it("with verified device only, displays no button without a label", () => {
|
||||
it("with verified device only, displays no button without a label", async () => {
|
||||
setMockDeviceTrust(true);
|
||||
renderComponent();
|
||||
await act(flushPromises);
|
||||
|
||||
expect(screen.getByText(device.getDisplayName()!)).toBeInTheDocument();
|
||||
expect(screen.queryByText(/trusted/)).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("when userId is the same as userId from client, uses isCrossSigningVerified to determine if button is shown", () => {
|
||||
it("when userId is the same as userId from client, uses isCrossSigningVerified to determine if button is shown", async () => {
|
||||
mockClient.getSafeUserId.mockReturnValueOnce(defaultUserId);
|
||||
mockClient.getUserId.mockReturnValueOnce(defaultUserId);
|
||||
renderComponent();
|
||||
await act(flushPromises);
|
||||
|
||||
// set trust to be false for isVerified, true for isCrossSigningVerified
|
||||
setMockDeviceTrust(false, true);
|
||||
@@ -428,10 +445,11 @@ describe("<DeviceItem />", () => {
|
||||
expect(screen.getByText(device.getDisplayName()!)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("with verified user and device, displays no button and a 'Trusted' label", () => {
|
||||
it("with verified user and device, displays no button and a 'Trusted' label", async () => {
|
||||
setMockUserTrust(true);
|
||||
setMockDeviceTrust(true);
|
||||
renderComponent();
|
||||
await act(flushPromises);
|
||||
|
||||
expect(screen.queryByRole("button")).not.toBeInTheDocument;
|
||||
expect(screen.getByText(device.getDisplayName()!)).toBeInTheDocument();
|
||||
@@ -441,6 +459,7 @@ describe("<DeviceItem />", () => {
|
||||
it("does not call verifyDevice if client.getUser returns null", async () => {
|
||||
mockClient.getUser.mockReturnValueOnce(null);
|
||||
renderComponent();
|
||||
await act(flushPromises);
|
||||
|
||||
const button = screen.getByRole("button", { name: device.getDisplayName()! });
|
||||
expect(button).toBeInTheDocument;
|
||||
@@ -455,6 +474,7 @@ describe("<DeviceItem />", () => {
|
||||
// even more mocking
|
||||
mockClient.isGuest.mockReturnValueOnce(true);
|
||||
renderComponent();
|
||||
await act(flushPromises);
|
||||
|
||||
const button = screen.getByRole("button", { name: device.getDisplayName()! });
|
||||
expect(button).toBeInTheDocument;
|
||||
|
@@ -19,7 +19,7 @@ import { render, waitFor, screen, act, fireEvent } from "@testing-library/react"
|
||||
import { mocked } from "jest-mock";
|
||||
import { EventType } from "matrix-js-sdk/src/@types/event";
|
||||
import { MatrixClient, PendingEventOrdering } from "matrix-js-sdk/src/client";
|
||||
import { TweakName } from "matrix-js-sdk/src/matrix";
|
||||
import { CryptoApi, TweakName } from "matrix-js-sdk/src/matrix";
|
||||
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||
import { NotificationCountType, Room } from "matrix-js-sdk/src/models/room";
|
||||
import { DeviceTrustLevel, UserTrustLevel } from "matrix-js-sdk/src/crypto/CrossSigning";
|
||||
@@ -30,7 +30,7 @@ import EventTile, { EventTileProps } from "../../../../src/components/views/room
|
||||
import MatrixClientContext from "../../../../src/contexts/MatrixClientContext";
|
||||
import RoomContext, { TimelineRenderingType } from "../../../../src/contexts/RoomContext";
|
||||
import { MatrixClientPeg } from "../../../../src/MatrixClientPeg";
|
||||
import { getRoomContext, mkEncryptedEvent, mkEvent, mkMessage, stubClient } from "../../../test-utils";
|
||||
import { flushPromises, getRoomContext, mkEncryptedEvent, mkEvent, mkMessage, stubClient } from "../../../test-utils";
|
||||
import { mkThread } from "../../../test-utils/threads";
|
||||
import DMRoomMap from "../../../../src/utils/DMRoomMap";
|
||||
import dis from "../../../../src/dispatcher/dispatcher";
|
||||
@@ -221,13 +221,16 @@ describe("EventTile", () => {
|
||||
// a version of checkDeviceTrust which says that TRUSTED_DEVICE is trusted, and others are not.
|
||||
const trustedDeviceTrustLevel = DeviceTrustLevel.fromUserTrustLevel(trustedUserTrustLevel, true, false);
|
||||
const untrustedDeviceTrustLevel = DeviceTrustLevel.fromUserTrustLevel(trustedUserTrustLevel, false, false);
|
||||
client.checkDeviceTrust = (userId, deviceId) => {
|
||||
if (deviceId === TRUSTED_DEVICE.deviceId) {
|
||||
return trustedDeviceTrustLevel;
|
||||
} else {
|
||||
return untrustedDeviceTrustLevel;
|
||||
}
|
||||
};
|
||||
const mockCrypto = {
|
||||
getDeviceVerificationStatus: async (userId: string, deviceId: string) => {
|
||||
if (deviceId === TRUSTED_DEVICE.deviceId) {
|
||||
return trustedDeviceTrustLevel;
|
||||
} else {
|
||||
return untrustedDeviceTrustLevel;
|
||||
}
|
||||
},
|
||||
} as unknown as CryptoApi;
|
||||
client.getCrypto = () => mockCrypto;
|
||||
});
|
||||
|
||||
it("shows a warning for an event from an unverified device", async () => {
|
||||
@@ -243,6 +246,7 @@ describe("EventTile", () => {
|
||||
} as IEncryptedEventInfo);
|
||||
|
||||
const { container } = getComponent();
|
||||
await act(flushPromises);
|
||||
|
||||
const eventTiles = container.getElementsByClassName("mx_EventTile");
|
||||
expect(eventTiles).toHaveLength(1);
|
||||
@@ -270,6 +274,7 @@ describe("EventTile", () => {
|
||||
} as IEncryptedEventInfo);
|
||||
|
||||
const { container } = getComponent();
|
||||
await act(flushPromises);
|
||||
|
||||
const eventTiles = container.getElementsByClassName("mx_EventTile");
|
||||
expect(eventTiles).toHaveLength(1);
|
||||
@@ -295,6 +300,7 @@ describe("EventTile", () => {
|
||||
} as IEncryptedEventInfo);
|
||||
|
||||
const { container } = getComponent();
|
||||
await act(flushPromises);
|
||||
|
||||
const eventTiles = container.getElementsByClassName("mx_EventTile");
|
||||
expect(eventTiles).toHaveLength(1);
|
||||
@@ -317,8 +323,9 @@ describe("EventTile", () => {
|
||||
sender: UNTRUSTED_DEVICE,
|
||||
} as IEncryptedEventInfo);
|
||||
|
||||
act(() => {
|
||||
await act(async () => {
|
||||
mxEvent.makeReplaced(replacementEvent);
|
||||
flushPromises();
|
||||
});
|
||||
|
||||
// check it was updated
|
||||
@@ -345,6 +352,7 @@ describe("EventTile", () => {
|
||||
} as IEncryptedEventInfo);
|
||||
|
||||
const { container } = getComponent();
|
||||
await act(flushPromises);
|
||||
|
||||
const eventTiles = container.getElementsByClassName("mx_EventTile");
|
||||
expect(eventTiles).toHaveLength(1);
|
||||
@@ -363,8 +371,9 @@ describe("EventTile", () => {
|
||||
event: true,
|
||||
});
|
||||
|
||||
act(() => {
|
||||
await act(async () => {
|
||||
mxEvent.makeReplaced(replacementEvent);
|
||||
await flushPromises();
|
||||
});
|
||||
|
||||
// check it was updated
|
||||
|
@@ -18,7 +18,6 @@ import { act, fireEvent, render } from "@testing-library/react";
|
||||
import { DeviceInfo } from "matrix-js-sdk/src/crypto/deviceinfo";
|
||||
import { sleep } from "matrix-js-sdk/src/utils";
|
||||
import { PUSHER_DEVICE_ID, PUSHER_ENABLED } from "matrix-js-sdk/src/@types/event";
|
||||
import { DeviceTrustLevel } from "matrix-js-sdk/src/crypto/CrossSigning";
|
||||
|
||||
import DevicesPanel from "../../../../src/components/views/settings/DevicesPanel";
|
||||
import { flushPromises, getMockClientWithEventEmitter, mkPusher, mockClientMethodsUser } from "../../../test-utils";
|
||||
@@ -29,16 +28,21 @@ describe("<DevicesPanel />", () => {
|
||||
const device1 = { device_id: "device_1" };
|
||||
const device2 = { device_id: "device_2" };
|
||||
const device3 = { device_id: "device_3" };
|
||||
const mockCrypto = {
|
||||
getDeviceVerificationStatus: jest.fn().mockResolvedValue({
|
||||
crossSigningVerified: false,
|
||||
}),
|
||||
};
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
...mockClientMethodsUser(userId),
|
||||
getDevices: jest.fn(),
|
||||
getDeviceId: jest.fn().mockReturnValue(device1.device_id),
|
||||
deleteMultipleDevices: jest.fn(),
|
||||
checkDeviceTrust: jest.fn().mockReturnValue(new DeviceTrustLevel(false, false, false, false)),
|
||||
getStoredDevice: jest.fn().mockReturnValue(new DeviceInfo("id")),
|
||||
generateClientSecret: jest.fn(),
|
||||
getPushers: jest.fn(),
|
||||
setPusher: jest.fn(),
|
||||
getCrypto: jest.fn().mockReturnValue(mockCrypto),
|
||||
});
|
||||
|
||||
const getComponent = () => (
|
||||
|
@@ -18,7 +18,6 @@ import React from "react";
|
||||
import { act, fireEvent, render, RenderResult } from "@testing-library/react";
|
||||
import { DeviceInfo } from "matrix-js-sdk/src/crypto/deviceinfo";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { DeviceTrustLevel } from "matrix-js-sdk/src/crypto/CrossSigning";
|
||||
import { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
|
||||
import { defer, sleep } from "matrix-js-sdk/src/utils";
|
||||
import {
|
||||
@@ -30,7 +29,10 @@ import {
|
||||
PUSHER_ENABLED,
|
||||
IAuthData,
|
||||
UNSTABLE_MSC3882_CAPABILITY,
|
||||
CryptoApi,
|
||||
DeviceVerificationStatus,
|
||||
} from "matrix-js-sdk/src/matrix";
|
||||
import { mocked } from "jest-mock";
|
||||
|
||||
import { clearAllModals } from "../../../../../test-utils";
|
||||
import SessionManagerTab from "../../../../../../src/components/views/settings/tabs/user/SessionManagerTab";
|
||||
@@ -78,9 +80,14 @@ describe("<SessionManagerTab />", () => {
|
||||
cancel: jest.fn(),
|
||||
on: jest.fn(),
|
||||
} as unknown as VerificationRequest;
|
||||
|
||||
const mockCrypto = mocked({
|
||||
getDeviceVerificationStatus: jest.fn(),
|
||||
} as unknown as CryptoApi);
|
||||
|
||||
const mockClient = getMockClientWithEventEmitter({
|
||||
...mockClientMethodsUser(aliceId),
|
||||
checkDeviceTrust: jest.fn(),
|
||||
getCrypto: jest.fn().mockReturnValue(mockCrypto),
|
||||
getDevices: jest.fn(),
|
||||
getStoredDevice: jest.fn(),
|
||||
getDeviceId: jest.fn().mockReturnValue(deviceId),
|
||||
@@ -171,7 +178,7 @@ describe("<SessionManagerTab />", () => {
|
||||
const device = [alicesDevice, alicesMobileDevice].find((device) => device.device_id === id);
|
||||
return device ? new DeviceInfo(device.device_id) : null;
|
||||
});
|
||||
mockClient.checkDeviceTrust.mockReset().mockReturnValue(new DeviceTrustLevel(false, false, false, false));
|
||||
mockCrypto.getDeviceVerificationStatus.mockReset().mockResolvedValue(new DeviceVerificationStatus({}));
|
||||
|
||||
mockClient.getDevices.mockReset().mockResolvedValue({ devices: [alicesDevice, alicesMobileDevice] });
|
||||
|
||||
@@ -221,13 +228,13 @@ describe("<SessionManagerTab />", () => {
|
||||
});
|
||||
|
||||
it("does not fail when checking device verification fails", async () => {
|
||||
const logSpy = jest.spyOn(console, "error").mockImplementation(() => {});
|
||||
const logSpy = jest.spyOn(console, "error").mockImplementation((e) => {});
|
||||
mockClient.getDevices.mockResolvedValue({
|
||||
devices: [alicesDevice, alicesMobileDevice],
|
||||
});
|
||||
const noCryptoError = new Error("End-to-end encryption disabled");
|
||||
mockClient.checkDeviceTrust.mockImplementation(() => {
|
||||
throw noCryptoError;
|
||||
const failError = new Error("non-specific failure");
|
||||
mockCrypto.getDeviceVerificationStatus.mockImplementation(() => {
|
||||
throw failError;
|
||||
});
|
||||
render(getComponent());
|
||||
|
||||
@@ -236,9 +243,9 @@ describe("<SessionManagerTab />", () => {
|
||||
});
|
||||
|
||||
// called for each device despite error
|
||||
expect(mockClient.checkDeviceTrust).toHaveBeenCalledWith(aliceId, alicesDevice.device_id);
|
||||
expect(mockClient.checkDeviceTrust).toHaveBeenCalledWith(aliceId, alicesMobileDevice.device_id);
|
||||
expect(logSpy).toHaveBeenCalledWith("Error getting device cross-signing info", noCryptoError);
|
||||
expect(mockCrypto.getDeviceVerificationStatus).toHaveBeenCalledWith(aliceId, alicesDevice.device_id);
|
||||
expect(mockCrypto.getDeviceVerificationStatus).toHaveBeenCalledWith(aliceId, alicesMobileDevice.device_id);
|
||||
expect(logSpy).toHaveBeenCalledWith("Error getting device cross-signing info", failError);
|
||||
});
|
||||
|
||||
it("sets device verification status correctly", async () => {
|
||||
@@ -246,14 +253,14 @@ describe("<SessionManagerTab />", () => {
|
||||
devices: [alicesDevice, alicesMobileDevice, alicesOlderMobileDevice],
|
||||
});
|
||||
mockClient.getStoredDevice.mockImplementation((_userId, deviceId) => new DeviceInfo(deviceId));
|
||||
mockClient.checkDeviceTrust.mockImplementation((_userId, deviceId) => {
|
||||
mockCrypto.getDeviceVerificationStatus.mockImplementation(async (_userId, deviceId) => {
|
||||
// alices device is trusted
|
||||
if (deviceId === alicesDevice.device_id) {
|
||||
return new DeviceTrustLevel(true, true, false, false);
|
||||
return new DeviceVerificationStatus({ crossSigningVerified: true, localVerified: true });
|
||||
}
|
||||
// alices mobile device is not
|
||||
if (deviceId === alicesMobileDevice.device_id) {
|
||||
return new DeviceTrustLevel(false, false, false, false);
|
||||
return new DeviceVerificationStatus({});
|
||||
}
|
||||
// alicesOlderMobileDevice does not support encryption
|
||||
throw new Error("encryption not supported");
|
||||
@@ -265,7 +272,7 @@ describe("<SessionManagerTab />", () => {
|
||||
await flushPromises();
|
||||
});
|
||||
|
||||
expect(mockClient.checkDeviceTrust).toHaveBeenCalledTimes(3);
|
||||
expect(mockCrypto.getDeviceVerificationStatus).toHaveBeenCalledTimes(3);
|
||||
expect(
|
||||
getByTestId(`device-tile-${alicesDevice.device_id}`).querySelector('[aria-label="Verified"]'),
|
||||
).toBeTruthy();
|
||||
@@ -418,7 +425,9 @@ describe("<SessionManagerTab />", () => {
|
||||
devices: [alicesDevice, alicesMobileDevice],
|
||||
});
|
||||
mockClient.getStoredDevice.mockImplementation(() => new DeviceInfo(alicesDevice.device_id));
|
||||
mockClient.checkDeviceTrust.mockReturnValue(new DeviceTrustLevel(true, true, false, false));
|
||||
mockCrypto.getDeviceVerificationStatus.mockResolvedValue(
|
||||
new DeviceVerificationStatus({ crossSigningVerified: true, localVerified: true }),
|
||||
);
|
||||
|
||||
const { getByTestId } = render(getComponent());
|
||||
|
||||
@@ -520,11 +529,11 @@ describe("<SessionManagerTab />", () => {
|
||||
devices: [alicesDevice, alicesMobileDevice],
|
||||
});
|
||||
mockClient.getStoredDevice.mockImplementation((_userId, deviceId) => new DeviceInfo(deviceId));
|
||||
mockClient.checkDeviceTrust.mockImplementation((_userId, deviceId) => {
|
||||
mockCrypto.getDeviceVerificationStatus.mockImplementation(async (_userId, deviceId) => {
|
||||
if (deviceId === alicesDevice.device_id) {
|
||||
return new DeviceTrustLevel(true, true, false, false);
|
||||
return new DeviceVerificationStatus({ crossSigningVerified: true, localVerified: true });
|
||||
}
|
||||
return new DeviceTrustLevel(false, false, false, false);
|
||||
return new DeviceVerificationStatus({});
|
||||
});
|
||||
|
||||
const { getByTestId } = render(getComponent());
|
||||
@@ -547,12 +556,13 @@ describe("<SessionManagerTab />", () => {
|
||||
devices: [alicesDevice, alicesMobileDevice],
|
||||
});
|
||||
mockClient.getStoredDevice.mockImplementation((_userId, deviceId) => new DeviceInfo(deviceId));
|
||||
mockClient.checkDeviceTrust.mockImplementation((_userId, deviceId) => {
|
||||
mockCrypto.getDeviceVerificationStatus.mockImplementation(async (_userId, deviceId) => {
|
||||
// current session verified = able to verify other sessions
|
||||
if (deviceId === alicesDevice.device_id) {
|
||||
return new DeviceTrustLevel(true, true, false, false);
|
||||
return new DeviceVerificationStatus({ crossSigningVerified: true, localVerified: true });
|
||||
}
|
||||
// but alicesMobileDevice doesn't support encryption
|
||||
// XXX this is not what happens if a device doesn't support encryption.
|
||||
throw new Error("encryption not supported");
|
||||
});
|
||||
|
||||
@@ -581,11 +591,11 @@ describe("<SessionManagerTab />", () => {
|
||||
devices: [alicesDevice, alicesMobileDevice],
|
||||
});
|
||||
mockClient.getStoredDevice.mockImplementation((_userId, deviceId) => new DeviceInfo(deviceId));
|
||||
mockClient.checkDeviceTrust.mockImplementation((_userId, deviceId) => {
|
||||
mockCrypto.getDeviceVerificationStatus.mockImplementation(async (_userId, deviceId) => {
|
||||
if (deviceId === alicesDevice.device_id) {
|
||||
return new DeviceTrustLevel(true, true, false, false);
|
||||
return new DeviceVerificationStatus({ crossSigningVerified: true, localVerified: true });
|
||||
}
|
||||
return new DeviceTrustLevel(false, false, false, false);
|
||||
return new DeviceVerificationStatus({});
|
||||
});
|
||||
|
||||
const { getByTestId } = render(getComponent());
|
||||
|
@@ -99,7 +99,6 @@ export function createTestClient(): MatrixClient {
|
||||
getDevice: jest.fn(),
|
||||
getDeviceId: jest.fn().mockReturnValue("ABCDEFGHI"),
|
||||
getStoredCrossSigningForUser: jest.fn(),
|
||||
checkDeviceTrust: jest.fn(),
|
||||
getStoredDevice: jest.fn(),
|
||||
requestVerification: jest.fn(),
|
||||
deviceId: "ABCDEFGHI",
|
||||
@@ -234,6 +233,7 @@ export function createTestClient(): MatrixClient {
|
||||
}),
|
||||
|
||||
searchUserDirectory: jest.fn().mockResolvedValue({ limited: false, results: [] }),
|
||||
getCrypto: jest.fn(),
|
||||
} as unknown as MatrixClient;
|
||||
|
||||
client.reEmitter = new ReEmitter(client);
|
||||
|
@@ -18,9 +18,8 @@ import React from "react";
|
||||
import { render, RenderResult, screen } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
import { mocked, Mocked } from "jest-mock";
|
||||
import { IMyDevice, MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import { CryptoApi, DeviceVerificationStatus, IMyDevice, MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import { DeviceInfo } from "matrix-js-sdk/src/crypto/deviceinfo";
|
||||
import { DeviceTrustLevel } from "matrix-js-sdk/src/crypto/CrossSigning";
|
||||
|
||||
import dis from "../../src/dispatcher/dispatcher";
|
||||
import { showToast } from "../../src/toasts/UnverifiedSessionToast";
|
||||
@@ -55,7 +54,11 @@ describe("UnverifiedSessionToast", () => {
|
||||
|
||||
return null;
|
||||
});
|
||||
client.checkDeviceTrust.mockReturnValue(new DeviceTrustLevel(true, false, false, false));
|
||||
client.getCrypto.mockReturnValue({
|
||||
getDeviceVerificationStatus: jest
|
||||
.fn()
|
||||
.mockResolvedValue(new DeviceVerificationStatus({ crossSigningVerified: true })),
|
||||
} as unknown as CryptoApi);
|
||||
jest.spyOn(dis, "dispatch");
|
||||
jest.spyOn(DeviceListener.sharedInstance(), "dismissUnverifiedSessions");
|
||||
});
|
||||
|
@@ -22,21 +22,25 @@ import DMRoomMap from "../../src/utils/DMRoomMap";
|
||||
function mkClient(selfTrust = false) {
|
||||
return {
|
||||
getUserId: () => "@self:localhost",
|
||||
getCrypto: () => ({
|
||||
getDeviceVerificationStatus: (userId: string, deviceId: string) =>
|
||||
Promise.resolve({
|
||||
isVerified: () => (userId === "@self:localhost" ? selfTrust : userId[2] == "T"),
|
||||
}),
|
||||
}),
|
||||
checkUserTrust: (userId: string) => ({
|
||||
isCrossSigningVerified: () => userId[1] == "T",
|
||||
wasCrossSigningVerified: () => userId[1] == "T" || userId[1] == "W",
|
||||
}),
|
||||
checkDeviceTrust: (userId: string, deviceId: string) => ({
|
||||
isVerified: () => (userId === "@self:localhost" ? selfTrust : userId[2] == "T"),
|
||||
}),
|
||||
getStoredDevicesForUser: (userId: string) => ["DEVICE"],
|
||||
} as unknown as MatrixClient;
|
||||
}
|
||||
|
||||
describe("mkClient self-test", function () {
|
||||
test.each([true, false])("behaves well for self-trust=%s", (v) => {
|
||||
test.each([true, false])("behaves well for self-trust=%s", async (v) => {
|
||||
const client = mkClient(v);
|
||||
expect(client.checkDeviceTrust("@self:localhost", "DEVICE").isVerified()).toBe(v);
|
||||
const status = await client.getCrypto()!.getDeviceVerificationStatus("@self:localhost", "DEVICE");
|
||||
expect(status?.isVerified()).toBe(v);
|
||||
});
|
||||
|
||||
test.each([
|
||||
@@ -53,8 +57,9 @@ describe("mkClient self-test", function () {
|
||||
["@TF:h", false],
|
||||
["@FT:h", true],
|
||||
["@FF:h", false],
|
||||
])("behaves well for device trust %s", (userId, trust) => {
|
||||
expect(mkClient().checkDeviceTrust(userId, "device").isVerified()).toBe(trust);
|
||||
])("behaves well for device trust %s", async (userId, trust) => {
|
||||
const status = await mkClient().getCrypto()!.getDeviceVerificationStatus(userId, "device");
|
||||
expect(status?.isVerified()).toBe(trust);
|
||||
});
|
||||
});
|
||||
|
||||
|
@@ -30,6 +30,7 @@ import {
|
||||
GroupedArray,
|
||||
concat,
|
||||
asyncEvery,
|
||||
asyncSome,
|
||||
} from "../../src/utils/arrays";
|
||||
|
||||
type TestParams = { input: number[]; output: number[] };
|
||||
@@ -444,4 +445,27 @@ describe("arrays", () => {
|
||||
expect(predicate).toHaveBeenCalledWith(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("asyncSome", () => {
|
||||
it("when called with an empty array, it should return false", async () => {
|
||||
expect(await asyncSome([], jest.fn().mockResolvedValue(true))).toBe(false);
|
||||
});
|
||||
|
||||
it("when called with some items and the predicate resolves to false for all of them, it should return false", async () => {
|
||||
const predicate = jest.fn().mockResolvedValue(false);
|
||||
expect(await asyncSome([1, 2, 3], predicate)).toBe(false);
|
||||
expect(predicate).toHaveBeenCalledTimes(3);
|
||||
expect(predicate).toHaveBeenCalledWith(1);
|
||||
expect(predicate).toHaveBeenCalledWith(2);
|
||||
expect(predicate).toHaveBeenCalledWith(3);
|
||||
});
|
||||
|
||||
it("when called with some items and the predicate resolves to true, it should short-circuit and return true", async () => {
|
||||
const predicate = jest.fn().mockResolvedValueOnce(false).mockResolvedValueOnce(true);
|
||||
expect(await asyncSome([1, 2, 3], predicate)).toBe(true);
|
||||
expect(predicate).toHaveBeenCalledTimes(2);
|
||||
expect(predicate).toHaveBeenCalledWith(1);
|
||||
expect(predicate).toHaveBeenCalledWith(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user