1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-11-25 05:23:13 +03:00

Expose new method CryptoApi.crossSignDevice (#3930)

This commit is contained in:
Richard van der Hoff
2023-11-29 14:45:26 +00:00
committed by GitHub
parent 3f246c6080
commit d90ae11e2b
4 changed files with 98 additions and 1 deletions

View File

@@ -31,8 +31,10 @@ import {
SELF_CROSS_SIGNING_PRIVATE_KEY_BASE64, SELF_CROSS_SIGNING_PRIVATE_KEY_BASE64,
SELF_CROSS_SIGNING_PUBLIC_KEY_BASE64, SELF_CROSS_SIGNING_PUBLIC_KEY_BASE64,
SIGNED_CROSS_SIGNING_KEYS_DATA, SIGNED_CROSS_SIGNING_KEYS_DATA,
SIGNED_TEST_DEVICE_DATA,
USER_CROSS_SIGNING_PRIVATE_KEY_BASE64, USER_CROSS_SIGNING_PRIVATE_KEY_BASE64,
} from "../../test-utils/test-data"; } from "../../test-utils/test-data";
import * as testData from "../../test-utils/test-data";
import { E2EKeyResponder } from "../../test-utils/E2EKeyResponder"; import { E2EKeyResponder } from "../../test-utils/E2EKeyResponder";
afterEach(() => { afterEach(() => {
@@ -97,6 +99,12 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("cross-signing (%s)", (backend: s
/** an object which intercepts `/keys/upload` requests on the test homeserver */ /** an object which intercepts `/keys/upload` requests on the test homeserver */
new E2EKeyReceiver(homeserverUrl); new E2EKeyReceiver(homeserverUrl);
// Silence warnings from the backup manager
fetchMock.getOnce(new URL("/_matrix/client/v3/room_keys/version", homeserverUrl).toString(), {
status: 404,
body: { errcode: "M_NOT_FOUND" },
});
await initCrypto(aliceClient); await initCrypto(aliceClient);
}); });
@@ -339,4 +347,48 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("cross-signing (%s)", (backend: s
expect(userSigningKeyId).toBe(getPubKey(crossSigningKeys.user_signing_key)); expect(userSigningKeyId).toBe(getPubKey(crossSigningKeys.user_signing_key));
}); });
}); });
describe("crossSignDevice", () => {
beforeEach(async () => {
jest.useFakeTimers();
// make sure that there is another device which we can sign
e2eKeyResponder.addDeviceKeys(SIGNED_TEST_DEVICE_DATA);
// Complete initialsync, to get the outgoing requests going
mockInitialApiRequests(aliceClient.getHomeserverUrl());
syncResponder.sendOrQueueSyncResponse({ next_batch: 1 });
await aliceClient.startClient();
await syncPromise(aliceClient);
// Wait for legacy crypto to find the device
await jest.advanceTimersByTimeAsync(10);
const devices = await aliceClient.getCrypto()!.getUserDeviceInfo([aliceClient.getSafeUserId()]);
expect(devices.get(aliceClient.getSafeUserId())!.has(testData.TEST_DEVICE_ID)).toBeTruthy();
});
afterEach(async () => {
jest.useRealTimers();
});
it("fails for an unknown device", async () => {
await expect(aliceClient.getCrypto()!.crossSignDevice("unknown")).rejects.toThrow("Unknown device");
});
it("cross-signs the device", async () => {
mockSetupCrossSigningRequests();
await aliceClient.getCrypto()!.bootstrapCrossSigning({});
fetchMock.mockClear();
await aliceClient.getCrypto()!.crossSignDevice(testData.TEST_DEVICE_ID);
// check that a sig for the device was uploaded
const calls = fetchMock.calls("upload-sigs");
expect(calls.length).toEqual(1);
const body = JSON.parse(calls[0][1]!.body as string);
const deviceSig = body[aliceClient.getSafeUserId()][testData.TEST_DEVICE_ID];
expect(deviceSig).toHaveProperty("signatures");
});
});
}); });

View File

@@ -162,7 +162,7 @@ export interface CryptoApi {
/** /**
* Mark the given device as locally verified. * 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 * Marking a device as locally verified has much the same effect as completing the verification dance, or receiving
* a cross-signing signature for it. * a cross-signing signature for it.
* *
* @param userId - owner of the device * @param userId - owner of the device
@@ -175,6 +175,21 @@ export interface CryptoApi {
*/ */
setDeviceVerified(userId: string, deviceId: string, verified?: boolean): Promise<void>; setDeviceVerified(userId: string, deviceId: string, verified?: boolean): Promise<void>;
/**
* Cross-sign one of our own devices.
*
* This will create a signature for the device using our self-signing key, and publish that signature.
* Cross-signing a device indicates, to our other devices and to other users, that we have verified that it really
* belongs to us.
*
* Requires that cross-signing has been set up on this device (normally by calling {@link bootstrapCrossSigning}.
*
* *Note*: Do not call this unless you have verified, somehow, that the device is genuine!
*
* @param deviceId - ID of the device to be signed.
*/
crossSignDevice(deviceId: string): Promise<void>;
/** /**
* Checks whether cross signing: * Checks whether cross signing:
* - is enabled on this account and trusted by this device * - is enabled on this account and trusted by this device

View File

@@ -2306,6 +2306,15 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
await this.setDeviceVerification(userId, deviceId, verified); await this.setDeviceVerification(userId, deviceId, verified);
} }
/**
* Blindly cross-sign one of our other devices.
*
* Implementation of {@link CryptoApi#crossSignDevice}.
*/
public async crossSignDevice(deviceId: string): Promise<void> {
await this.setDeviceVerified(this.userId, deviceId, true);
}
/** /**
* Update the blocked/verified state of the given device * Update the blocked/verified state of the given device
* *

View File

@@ -572,6 +572,27 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, RustCryptoEv
} }
} }
/**
* Blindly cross-sign one of our other devices.
*
* Implementation of {@link CryptoApi#crossSignDevice}.
*/
public async crossSignDevice(deviceId: string): Promise<void> {
const device: RustSdkCryptoJs.Device | undefined = await this.olmMachine.getDevice(
new RustSdkCryptoJs.UserId(this.userId),
new RustSdkCryptoJs.DeviceId(deviceId),
);
if (!device) {
throw new Error(`Unknown device ${deviceId}`);
}
try {
const outgoingRequest: RustSdkCryptoJs.SignatureUploadRequest = await device.verify();
await this.outgoingRequestProcessor.makeOutgoingRequest(outgoingRequest);
} finally {
device.free();
}
}
/** /**
* Implementation of {@link CryptoApi#getDeviceVerificationStatus}. * Implementation of {@link CryptoApi#getDeviceVerificationStatus}.
*/ */