diff --git a/package.json b/package.json index 341ab850b..02a5c4cee 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.8", + "@matrix-org/matrix-sdk-crypto-js": "^0.1.0-alpha.9", "another-json": "^0.2.0", "bs58": "^5.0.0", "content-type": "^1.0.4", diff --git a/spec/unit/rust-crypto/OutgoingRequestProcessor.spec.ts b/spec/unit/rust-crypto/OutgoingRequestProcessor.spec.ts index 28d1e9b35..bb1cdff6a 100644 --- a/spec/unit/rust-crypto/OutgoingRequestProcessor.spec.ts +++ b/spec/unit/rust-crypto/OutgoingRequestProcessor.spec.ts @@ -24,11 +24,12 @@ import { KeysUploadRequest, RoomMessageRequest, SignatureUploadRequest, + SigningKeysUploadRequest, ToDeviceRequest, } from "@matrix-org/matrix-sdk-crypto-js"; import { TypedEventEmitter } from "../../../src/models/typed-event-emitter"; -import { HttpApiEvent, HttpApiEventHandlerMap, MatrixHttpApi } from "../../../src"; +import { HttpApiEvent, HttpApiEventHandlerMap, MatrixHttpApi, UIAuthCallback } from "../../../src"; import { OutgoingRequestProcessor } from "../../../src/rust-crypto/OutgoingRequestProcessor"; describe("OutgoingRequestProcessor", () => { @@ -80,6 +81,12 @@ describe("OutgoingRequestProcessor", () => { "https://example.com/_matrix/client/v3/keys/signatures/upload", ], ["KeysBackupRequest", KeysBackupRequest, "PUT", "https://example.com/_matrix/client/v3/room_keys/keys"], + [ + "SigningKeysUploadRequest", + SigningKeysUploadRequest, + "POST", + "https://example.com/_matrix/client/v3/keys/device_signing/upload", + ], ]; test.each(tests)(`should handle %ss`, async (_, RequestClass, expectedMethod, expectedPath) => { @@ -171,6 +178,40 @@ describe("OutgoingRequestProcessor", () => { httpBackend.verifyNoOutstandingRequests(); }); + it("should handle SigningKeysUploadRequests with UIA", async () => { + // first, mock up a request as we might expect to receive it from the Rust layer ... + const testReq = { foo: "bar" }; + const outgoingRequest = new SigningKeysUploadRequest("1234", JSON.stringify(testReq)); + + // also create a UIA callback + const authCallback: UIAuthCallback = async (makeRequest) => { + return await makeRequest({ type: "test" }); + }; + + // ... then poke the request into the OutgoingRequestProcessor under test + const reqProm = processor.makeOutgoingRequest(outgoingRequest, authCallback); + + // Now: check that it makes a matching HTTP request ... + const testResponse = '{"result":1}'; + httpBackend + .when("POST", "/_matrix") + .check((req) => { + expect(req.path).toEqual("https://example.com/_matrix/client/v3/keys/device_signing/upload"); + expect(JSON.parse(req.rawData)).toEqual({ foo: "bar", auth: { type: "test" } }); + expect(req.headers["Accept"]).toEqual("application/json"); + expect(req.headers["Content-Type"]).toEqual("application/json"); + }) + .respond(200, testResponse, true); + + // ... and that it calls OlmMachine.markAsSent. + const markSentCallPromise = awaitCallToMarkAsSent(); + await httpBackend.flushAllExpected(); + + await Promise.all([reqProm, markSentCallPromise]); + expect(olmMachine.markRequestAsSent).toHaveBeenCalledWith("1234", outgoingRequest.type, testResponse); + httpBackend.verifyNoOutstandingRequests(); + }); + it("does not explode with unknown requests", async () => { const outgoingRequest = { id: "5678", type: 987 }; const markSentCallPromise = awaitCallToMarkAsSent(); diff --git a/src/rust-crypto/OutgoingRequestProcessor.ts b/src/rust-crypto/OutgoingRequestProcessor.ts index 7ac9a2105..4e98bce8d 100644 --- a/src/rust-crypto/OutgoingRequestProcessor.ts +++ b/src/rust-crypto/OutgoingRequestProcessor.ts @@ -23,11 +23,14 @@ import { RoomMessageRequest, SignatureUploadRequest, ToDeviceRequest, + SigningKeysUploadRequest, } from "@matrix-org/matrix-sdk-crypto-js"; import { logger } from "../logger"; import { IHttpOpts, MatrixHttpApi, Method } from "../http-api"; import { QueryDict } from "../utils"; +import { IAuthDict, UIAuthCallback } from "../interactive-auth"; +import { UIAResponse } from "../@types/uia"; /** * Common interface for all the request types returned by `OlmMachine.outgoingRequests`. @@ -53,7 +56,7 @@ export class OutgoingRequestProcessor { private readonly http: MatrixHttpApi, ) {} - public async makeOutgoingRequest(msg: OutgoingRequest): Promise { + public async makeOutgoingRequest(msg: OutgoingRequest, uiaCallback?: UIAuthCallback): Promise { let resp: string; /* refer https://docs.rs/matrix-sdk-crypto/0.6.0/matrix_sdk_crypto/requests/enum.OutgoingRequests.html @@ -79,6 +82,14 @@ export class OutgoingRequestProcessor { `/_matrix/client/v3/room/${encodeURIComponent(msg.room_id)}/send/` + `${encodeURIComponent(msg.event_type)}/${encodeURIComponent(msg.txn_id)}`; resp = await this.rawJsonRequest(Method.Put, path, {}, msg.body); + } else if (msg instanceof SigningKeysUploadRequest) { + resp = await this.makeRequestWithUIA( + Method.Post, + "/_matrix/client/v3/keys/device_signing/upload", + {}, + msg.body, + uiaCallback, + ); } else { logger.warn("Unsupported outgoing message", Object.getPrototypeOf(msg)); resp = ""; @@ -89,6 +100,31 @@ export class OutgoingRequestProcessor { } } + private async makeRequestWithUIA( + method: Method, + path: string, + queryParams: QueryDict, + body: string, + uiaCallback: UIAuthCallback | undefined, + ): Promise { + if (!uiaCallback) { + return await this.rawJsonRequest(method, path, queryParams, body); + } + + const parsedBody = JSON.parse(body); + const makeRequest = async (auth: IAuthDict): Promise> => { + const newBody = { + ...parsedBody, + auth, + }; + const resp = await this.rawJsonRequest(method, path, queryParams, JSON.stringify(newBody)); + return JSON.parse(resp) as T; + }; + + const resp = await uiaCallback(makeRequest); + return JSON.stringify(resp); + } + private async rawJsonRequest(method: Method, path: string, queryParams: QueryDict, body: string): Promise { const opts = { // inhibit the JSON stringification and parsing within HttpApi. diff --git a/yarn.lock b/yarn.lock index 07a9e8e70..7f0917823 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1426,10 +1426,10 @@ dependencies: lodash "^4.17.21" -"@matrix-org/matrix-sdk-crypto-js@^0.1.0-alpha.8": - version "0.1.0-alpha.8" - resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-js/-/matrix-sdk-crypto-js-0.1.0-alpha.8.tgz#18dd8e7fb56602d2999d8a502b49e902a2bb3782" - integrity sha512-hdmbbGXKrN6JNo3wdBaR5Zs3lXlzllT3U43ViNTlabB3nKkOZQnEAN/Isv+4EQSgz1+8897veI9Q8sqlQX22oA== +"@matrix-org/matrix-sdk-crypto-js@^0.1.0-alpha.9": + version "0.1.0-alpha.9" + resolved "https://registry.yarnpkg.com/@matrix-org/matrix-sdk-crypto-js/-/matrix-sdk-crypto-js-0.1.0-alpha.9.tgz#00bc266781502641a661858a5a521dd4d95275fc" + integrity sha512-g5cjpFwA9h0CbEGoAqNVI2QcyDsbI8FHoLo9+OXWHIezEKITsSv78mc5ilIwN+2YpmVlH0KNeQWTHw4vi0BMnw== "@matrix-org/olm@https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.14.tgz": version "3.2.14"