From 9f8a8f8d363b678450e1be9a27bc64bd4b4afb12 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 20 Jan 2022 13:43:24 -0700 Subject: [PATCH 1/5] Add functions for refreshing access tokens --- src/@types/auth.ts | 29 +++++++++++++++++++++++++++++ src/client.ts | 36 +++++++++++++++++++++++++++--------- src/http-api.ts | 8 +++++++- 3 files changed, 63 insertions(+), 10 deletions(-) create mode 100644 src/@types/auth.ts diff --git a/src/@types/auth.ts b/src/@types/auth.ts new file mode 100644 index 00000000000..592974221ba --- /dev/null +++ b/src/@types/auth.ts @@ -0,0 +1,29 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// disable lint because these are wire responses +/* eslint-disable camelcase */ + +/** + * Represents a response to the CSAPI `/refresh` endpoint. + */ +export interface IRefreshTokenResponse { + access_token: string; + expires_in_ms: number; + refresh_token: string; +} + +/* eslint-enable camelcase */ diff --git a/src/client.ts b/src/client.ts index 64d669b3dcf..1f267af1376 100644 --- a/src/client.ts +++ b/src/client.ts @@ -20,7 +20,7 @@ limitations under the License. */ import { EventEmitter } from "events"; -import { EmoteEvent, MessageEvent, NoticeEvent, IPartialEvent } from "matrix-events-sdk"; +import { EmoteEvent, IPartialEvent, MessageEvent, NoticeEvent } from "matrix-events-sdk"; import { ISyncStateData, SyncApi, SyncState } from "./sync"; import { EventStatus, IContent, IDecryptOptions, IEvent, MatrixEvent } from "./models/event"; @@ -87,14 +87,7 @@ import { } from "./crypto/keybackup"; import { IIdentityServerProvider } from "./@types/IIdentityServerProvider"; import { MatrixScheduler } from "./scheduler"; -import { - IAuthData, - ICryptoCallbacks, - IMinimalEvent, - IRoomEvent, - IStateEvent, - NotificationCountType, -} from "./matrix"; +import { IAuthData, ICryptoCallbacks, IMinimalEvent, IRoomEvent, IStateEvent, NotificationCountType, } from "./matrix"; import { CrossSigningKey, IAddSecretStorageKeyOpts, @@ -160,6 +153,7 @@ import { IPusher, IPusherRequest, IPushRules, PushRuleAction, PushRuleKind, Rule import { IThreepid } from "./@types/threepids"; import { CryptoStore } from "./crypto/store/base"; import { MediaHandler } from "./webrtc/mediaHandler"; +import { IRefreshTokenResponse } from "./@types/auth"; export type Store = IStore; export type SessionStore = WebStorageSessionStore; @@ -6695,6 +6689,7 @@ export class MatrixClient extends EventEmitter { const params: any = { auth: auth, + refresh_token: true, // always ask for a refresh token - does nothing if unsupported }; if (username !== undefined && username !== null) { params.username = username; @@ -6772,6 +6767,29 @@ export class MatrixClient extends EventEmitter { return this.http.request(callback, Method.Post, "/register", params, data); } + /** + * Refreshes an access token using a provided refresh token. The refresh token + * must be valid for the current access token known to the client instance. + * + * Note that this function will not cause a logout if the token is deemed + * unknown by the server - the caller is responsible for managing logout + * actions on error. + * @param {string} refreshToken The refresh token. + * @return {Promise} Resolves to the new token. + * @return {module:http-api.MatrixError} Rejects with an error response. + */ + public refreshToken(refreshToken: string): Promise { + return this.http.authedRequest( + undefined, Method.Post, "/_matrix/client/v1/refresh", + undefined, { + refresh_token: refreshToken, + }, { + prefix: "", // set manually + inhibitLogoutEmit: true, // we don't want to cause logout loops + }, + ); + } + /** * @param {module:client.callback} callback Optional. * @return {Promise} Resolves: TODO diff --git a/src/http-api.ts b/src/http-api.ts index 331fcb24821..fd016c731e8 100644 --- a/src/http-api.ts +++ b/src/http-api.ts @@ -111,6 +111,12 @@ interface IRequestOpts { json?: boolean; // defaults to true qsStringifyOptions?: CoreOptions["qsStringifyOptions"]; bodyParser?(body: string): T; + + // Set to true to prevent the request function from emitting + // a Session.logged_out event. This is intended for use on + // endpoints where M_UNKNOWN_TOKEN is a valid/notable error + // response, such as with token refreshes. + inhibitLogoutEmit?: boolean; } export interface IUpload { @@ -596,7 +602,7 @@ export class MatrixHttpApi { const requestPromise = this.request(callback, method, path, queryParams, data, requestOpts); requestPromise.catch((err: MatrixError) => { - if (err.errcode == 'M_UNKNOWN_TOKEN') { + if (err.errcode == 'M_UNKNOWN_TOKEN' && !requestOpts?.inhibitLogoutEmit) { this.eventEmitter.emit("Session.logged_out", err); } else if (err.errcode == 'M_CONSENT_NOT_GIVEN') { this.eventEmitter.emit( From 7614f3b7ea9b1594453ec1d4367f25fd2172d585 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Thu, 20 Jan 2022 14:35:14 -0700 Subject: [PATCH 2/5] Add function to change the client's access token in flight --- src/client.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/client.ts b/src/client.ts index 1f267af1376..5f1ac84314c 100644 --- a/src/client.ts +++ b/src/client.ts @@ -6613,6 +6613,14 @@ export class MatrixClient extends EventEmitter { return this.http.opts.accessToken || null; } + /** + * Set the access token associated with this account. + * @param {string} token The new access token. + */ + public setAccessToken(token: string) { + this.http.opts.accessToken = token; + } + /** * @return {boolean} true if there is a valid access_token for this client. */ From 7b4c7048d6f3f53483374901883e2042d73f9760 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 14 Feb 2022 20:36:56 -0700 Subject: [PATCH 3/5] Appease the linter --- src/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client.ts b/src/client.ts index 5f1ac84314c..0d3c1262221 100644 --- a/src/client.ts +++ b/src/client.ts @@ -87,7 +87,7 @@ import { } from "./crypto/keybackup"; import { IIdentityServerProvider } from "./@types/IIdentityServerProvider"; import { MatrixScheduler } from "./scheduler"; -import { IAuthData, ICryptoCallbacks, IMinimalEvent, IRoomEvent, IStateEvent, NotificationCountType, } from "./matrix"; +import { IAuthData, ICryptoCallbacks, IMinimalEvent, IRoomEvent, IStateEvent, NotificationCountType } from "./matrix"; import { CrossSigningKey, IAddSecretStorageKeyOpts, From 3b81d3100f203762f2f6ebea707770c8ba9f012c Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 15 Feb 2022 13:02:32 -0700 Subject: [PATCH 4/5] Use sensible code style --- src/client.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/client.ts b/src/client.ts index 0d3c1262221..d4fd4d94e54 100644 --- a/src/client.ts +++ b/src/client.ts @@ -51,7 +51,8 @@ import { PREFIX_IDENTITY_V2, PREFIX_MEDIA_R0, PREFIX_R0, - PREFIX_UNSTABLE, + PREFIX_UNSTABLE, + PREFIX_V1, retryNetworkOperation, UploadContentResponseType, } from "./http-api"; @@ -6788,11 +6789,13 @@ export class MatrixClient extends EventEmitter { */ public refreshToken(refreshToken: string): Promise { return this.http.authedRequest( - undefined, Method.Post, "/_matrix/client/v1/refresh", - undefined, { - refresh_token: refreshToken, - }, { - prefix: "", // set manually + undefined, + Method.Post, + "/refresh", + undefined, + { refresh_token: refreshToken }, + { + prefix: PREFIX_V1, inhibitLogoutEmit: true, // we don't want to cause logout loops }, ); From 53393a148b1f9dce7fd7885a80c85fc0f35913d9 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 15 Feb 2022 13:04:43 -0700 Subject: [PATCH 5/5] lint --- src/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client.ts b/src/client.ts index d4fd4d94e54..dafa4937f93 100644 --- a/src/client.ts +++ b/src/client.ts @@ -51,7 +51,7 @@ import { PREFIX_IDENTITY_V2, PREFIX_MEDIA_R0, PREFIX_R0, - PREFIX_UNSTABLE, + PREFIX_UNSTABLE, PREFIX_V1, retryNetworkOperation, UploadContentResponseType,