diff --git a/src/MatrixClient.ts b/src/MatrixClient.ts index f9ca9e44..73c40384 100644 --- a/src/MatrixClient.ts +++ b/src/MatrixClient.ts @@ -1609,6 +1609,29 @@ export class MatrixClient extends EventEmitter { .then(response => response["content_uri"]); } + /** + * Download Authenticated content from the homeserver's media repository. Note that this will not automatically + * decrypt media as it cannot determine if the media is encrypted. + * @param {string} mxcUrl The MXC URI for the content. + * @param {number} timeoutMs The maximum number of milliseconds that the client is willing to wait to start receiving data, + * in the case that the content has not yet been uploaded. The default value is 20000 (20 seconds). + * @returns {Promise<{data: Buffer, contentType: string}>} Resolves to the downloaded content. + */ + public async downloadAuthenticatedContent(mxcUrl: string, timeoutMs = 20000): Promise<{ data: Buffer, contentType: string }> { + if (!mxcUrl.toLowerCase().startsWith("mxc://")) { + throw Error("'mxcUrl' does not begin with mxc://"); + } + const urlParts = mxcUrl.substr("mxc://".length).split("/"); + const domain = encodeURIComponent(urlParts[0]); + const mediaId = encodeURIComponent(urlParts[1].split("/")[0]); + const path = `/_matrix/client/v1/media/download/${domain}/${mediaId}`; + const res = await this.doRequest("GET", path, { timeout_ms: timeoutMs }, null, null, true, null, true); + return { + data: res.body, + contentType: res.headers["content-type"], + }; + } + /** * Download content from the homeserver's media repository. Note that this will not automatically decrypt * media as it cannot determine if the media is encrypted. diff --git a/test/MatrixClientTest.ts b/test/MatrixClientTest.ts index 6abdf93e..d7d90484 100644 --- a/test/MatrixClientTest.ts +++ b/test/MatrixClientTest.ts @@ -5727,6 +5727,35 @@ describe('MatrixClient', () => { }); }); + describe('downloadAuthenticatedContent', () => { + it('should call the right endpoint', async () => { + const { client, http } = createTestClient(); + const urlPart = "example.org/testing"; + const mxcUrl = "mxc://" + urlPart; + // const fileContents = Buffer.from("12345"); + + // noinspection TypeScriptValidateJSTypes + http.when("GET", "/_matrix/client/v1/media/download/").respond(200, (path, _, req) => { + expect(path).toContain("/_matrix/client/v1/media/download/" + urlPart); + expect((req as any).opts.encoding).toEqual(null); + // TODO: Honestly, I have no idea how to coerce the mock library to return headers or buffers, + // so this is left as a fun activity. + // return { + // body: fileContents, + // headers: { + // "content-type": "test/test", + // }, + // }; + return {}; + }); + + // Due to the above problem, the output of this won't be correct, so we cannot verify it. + const [res] = await Promise.all([client.downloadAuthenticatedContent(mxcUrl), http.flushAllExpected()]); + expect(Object.keys(res)).toContain("data"); + expect(Object.keys(res)).toContain("contentType"); + }); + }); + describe('downloadContent', () => { it('should call the right endpoint', async () => { const { client, http } = createTestClient();