You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-08-07 23:02:56 +03:00
Element-R: Implement VerificationRequest.{timeout,pending}
(#3532)
* implement `VerificationRequest.pending` * Implement `VerificationRequest.timeout` * Rust crypto: allow using a memory store (#3536) * Rust crypto: allow using a memory store It turns out that, for some usecases (in particular, "bot users" for cypress tests), we don't need persistent storage and an in-memory store will be fine. * Rust crypto: use a memory store for the unit tests
This commit is contained in:
committed by
GitHub
parent
3a8a1389f5
commit
3a694f4998
@@ -55,7 +55,7 @@
|
|||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.12.5",
|
"@babel/runtime": "^7.12.5",
|
||||||
"@matrix-org/matrix-sdk-crypto-js": "^0.1.0-alpha.11",
|
"@matrix-org/matrix-sdk-crypto-js": "^0.1.0",
|
||||||
"another-json": "^0.2.0",
|
"another-json": "^0.2.0",
|
||||||
"bs58": "^5.0.0",
|
"bs58": "^5.0.0",
|
||||||
"content-type": "^1.0.4",
|
"content-type": "^1.0.4",
|
||||||
|
@@ -153,6 +153,9 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("verification (%s)", (backend: st
|
|||||||
expect(request.chosenMethod).toBe(null); // nothing chosen yet
|
expect(request.chosenMethod).toBe(null); // nothing chosen yet
|
||||||
expect(request.initiatedByMe).toBe(true);
|
expect(request.initiatedByMe).toBe(true);
|
||||||
expect(request.otherUserId).toEqual(TEST_USER_ID);
|
expect(request.otherUserId).toEqual(TEST_USER_ID);
|
||||||
|
expect(request.pending).toBe(true);
|
||||||
|
// we're using fake timers, so the timeout should have exactly 10 minutes left still.
|
||||||
|
expect(request.timeout).toEqual(600_000);
|
||||||
|
|
||||||
// and now the request should be visible via `getVerificationRequestsToDeviceInProgress`
|
// and now the request should be visible via `getVerificationRequestsToDeviceInProgress`
|
||||||
{
|
{
|
||||||
@@ -248,6 +251,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("verification (%s)", (backend: st
|
|||||||
// ... and the whole thing should be done!
|
// ... and the whole thing should be done!
|
||||||
await verificationPromise;
|
await verificationPromise;
|
||||||
expect(request.phase).toEqual(VerificationPhase.Done);
|
expect(request.phase).toEqual(VerificationPhase.Done);
|
||||||
|
expect(request.pending).toBe(false);
|
||||||
|
|
||||||
// at this point, cancelling should do nothing.
|
// at this point, cancelling should do nothing.
|
||||||
await request.cancel();
|
await request.cancel();
|
||||||
@@ -564,6 +568,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("verification (%s)", (backend: st
|
|||||||
expect(request.otherUserId).toEqual(TEST_USER_ID);
|
expect(request.otherUserId).toEqual(TEST_USER_ID);
|
||||||
expect(request.chosenMethod).toBe(null); // nothing chosen yet
|
expect(request.chosenMethod).toBe(null); // nothing chosen yet
|
||||||
expect(canAcceptVerificationRequest(request)).toBe(true);
|
expect(canAcceptVerificationRequest(request)).toBe(true);
|
||||||
|
expect(request.pending).toBe(true);
|
||||||
|
|
||||||
// Alice accepts, by sending a to-device message
|
// Alice accepts, by sending a to-device message
|
||||||
const sendToDevicePromise = expectSendToDeviceMessage("m.key.verification.ready");
|
const sendToDevicePromise = expectSendToDeviceMessage("m.key.verification.ready");
|
||||||
|
@@ -14,8 +14,6 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import "fake-indexeddb/auto";
|
|
||||||
import { IDBFactory } from "fake-indexeddb";
|
|
||||||
import * as RustSdkCryptoJs from "@matrix-org/matrix-sdk-crypto-js";
|
import * as RustSdkCryptoJs from "@matrix-org/matrix-sdk-crypto-js";
|
||||||
import { KeysQueryRequest, OlmMachine } from "@matrix-org/matrix-sdk-crypto-js";
|
import { KeysQueryRequest, OlmMachine } from "@matrix-org/matrix-sdk-crypto-js";
|
||||||
import { Mocked } from "jest-mock";
|
import { Mocked } from "jest-mock";
|
||||||
@@ -41,13 +39,6 @@ import { ServerSideSecretStorage } from "../../../src/secret-storage";
|
|||||||
import { CryptoCallbacks, ImportRoomKeysOpts, VerificationRequest } from "../../../src/crypto-api";
|
import { CryptoCallbacks, ImportRoomKeysOpts, VerificationRequest } from "../../../src/crypto-api";
|
||||||
import * as testData from "../../test-utils/test-data";
|
import * as testData from "../../test-utils/test-data";
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
// reset fake-indexeddb after each test, to make sure we don't leak connections
|
|
||||||
// cf https://github.com/dumbmatter/fakeIndexedDB#wipingresetting-the-indexeddb-for-a-fresh-state
|
|
||||||
// eslint-disable-next-line no-global-assign
|
|
||||||
indexedDB = new IDBFactory();
|
|
||||||
});
|
|
||||||
|
|
||||||
const TEST_USER = "@alice:example.com";
|
const TEST_USER = "@alice:example.com";
|
||||||
const TEST_DEVICE_ID = "TEST_DEVICE";
|
const TEST_DEVICE_ID = "TEST_DEVICE";
|
||||||
|
|
||||||
@@ -542,5 +533,5 @@ async function makeTestRustCrypto(
|
|||||||
secretStorage: ServerSideSecretStorage = {} as ServerSideSecretStorage,
|
secretStorage: ServerSideSecretStorage = {} as ServerSideSecretStorage,
|
||||||
cryptoCallbacks: CryptoCallbacks = {} as CryptoCallbacks,
|
cryptoCallbacks: CryptoCallbacks = {} as CryptoCallbacks,
|
||||||
): Promise<RustCrypto> {
|
): Promise<RustCrypto> {
|
||||||
return await initRustCrypto(http, userId, deviceId, secretStorage, cryptoCallbacks);
|
return await initRustCrypto(http, userId, deviceId, secretStorage, cryptoCallbacks, null);
|
||||||
}
|
}
|
||||||
|
@@ -21,18 +21,49 @@ import { RustVerificationRequest } from "../../../src/rust-crypto/verification";
|
|||||||
import { OutgoingRequestProcessor } from "../../../src/rust-crypto/OutgoingRequestProcessor";
|
import { OutgoingRequestProcessor } from "../../../src/rust-crypto/OutgoingRequestProcessor";
|
||||||
|
|
||||||
describe("VerificationRequest", () => {
|
describe("VerificationRequest", () => {
|
||||||
describe("startVerification", () => {
|
describe("pending", () => {
|
||||||
|
let request: RustVerificationRequest;
|
||||||
let mockedInner: Mocked<RustSdkCryptoJs.VerificationRequest>;
|
let mockedInner: Mocked<RustSdkCryptoJs.VerificationRequest>;
|
||||||
let mockedOutgoingRequestProcessor: Mocked<OutgoingRequestProcessor>;
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mockedInner = makeMockedInner();
|
||||||
|
request = makeTestRequest(mockedInner);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns true for a created request", () => {
|
||||||
|
expect(request.pending).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns false for passive requests", () => {
|
||||||
|
mockedInner.isPassive.mockReturnValue(true);
|
||||||
|
expect(request.pending).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns false for completed requests", () => {
|
||||||
|
mockedInner.phase.mockReturnValue(RustSdkCryptoJs.VerificationRequestPhase.Done);
|
||||||
|
expect(request.pending).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("returns false for cancelled requests", () => {
|
||||||
|
mockedInner.phase.mockReturnValue(RustSdkCryptoJs.VerificationRequestPhase.Cancelled);
|
||||||
|
expect(request.pending).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("timeout", () => {
|
||||||
|
it("passes through the result", () => {
|
||||||
|
const mockedInner = makeMockedInner();
|
||||||
|
const request = makeTestRequest(mockedInner);
|
||||||
|
mockedInner.timeRemainingMillis.mockReturnValue(10_000);
|
||||||
|
expect(request.timeout).toEqual(10_000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("startVerification", () => {
|
||||||
let request: RustVerificationRequest;
|
let request: RustVerificationRequest;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockedInner = {
|
request = makeTestRequest();
|
||||||
registerChangesCallback: jest.fn(),
|
|
||||||
startSas: jest.fn(),
|
|
||||||
} as unknown as Mocked<RustSdkCryptoJs.VerificationRequest>;
|
|
||||||
mockedOutgoingRequestProcessor = {} as Mocked<OutgoingRequestProcessor>;
|
|
||||||
request = new RustVerificationRequest(mockedInner, mockedOutgoingRequestProcessor, undefined);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not permit methods other than SAS", async () => {
|
it("does not permit methods other than SAS", async () => {
|
||||||
@@ -48,3 +79,24 @@ describe("VerificationRequest", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/** build a RustVerificationRequest with default parameters */
|
||||||
|
function makeTestRequest(
|
||||||
|
inner?: RustSdkCryptoJs.VerificationRequest,
|
||||||
|
outgoingRequestProcessor?: OutgoingRequestProcessor,
|
||||||
|
): RustVerificationRequest {
|
||||||
|
inner ??= makeMockedInner();
|
||||||
|
outgoingRequestProcessor ??= {} as OutgoingRequestProcessor;
|
||||||
|
return new RustVerificationRequest(inner, outgoingRequestProcessor, undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Mock up a rust-side VerificationRequest */
|
||||||
|
function makeMockedInner(): Mocked<RustSdkCryptoJs.VerificationRequest> {
|
||||||
|
return {
|
||||||
|
registerChangesCallback: jest.fn(),
|
||||||
|
startSas: jest.fn(),
|
||||||
|
phase: jest.fn().mockReturnValue(RustSdkCryptoJs.VerificationRequestPhase.Created),
|
||||||
|
isPassive: jest.fn().mockReturnValue(false),
|
||||||
|
timeRemainingMillis: jest.fn(),
|
||||||
|
} as unknown as Mocked<RustSdkCryptoJs.VerificationRequest>;
|
||||||
|
}
|
||||||
|
@@ -2206,10 +2206,12 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
*
|
*
|
||||||
* @experimental
|
* @experimental
|
||||||
*
|
*
|
||||||
|
* @param useIndexedDB - True to use an indexeddb store, false to use an in-memory store. Defaults to 'true'.
|
||||||
|
*
|
||||||
* @returns a Promise which will resolve when the crypto layer has been
|
* @returns a Promise which will resolve when the crypto layer has been
|
||||||
* successfully initialised.
|
* successfully initialised.
|
||||||
*/
|
*/
|
||||||
public async initRustCrypto(): Promise<void> {
|
public async initRustCrypto({ useIndexedDB = true }: { useIndexedDB?: boolean } = {}): Promise<void> {
|
||||||
if (this.cryptoBackend) {
|
if (this.cryptoBackend) {
|
||||||
logger.warn("Attempt to re-initialise e2e encryption on MatrixClient");
|
logger.warn("Attempt to re-initialise e2e encryption on MatrixClient");
|
||||||
return;
|
return;
|
||||||
@@ -2239,6 +2241,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
deviceId,
|
deviceId,
|
||||||
this.secretStorage,
|
this.secretStorage,
|
||||||
this.cryptoCallbacks,
|
this.cryptoCallbacks,
|
||||||
|
useIndexedDB ? RUST_SDK_STORE_PREFIX : null,
|
||||||
);
|
);
|
||||||
rustCrypto.supportedVerificationMethods = this.verificationMethods;
|
rustCrypto.supportedVerificationMethods = this.verificationMethods;
|
||||||
|
|
||||||
|
@@ -18,7 +18,6 @@ import * as RustSdkCryptoJs from "@matrix-org/matrix-sdk-crypto-js";
|
|||||||
|
|
||||||
import { RustCrypto } from "./rust-crypto";
|
import { RustCrypto } from "./rust-crypto";
|
||||||
import { logger } from "../logger";
|
import { logger } from "../logger";
|
||||||
import { RUST_SDK_STORE_PREFIX } from "./constants";
|
|
||||||
import { IHttpOpts, MatrixHttpApi } from "../http-api";
|
import { IHttpOpts, MatrixHttpApi } from "../http-api";
|
||||||
import { ServerSideSecretStorage } from "../secret-storage";
|
import { ServerSideSecretStorage } from "../secret-storage";
|
||||||
import { ICryptoCallbacks } from "../crypto";
|
import { ICryptoCallbacks } from "../crypto";
|
||||||
@@ -32,6 +31,8 @@ import { ICryptoCallbacks } from "../crypto";
|
|||||||
* @param deviceId - The local user's Device ID.
|
* @param deviceId - The local user's Device ID.
|
||||||
* @param secretStorage - Interface to server-side secret storage.
|
* @param secretStorage - Interface to server-side secret storage.
|
||||||
* @param cryptoCallbacks - Crypto callbacks provided by the application
|
* @param cryptoCallbacks - Crypto callbacks provided by the application
|
||||||
|
* @param storePrefix - the prefix to use on the indexeddbs created by rust-crypto.
|
||||||
|
* If unset, a memory store will be used.
|
||||||
*/
|
*/
|
||||||
export async function initRustCrypto(
|
export async function initRustCrypto(
|
||||||
http: MatrixHttpApi<IHttpOpts & { onlyData: true }>,
|
http: MatrixHttpApi<IHttpOpts & { onlyData: true }>,
|
||||||
@@ -39,6 +40,7 @@ export async function initRustCrypto(
|
|||||||
deviceId: string,
|
deviceId: string,
|
||||||
secretStorage: ServerSideSecretStorage,
|
secretStorage: ServerSideSecretStorage,
|
||||||
cryptoCallbacks: ICryptoCallbacks,
|
cryptoCallbacks: ICryptoCallbacks,
|
||||||
|
storePrefix: string | null,
|
||||||
): Promise<RustCrypto> {
|
): Promise<RustCrypto> {
|
||||||
// initialise the rust matrix-sdk-crypto-js, if it hasn't already been done
|
// initialise the rust matrix-sdk-crypto-js, if it hasn't already been done
|
||||||
await RustSdkCryptoJs.initAsync();
|
await RustSdkCryptoJs.initAsync();
|
||||||
@@ -51,7 +53,12 @@ export async function initRustCrypto(
|
|||||||
logger.info("Init OlmMachine");
|
logger.info("Init OlmMachine");
|
||||||
|
|
||||||
// TODO: use the pickle key for the passphrase
|
// TODO: use the pickle key for the passphrase
|
||||||
const olmMachine = await RustSdkCryptoJs.OlmMachine.initialize(u, d, RUST_SDK_STORE_PREFIX, "test pass");
|
const olmMachine = await RustSdkCryptoJs.OlmMachine.initialize(
|
||||||
|
u,
|
||||||
|
d,
|
||||||
|
storePrefix ?? undefined,
|
||||||
|
(storePrefix && "test pass") ?? undefined,
|
||||||
|
);
|
||||||
const rustCrypto = new RustCrypto(olmMachine, http, userId, deviceId, secretStorage, cryptoCallbacks);
|
const rustCrypto = new RustCrypto(olmMachine, http, userId, deviceId, secretStorage, cryptoCallbacks);
|
||||||
await olmMachine.registerRoomKeyUpdatedCallback((sessions: RustSdkCryptoJs.RoomKeyInfo[]) =>
|
await olmMachine.registerRoomKeyUpdatedCallback((sessions: RustSdkCryptoJs.RoomKeyInfo[]) =>
|
||||||
rustCrypto.onRoomKeysUpdated(sessions),
|
rustCrypto.onRoomKeysUpdated(sessions),
|
||||||
|
@@ -145,7 +145,9 @@ export class RustVerificationRequest
|
|||||||
* (ie it is in phase `Requested`, `Ready` or `Started`).
|
* (ie it is in phase `Requested`, `Ready` or `Started`).
|
||||||
*/
|
*/
|
||||||
public get pending(): boolean {
|
public get pending(): boolean {
|
||||||
throw new Error("not implemented");
|
if (this.inner.isPassive()) return false;
|
||||||
|
const phase = this.phase;
|
||||||
|
return phase !== VerificationPhase.Done && phase !== VerificationPhase.Cancelled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -170,7 +172,7 @@ export class RustVerificationRequest
|
|||||||
* `null` indicates that there is no timeout
|
* `null` indicates that there is no timeout
|
||||||
*/
|
*/
|
||||||
public get timeout(): number | null {
|
public get timeout(): number | null {
|
||||||
throw new Error("not implemented");
|
return this.inner.timeRemainingMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** once the phase is Started (and !initiatedByMe) or Ready: common methods supported by both sides */
|
/** once the phase is Started (and !initiatedByMe) or Ready: common methods supported by both sides */
|
||||||
|
@@ -1426,7 +1426,7 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
lodash "^4.17.21"
|
lodash "^4.17.21"
|
||||||
|
|
||||||
"@matrix-org/matrix-sdk-crypto-js@^0.1.0-alpha.11":
|
"@matrix-org/matrix-sdk-crypto-js@^0.1.0":
|
||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-js/-/matrix-sdk-crypto-js-0.1.0.tgz#766580036d4df12120ded223e13b5640e77db136"
|
resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-js/-/matrix-sdk-crypto-js-0.1.0.tgz#766580036d4df12120ded223e13b5640e77db136"
|
||||||
integrity sha512-ra/bcFdleC1iRNms2I96UXA0NvQYWpMsHrV5EfJRS7qV1PtnQNvgsvMfjMbkx8QT2ErEmIhsvB5fPCpfp8BSuw==
|
integrity sha512-ra/bcFdleC1iRNms2I96UXA0NvQYWpMsHrV5EfJRS7qV1PtnQNvgsvMfjMbkx8QT2ErEmIhsvB5fPCpfp8BSuw==
|
||||||
|
Reference in New Issue
Block a user