Skip to content

Commit

Permalink
Add CryptoApi.setDeviceVerified (#3624)
Browse files Browse the repository at this point in the history
I need a way to mark devices as trusted for the backup tests.
  • Loading branch information
richvdh authored Jul 27, 2023
1 parent e6fa4cd commit 73c9f4e
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 0 deletions.
56 changes: 56 additions & 0 deletions spec/unit/rust-crypto/rust-crypto.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import { RustCrypto } from "../../../src/rust-crypto/rust-crypto";
import { initRustCrypto } from "../../../src/rust-crypto";
import {
CryptoEvent,
Device,
DeviceVerification,
HttpApiEvent,
HttpApiEventHandlerMap,
IHttpOpts,
Expand Down Expand Up @@ -351,6 +353,60 @@ describe("RustCrypto", () => {
});
});

describe("setDeviceVerified", () => {
let rustCrypto: RustCrypto;

async function getTestDevice(): Promise<Device> {
const devices = await rustCrypto.getUserDeviceInfo([testData.TEST_USER_ID]);
return devices.get(testData.TEST_USER_ID)!.get(testData.TEST_DEVICE_ID)!;
}

beforeEach(async () => {
rustCrypto = await makeTestRustCrypto(
new MatrixHttpApi(new TypedEventEmitter<HttpApiEvent, HttpApiEventHandlerMap>(), {
baseUrl: "http://server/",
prefix: "",
onlyData: true,
}),
testData.TEST_USER_ID,
);

fetchMock.post("path:/_matrix/client/v3/keys/upload", { one_time_key_counts: {} });
fetchMock.post("path:/_matrix/client/v3/keys/query", {
device_keys: {
[testData.TEST_USER_ID]: {
[testData.TEST_DEVICE_ID]: testData.SIGNED_TEST_DEVICE_DATA,
},
},
});
// call onSyncCompleted to kick off the outgoingRequestLoop and download the device list.
rustCrypto.onSyncCompleted({});

// before the call, the device should be unverified.
const device = await getTestDevice();
expect(device.verified).toEqual(DeviceVerification.Unverified);
});

it("should throw an error for an unknown device", async () => {
await expect(rustCrypto.setDeviceVerified(testData.TEST_USER_ID, "xxy")).rejects.toThrow("Unknown device");
});

it("should mark an unverified device as verified", async () => {
await rustCrypto.setDeviceVerified(testData.TEST_USER_ID, testData.TEST_DEVICE_ID);

// and confirm that the device is now verified
expect((await getTestDevice()).verified).toEqual(DeviceVerification.Verified);
});

it("should mark a verified device as unverified", async () => {
await rustCrypto.setDeviceVerified(testData.TEST_USER_ID, testData.TEST_DEVICE_ID);
expect((await getTestDevice()).verified).toEqual(DeviceVerification.Verified);

await rustCrypto.setDeviceVerified(testData.TEST_USER_ID, testData.TEST_DEVICE_ID, false);
expect((await getTestDevice()).verified).toEqual(DeviceVerification.Unverified);
});
});

describe("getDeviceVerificationStatus", () => {
let rustCrypto: RustCrypto;
let olmMachine: Mocked<RustSdkCryptoJs.OlmMachine>;
Expand Down
16 changes: 16 additions & 0 deletions src/crypto-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,22 @@ export interface CryptoApi {
*/
getDeviceVerificationStatus(userId: string, deviceId: string): Promise<DeviceVerificationStatus | null>;

/**
* Mark the given device as locally verified.
*
* Marking a devices as locally verified has much the same effect as completing the verification dance, or receiving
* a cross-signing signature for it.
*
* @param userId - owner of the device
* @param deviceId - unique identifier for the device.
* @param verified - whether to mark the device as verified. Defaults to 'true'.
*
* @throws an error if the device is unknown, or has not published any encryption keys.
*
* @remarks Fires {@link CryptoEvent#DeviceVerificationChanged}
*/
setDeviceVerified(userId: string, deviceId: string, verified?: boolean): Promise<void>;

/**
* Checks whether cross signing:
* - is enabled on this account and trusted by this device
Expand Down
9 changes: 9 additions & 0 deletions src/crypto/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2174,6 +2174,15 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
return this.deviceList.saveIfDirty(delay);
}

/**
* Mark the given device as locally verified.
*
* Implementation of {@link CryptoApi#setDeviceVerified}.
*/
public async setDeviceVerified(userId: string, deviceId: string, verified = true): Promise<void> {
await this.setDeviceVerification(userId, deviceId, verified);
}

/**
* Update the blocked/verified state of the given device
*
Expand Down
17 changes: 17 additions & 0 deletions src/rust-crypto/rust-crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,23 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, RustCryptoEv
// events. Maybe we need to do the same?
}

/**
* Mark the given device as locally verified.
*
* Implementation of {@link CryptoApi#setDeviceVerified}.
*/
public async setDeviceVerified(userId: string, deviceId: string, verified = true): Promise<void> {
const device: RustSdkCryptoJs.Device | undefined = await this.olmMachine.getDevice(
new RustSdkCryptoJs.UserId(userId),
new RustSdkCryptoJs.DeviceId(deviceId),
);

if (!device) {
throw new Error(`Unknown device ${userId}|${deviceId}`);
}
await device.setLocalTrust(verified ? RustSdkCryptoJs.LocalTrust.Verified : RustSdkCryptoJs.LocalTrust.Unset);
}

/**
* Implementation of {@link CryptoApi#getDeviceVerificationStatus}.
*/
Expand Down

0 comments on commit 73c9f4e

Please sign in to comment.