DeviceListener
: use new getUserDeviceInfo
method (#10826)
* DeviceListener: use new `getUserDeviceInfo` method https://github.com/matrix-org/matrix-js-sdk/pull/3272 added a new `CryptoApi.getUserDeviceInfo` method, which also works with rust crypto. Update DeviceListener to use it, thus making many of the cypress tests work on Element Web R. * add missing await ... mostly to silence the quality gate
This commit is contained in:
parent
339e7dab18
commit
5e8488c283
2 changed files with 41 additions and 23 deletions
|
@ -149,13 +149,26 @@ export default class DeviceListener {
|
||||||
this.recheck();
|
this.recheck();
|
||||||
}
|
}
|
||||||
|
|
||||||
private ensureDeviceIdsAtStartPopulated(): void {
|
private async ensureDeviceIdsAtStartPopulated(): Promise<void> {
|
||||||
if (this.ourDeviceIdsAtStart === null) {
|
if (this.ourDeviceIdsAtStart === null) {
|
||||||
const cli = MatrixClientPeg.get();
|
this.ourDeviceIdsAtStart = await this.getDeviceIds();
|
||||||
this.ourDeviceIdsAtStart = new Set(cli.getStoredDevicesForUser(cli.getUserId()!).map((d) => d.deviceId));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get the device list for the current user
|
||||||
|
*
|
||||||
|
* @returns the set of device IDs
|
||||||
|
*/
|
||||||
|
private async getDeviceIds(): Promise<Set<string>> {
|
||||||
|
const cli = MatrixClientPeg.get();
|
||||||
|
const crypto = cli.getCrypto();
|
||||||
|
if (crypto === undefined) return new Set();
|
||||||
|
|
||||||
|
const userId = cli.getSafeUserId();
|
||||||
|
const devices = await crypto.getUserDeviceInfo([userId]);
|
||||||
|
return new Set(devices.get(userId)?.keys() ?? []);
|
||||||
|
}
|
||||||
|
|
||||||
private onWillUpdateDevices = async (users: string[], initialFetch?: boolean): Promise<void> => {
|
private onWillUpdateDevices = async (users: string[], initialFetch?: boolean): Promise<void> => {
|
||||||
// If we didn't know about *any* devices before (ie. it's fresh login),
|
// If we didn't know about *any* devices before (ie. it's fresh login),
|
||||||
// then they are all pre-existing devices, so ignore this and set the
|
// then they are all pre-existing devices, so ignore this and set the
|
||||||
|
@ -163,7 +176,7 @@ export default class DeviceListener {
|
||||||
if (initialFetch) return;
|
if (initialFetch) return;
|
||||||
|
|
||||||
const myUserId = MatrixClientPeg.get().getUserId()!;
|
const myUserId = MatrixClientPeg.get().getUserId()!;
|
||||||
if (users.includes(myUserId)) this.ensureDeviceIdsAtStartPopulated();
|
if (users.includes(myUserId)) await this.ensureDeviceIdsAtStartPopulated();
|
||||||
|
|
||||||
// No need to do a recheck here: we just need to get a snapshot of our devices
|
// No need to do a recheck here: we just need to get a snapshot of our devices
|
||||||
// before we download any new ones.
|
// before we download any new ones.
|
||||||
|
@ -299,7 +312,7 @@ export default class DeviceListener {
|
||||||
|
|
||||||
// This needs to be done after awaiting on downloadKeys() above, so
|
// This needs to be done after awaiting on downloadKeys() above, so
|
||||||
// we make sure we get the devices after the fetch is done.
|
// we make sure we get the devices after the fetch is done.
|
||||||
this.ensureDeviceIdsAtStartPopulated();
|
await this.ensureDeviceIdsAtStartPopulated();
|
||||||
|
|
||||||
// Unverified devices that were there last time the app ran
|
// Unverified devices that were there last time the app ran
|
||||||
// (technically could just be a boolean: we don't actually
|
// (technically could just be a boolean: we don't actually
|
||||||
|
@ -319,18 +332,16 @@ export default class DeviceListener {
|
||||||
// as long as cross-signing isn't ready,
|
// as long as cross-signing isn't ready,
|
||||||
// you can't see or dismiss any device toasts
|
// you can't see or dismiss any device toasts
|
||||||
if (crossSigningReady) {
|
if (crossSigningReady) {
|
||||||
const devices = cli.getStoredDevicesForUser(cli.getUserId()!);
|
const devices = await this.getDeviceIds();
|
||||||
for (const device of devices) {
|
for (const deviceId of devices) {
|
||||||
if (device.deviceId === cli.deviceId) continue;
|
if (deviceId === cli.deviceId) continue;
|
||||||
|
|
||||||
const deviceTrust = await cli
|
const deviceTrust = await cli.getCrypto()!.getDeviceVerificationStatus(cli.getUserId()!, deviceId);
|
||||||
.getCrypto()!
|
if (!deviceTrust?.crossSigningVerified && !this.dismissed.has(deviceId)) {
|
||||||
.getDeviceVerificationStatus(cli.getUserId()!, device.deviceId!);
|
if (this.ourDeviceIdsAtStart?.has(deviceId)) {
|
||||||
if (!deviceTrust?.crossSigningVerified && !this.dismissed.has(device.deviceId)) {
|
oldUnverifiedDeviceIds.add(deviceId);
|
||||||
if (this.ourDeviceIdsAtStart?.has(device.deviceId)) {
|
|
||||||
oldUnverifiedDeviceIds.add(device.deviceId);
|
|
||||||
} else {
|
} else {
|
||||||
newUnverifiedDeviceIds.add(device.deviceId);
|
newUnverifiedDeviceIds.add(deviceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,10 @@ limitations under the License.
|
||||||
import { Mocked, mocked } from "jest-mock";
|
import { Mocked, mocked } from "jest-mock";
|
||||||
import { MatrixEvent, Room, MatrixClient, DeviceVerificationStatus, CryptoApi } 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 { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { DeviceInfo } from "matrix-js-sdk/src/crypto/deviceinfo";
|
|
||||||
import { CrossSigningInfo } 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 { CryptoEvent } from "matrix-js-sdk/src/crypto";
|
||||||
import { IKeyBackupInfo } from "matrix-js-sdk/src/crypto/keybackup";
|
import { IKeyBackupInfo } from "matrix-js-sdk/src/crypto/keybackup";
|
||||||
|
import { Device } from "matrix-js-sdk/src/models/device";
|
||||||
|
|
||||||
import DeviceListener from "../src/DeviceListener";
|
import DeviceListener from "../src/DeviceListener";
|
||||||
import { MatrixClientPeg } from "../src/MatrixClientPeg";
|
import { MatrixClientPeg } from "../src/MatrixClientPeg";
|
||||||
|
@ -80,10 +80,12 @@ describe("DeviceListener", () => {
|
||||||
getDeviceVerificationStatus: jest.fn().mockResolvedValue({
|
getDeviceVerificationStatus: jest.fn().mockResolvedValue({
|
||||||
crossSigningVerified: false,
|
crossSigningVerified: false,
|
||||||
}),
|
}),
|
||||||
|
getUserDeviceInfo: jest.fn().mockResolvedValue(new Map()),
|
||||||
} as unknown as Mocked<CryptoApi>;
|
} as unknown as Mocked<CryptoApi>;
|
||||||
mockClient = getMockClientWithEventEmitter({
|
mockClient = getMockClientWithEventEmitter({
|
||||||
isGuest: jest.fn(),
|
isGuest: jest.fn(),
|
||||||
getUserId: jest.fn().mockReturnValue(userId),
|
getUserId: jest.fn().mockReturnValue(userId),
|
||||||
|
getSafeUserId: jest.fn().mockReturnValue(userId),
|
||||||
getKeyBackupVersion: jest.fn().mockResolvedValue(undefined),
|
getKeyBackupVersion: jest.fn().mockResolvedValue(undefined),
|
||||||
getRooms: jest.fn().mockReturnValue([]),
|
getRooms: jest.fn().mockReturnValue([]),
|
||||||
isVersionSupported: jest.fn().mockResolvedValue(true),
|
isVersionSupported: jest.fn().mockResolvedValue(true),
|
||||||
|
@ -92,7 +94,6 @@ describe("DeviceListener", () => {
|
||||||
isCryptoEnabled: jest.fn().mockReturnValue(true),
|
isCryptoEnabled: jest.fn().mockReturnValue(true),
|
||||||
isInitialSyncComplete: jest.fn().mockReturnValue(true),
|
isInitialSyncComplete: jest.fn().mockReturnValue(true),
|
||||||
getKeyBackupEnabled: jest.fn(),
|
getKeyBackupEnabled: jest.fn(),
|
||||||
getStoredDevicesForUser: jest.fn().mockReturnValue([]),
|
|
||||||
getCrossSigningId: jest.fn(),
|
getCrossSigningId: jest.fn(),
|
||||||
getStoredCrossSigningForUser: jest.fn(),
|
getStoredCrossSigningForUser: jest.fn(),
|
||||||
waitForClientWellKnown: jest.fn(),
|
waitForClientWellKnown: jest.fn(),
|
||||||
|
@ -393,16 +394,18 @@ describe("DeviceListener", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("unverified sessions toasts", () => {
|
describe("unverified sessions toasts", () => {
|
||||||
const currentDevice = new DeviceInfo(deviceId);
|
const currentDevice = new Device({ deviceId, userId: userId, algorithms: [], keys: new Map() });
|
||||||
const device2 = new DeviceInfo("d2");
|
const device2 = new Device({ deviceId: "d2", userId: userId, algorithms: [], keys: new Map() });
|
||||||
const device3 = new DeviceInfo("d3");
|
const device3 = new Device({ deviceId: "d3", userId: userId, algorithms: [], keys: new Map() });
|
||||||
|
|
||||||
const deviceTrustVerified = new DeviceVerificationStatus({ crossSigningVerified: true });
|
const deviceTrustVerified = new DeviceVerificationStatus({ crossSigningVerified: true });
|
||||||
const deviceTrustUnverified = new DeviceVerificationStatus({});
|
const deviceTrustUnverified = new DeviceVerificationStatus({});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockClient!.isCrossSigningReady.mockResolvedValue(true);
|
mockClient!.isCrossSigningReady.mockResolvedValue(true);
|
||||||
mockClient!.getStoredDevicesForUser.mockReturnValue([currentDevice, device2, device3]);
|
mockCrypto!.getUserDeviceInfo.mockResolvedValue(
|
||||||
|
new Map([[userId, new Map([currentDevice, device2, device3].map((d) => [d.deviceId, d]))]]),
|
||||||
|
);
|
||||||
// all devices verified by default
|
// all devices verified by default
|
||||||
mockCrypto!.getDeviceVerificationStatus.mockResolvedValue(deviceTrustVerified);
|
mockCrypto!.getDeviceVerificationStatus.mockResolvedValue(deviceTrustVerified);
|
||||||
mockClient!.deviceId = currentDevice.deviceId;
|
mockClient!.deviceId = currentDevice.deviceId;
|
||||||
|
@ -525,13 +528,17 @@ describe("DeviceListener", () => {
|
||||||
return deviceTrustUnverified;
|
return deviceTrustUnverified;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mockClient!.getStoredDevicesForUser.mockReturnValue([currentDevice, device2]);
|
mockCrypto!.getUserDeviceInfo.mockResolvedValue(
|
||||||
|
new Map([[userId, new Map([currentDevice, device2].map((d) => [d.deviceId, d]))]]),
|
||||||
|
);
|
||||||
await createAndStart();
|
await createAndStart();
|
||||||
|
|
||||||
expect(BulkUnverifiedSessionsToast.hideToast).toHaveBeenCalled();
|
expect(BulkUnverifiedSessionsToast.hideToast).toHaveBeenCalled();
|
||||||
|
|
||||||
// add an unverified device
|
// add an unverified device
|
||||||
mockClient!.getStoredDevicesForUser.mockReturnValue([currentDevice, device2, device3]);
|
mockCrypto!.getUserDeviceInfo.mockResolvedValue(
|
||||||
|
new Map([[userId, new Map([currentDevice, device2, device3].map((d) => [d.deviceId, d]))]]),
|
||||||
|
);
|
||||||
// trigger a recheck
|
// trigger a recheck
|
||||||
mockClient!.emit(CryptoEvent.DevicesUpdated, [userId], false);
|
mockClient!.emit(CryptoEvent.DevicesUpdated, [userId], false);
|
||||||
await flushPromises();
|
await flushPromises();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue