diff --git a/package.json b/package.json index 32bd4f6c8..4cfe6b380 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ ], "dependencies": { "@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", "bs58": "^5.0.0", "content-type": "^1.0.4", diff --git a/spec/integ/crypto/verification.spec.ts b/spec/integ/crypto/verification.spec.ts index 00247ec33..8e008ad5c 100644 --- a/spec/integ/crypto/verification.spec.ts +++ b/spec/integ/crypto/verification.spec.ts @@ -153,6 +153,9 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("verification (%s)", (backend: st expect(request.chosenMethod).toBe(null); // nothing chosen yet expect(request.initiatedByMe).toBe(true); 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` { @@ -248,6 +251,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("verification (%s)", (backend: st // ... and the whole thing should be done! await verificationPromise; expect(request.phase).toEqual(VerificationPhase.Done); + expect(request.pending).toBe(false); // at this point, cancelling should do nothing. 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.chosenMethod).toBe(null); // nothing chosen yet expect(canAcceptVerificationRequest(request)).toBe(true); + expect(request.pending).toBe(true); // Alice accepts, by sending a to-device message const sendToDevicePromise = expectSendToDeviceMessage("m.key.verification.ready"); diff --git a/spec/unit/rust-crypto/rust-crypto.spec.ts b/spec/unit/rust-crypto/rust-crypto.spec.ts index 25f225e1f..7776e9ef8 100644 --- a/spec/unit/rust-crypto/rust-crypto.spec.ts +++ b/spec/unit/rust-crypto/rust-crypto.spec.ts @@ -14,8 +14,6 @@ See the License for the specific language governing permissions and limitations under the License. */ -import "fake-indexeddb/auto"; -import { IDBFactory } from "fake-indexeddb"; import * as RustSdkCryptoJs from "@matrix-org/matrix-sdk-crypto-js"; import { KeysQueryRequest, OlmMachine } from "@matrix-org/matrix-sdk-crypto-js"; import { Mocked } from "jest-mock"; @@ -41,13 +39,6 @@ import { ServerSideSecretStorage } from "../../../src/secret-storage"; import { CryptoCallbacks, ImportRoomKeysOpts, VerificationRequest } from "../../../src/crypto-api"; 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_DEVICE_ID = "TEST_DEVICE"; @@ -542,5 +533,5 @@ async function makeTestRustCrypto( secretStorage: ServerSideSecretStorage = {} as ServerSideSecretStorage, cryptoCallbacks: CryptoCallbacks = {} as CryptoCallbacks, ): Promise { - return await initRustCrypto(http, userId, deviceId, secretStorage, cryptoCallbacks); + return await initRustCrypto(http, userId, deviceId, secretStorage, cryptoCallbacks, null); } diff --git a/spec/unit/rust-crypto/verification.spec.ts b/spec/unit/rust-crypto/verification.spec.ts index b76a672d2..d74e8de1a 100644 --- a/spec/unit/rust-crypto/verification.spec.ts +++ b/spec/unit/rust-crypto/verification.spec.ts @@ -21,18 +21,49 @@ import { RustVerificationRequest } from "../../../src/rust-crypto/verification"; import { OutgoingRequestProcessor } from "../../../src/rust-crypto/OutgoingRequestProcessor"; describe("VerificationRequest", () => { - describe("startVerification", () => { + describe("pending", () => { + let request: RustVerificationRequest; let mockedInner: Mocked; - let mockedOutgoingRequestProcessor: Mocked; + + 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; beforeEach(() => { - mockedInner = { - registerChangesCallback: jest.fn(), - startSas: jest.fn(), - } as unknown as Mocked; - mockedOutgoingRequestProcessor = {} as Mocked; - request = new RustVerificationRequest(mockedInner, mockedOutgoingRequestProcessor, undefined); + request = makeTestRequest(); }); 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 { + 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; +} diff --git a/src/client.ts b/src/client.ts index 8ef86b8fe..85d35db10 100644 --- a/src/client.ts +++ b/src/client.ts @@ -2206,10 +2206,12 @@ export class MatrixClient extends TypedEventEmitter { + public async initRustCrypto({ useIndexedDB = true }: { useIndexedDB?: boolean } = {}): Promise { if (this.cryptoBackend) { logger.warn("Attempt to re-initialise e2e encryption on MatrixClient"); return; @@ -2239,6 +2241,7 @@ export class MatrixClient extends TypedEventEmitter, @@ -39,6 +40,7 @@ export async function initRustCrypto( deviceId: string, secretStorage: ServerSideSecretStorage, cryptoCallbacks: ICryptoCallbacks, + storePrefix: string | null, ): Promise { // initialise the rust matrix-sdk-crypto-js, if it hasn't already been done await RustSdkCryptoJs.initAsync(); @@ -51,7 +53,12 @@ export async function initRustCrypto( logger.info("Init OlmMachine"); // 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); await olmMachine.registerRoomKeyUpdatedCallback((sessions: RustSdkCryptoJs.RoomKeyInfo[]) => rustCrypto.onRoomKeysUpdated(sessions), diff --git a/src/rust-crypto/verification.ts b/src/rust-crypto/verification.ts index 5382a6463..fbf65f64f 100644 --- a/src/rust-crypto/verification.ts +++ b/src/rust-crypto/verification.ts @@ -145,7 +145,9 @@ export class RustVerificationRequest * (ie it is in phase `Requested`, `Ready` or `Started`). */ 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 */ 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 */ diff --git a/yarn.lock b/yarn.lock index d6a608cfd..51914809e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1426,7 +1426,7 @@ dependencies: 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" resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-js/-/matrix-sdk-crypto-js-0.1.0.tgz#766580036d4df12120ded223e13b5640e77db136" integrity sha512-ra/bcFdleC1iRNms2I96UXA0NvQYWpMsHrV5EfJRS7qV1PtnQNvgsvMfjMbkx8QT2ErEmIhsvB5fPCpfp8BSuw==