From 31e72efc91bbb07dd6f5f2921b9ea58ffc7f0620 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Thu, 22 Aug 2019 14:31:41 +0100 Subject: [PATCH 1/2] Send id_access_token to HS for use in proxied IS requests This passes along the `id_access_token` to the HS, which it will need when speaking v2 IS APIs to the IS. Unfortunately, some HSes seem to explode when given this new parameter, so we only pass it along for the moment if an unstable feature `m.id_access_token` is also set. Part of https://github.com/vector-im/riot-web/issues/10525 Defined in MSC2140 --- src/base-apis.js | 9 +++++++ src/client.js | 61 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/src/base-apis.js b/src/base-apis.js index 3e9a9bc7467..f5069c7c344 100644 --- a/src/base-apis.js +++ b/src/base-apis.js @@ -63,6 +63,14 @@ function termsUrlForService(serviceType, baseUrl) { * * @param {string} opts.accessToken The access_token for this user. * + * @param {Function} [opts.getIdentityAccessToken] + * Optional. A callback that returns a Promise of an identity access + * token to supply with identity requests. If the callback is unset, no access + * token will be supplied. + * See also https://github.com/vector-im/riot-web/issues/10615 which seeks to + * replace the previous approach of manual access tokens params with this + * callback throughout the SDK. + * * @param {Number=} opts.localTimeoutMs Optional. The default maximum amount of * time to wait before timing out HTTP requests. If not specified, there is no * timeout. @@ -79,6 +87,7 @@ function MatrixBaseApis(opts) { this.baseUrl = opts.baseUrl; this.idBaseUrl = opts.idBaseUrl; + this.getIdentityAccessToken = opts.getIdentityAccessToken; const httpOpts = { baseUrl: opts.baseUrl, diff --git a/src/client.js b/src/client.js index 51ec683f80e..a87c475f15c 100644 --- a/src/client.js +++ b/src/client.js @@ -108,6 +108,14 @@ function keyFromRecoverySession(session, decryptionKey) { * * @param {string} opts.userId The user ID for this user. * + * @param {Function} [opts.getIdentityAccessToken] + * Optional. A callback that returns a Promise of an identity access + * token to supply with identity requests. If the callback is unset, no access + * token will be supplied. + * See also https://github.com/vector-im/riot-web/issues/10615 which seeks to + * replace the previous approach of manual access tokens params with this + * callback throughout the SDK. + * * @param {Object=} opts.store * The data store used for sync data from the homeserver. If not specified, * this client will not store any HTTP responses. The `createClient` helper @@ -2438,7 +2446,12 @@ MatrixClient.prototype.inviteByEmail = function(roomId, email, callback) { * @return {module:client.Promise} Resolves: TODO * @return {module:http-api.MatrixError} Rejects: with an error response. */ -MatrixClient.prototype.inviteByThreePid = function(roomId, medium, address, callback) { +MatrixClient.prototype.inviteByThreePid = async function( + roomId, + medium, + address, + callback, +) { const path = utils.encodeUri( "/rooms/$roomId/invite", { $roomId: roomId }, @@ -2451,12 +2464,23 @@ MatrixClient.prototype.inviteByThreePid = function(roomId, medium, address, call errcode: "ORG.MATRIX.JSSDK_MISSING_PARAM", })); } - - return this._http.authedRequest(callback, "POST", path, undefined, { + const params = { id_server: identityServerUrl, medium: medium, address: address, - }); + }; + + if ( + this.getIdentityAccessToken && + await this.doesServerAcceptIdentityAccessToken() + ) { + const identityAccessToken = await this.getIdentityAccessToken(); + if (identityAccessToken) { + params.id_access_token = identityAccessToken; + } + } + + return this._http.authedRequest(callback, "POST", path, undefined, params); }; /** @@ -3423,7 +3447,7 @@ MatrixClient.prototype.requestPasswordMsisdnToken = function(phoneCountry, phone * @param {object} params Parameters for the POST request * @return {module:client.Promise} Resolves: As requestEmailToken */ -MatrixClient.prototype._requestTokenFromEndpoint = function(endpoint, params) { +MatrixClient.prototype._requestTokenFromEndpoint = async function(endpoint, params) { const postParams = Object.assign({}, params); if (this.idBaseUrl) { @@ -3432,6 +3456,16 @@ MatrixClient.prototype._requestTokenFromEndpoint = function(endpoint, params) { throw new Error("Invalid ID server URL: " + this.idBaseUrl); } postParams.id_server = idServerUrl.host; + + if ( + this.getIdentityAccessToken && + await this.doesServerAcceptIdentityAccessToken() + ) { + const identityAccessToken = await this.getIdentityAccessToken(); + if (identityAccessToken) { + postParams.id_access_token = identityAccessToken; + } + } } return this._http.request( @@ -4092,6 +4126,23 @@ MatrixClient.prototype.doesServerRequireIdServerParam = async function() { } }; +/* + * Query the server to see if the `id_access_token` parameter can be safely + * passed to the homeserver. Some homeservers may trigger errors if they are not + * prepared for the new parameter. + * @return {Promise} true if id_access_token can be sent + */ +MatrixClient.prototype.doesServerAcceptIdentityAccessToken = async function() { + const response = await this.getVersions(); + + const unstableFeatures = response["unstable_features"]; + if (unstableFeatures["m.id_access_token"] === undefined) { + return false; + } + + return unstableFeatures["m.id_access_token"]; +}; + /* * Get if lazy loading members is being used. * @return {boolean} Whether or not members are lazy loaded by this client From 3d274815d9a6686be2adf5bb8594b7fb5d8677f4 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 23 Aug 2019 11:17:39 +0100 Subject: [PATCH 2/2] Change to provider object --- src/base-apis.js | 11 ++++++----- src/client.js | 19 +++++++++++-------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/src/base-apis.js b/src/base-apis.js index f5069c7c344..e8af3400a51 100644 --- a/src/base-apis.js +++ b/src/base-apis.js @@ -63,10 +63,11 @@ function termsUrlForService(serviceType, baseUrl) { * * @param {string} opts.accessToken The access_token for this user. * - * @param {Function} [opts.getIdentityAccessToken] - * Optional. A callback that returns a Promise of an identity access - * token to supply with identity requests. If the callback is unset, no access - * token will be supplied. + * @param {IdentityServerProvider} [opts.identityServer] + * Optional. A provider object with one function `getAccessToken`, which is a + * callback that returns a Promise of an identity access token to supply + * with identity requests. If the object is unset, no access token will be + * supplied. * See also https://github.com/vector-im/riot-web/issues/10615 which seeks to * replace the previous approach of manual access tokens params with this * callback throughout the SDK. @@ -87,7 +88,7 @@ function MatrixBaseApis(opts) { this.baseUrl = opts.baseUrl; this.idBaseUrl = opts.idBaseUrl; - this.getIdentityAccessToken = opts.getIdentityAccessToken; + this.identityServer = opts.identityServer; const httpOpts = { baseUrl: opts.baseUrl, diff --git a/src/client.js b/src/client.js index a87c475f15c..55aa633619f 100644 --- a/src/client.js +++ b/src/client.js @@ -108,10 +108,11 @@ function keyFromRecoverySession(session, decryptionKey) { * * @param {string} opts.userId The user ID for this user. * - * @param {Function} [opts.getIdentityAccessToken] - * Optional. A callback that returns a Promise of an identity access - * token to supply with identity requests. If the callback is unset, no access - * token will be supplied. + * @param {IdentityServerProvider} [opts.identityServer] + * Optional. A provider object with one function `getAccessToken`, which is a + * callback that returns a Promise of an identity access token to supply + * with identity requests. If the object is unset, no access token will be + * supplied. * See also https://github.com/vector-im/riot-web/issues/10615 which seeks to * replace the previous approach of manual access tokens params with this * callback throughout the SDK. @@ -2471,10 +2472,11 @@ MatrixClient.prototype.inviteByThreePid = async function( }; if ( - this.getIdentityAccessToken && + this.identityServer && + this.identityServer.getAccessToken && await this.doesServerAcceptIdentityAccessToken() ) { - const identityAccessToken = await this.getIdentityAccessToken(); + const identityAccessToken = await this.identityServer.getAccessToken(); if (identityAccessToken) { params.id_access_token = identityAccessToken; } @@ -3458,10 +3460,11 @@ MatrixClient.prototype._requestTokenFromEndpoint = async function(endpoint, para postParams.id_server = idServerUrl.host; if ( - this.getIdentityAccessToken && + this.identityServer && + this.identityServer.getAccessToken && await this.doesServerAcceptIdentityAccessToken() ) { - const identityAccessToken = await this.getIdentityAccessToken(); + const identityAccessToken = await this.identityServer.getAccessToken(); if (identityAccessToken) { postParams.id_access_token = identityAccessToken; }