From 618d02d838b62abf37ac24cca6b626059be1a812 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 23 Dec 2021 15:17:09 +0530 Subject: [PATCH 01/54] fetch registration flows --- src/matrix/net/HomeServerApi.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/matrix/net/HomeServerApi.ts b/src/matrix/net/HomeServerApi.ts index a23321f9..4a84adf0 100644 --- a/src/matrix/net/HomeServerApi.ts +++ b/src/matrix/net/HomeServerApi.ts @@ -26,6 +26,7 @@ import type {ILogItem} from "../../logging/types"; type RequestMethod = "POST" | "GET" | "PUT"; const CS_R0_PREFIX = "/_matrix/client/r0"; +const CS_V3_PREFIX = "/_matrix/client/v3"; const DEHYDRATION_PREFIX = "/_matrix/client/unstable/org.matrix.msc2697.v2"; type Options = { @@ -163,6 +164,10 @@ export class HomeServerApi { return this._unauthedRequest("GET", this._url("/login")); } + getRegistrationFlows(): IHomeServerRequest { + return this._unauthedRequest("POST", this._url("/register", CS_V3_PREFIX), undefined, { auth: {} }); + } + passwordLogin(username: string, password: string, initialDeviceDisplayName: string, options?: IRequestOptions): IHomeServerRequest { return this._unauthedRequest("POST", this._url("/login"), undefined, { "type": "m.login.password", From eb146830ba51757901469e4bb8e442deacc3ec50 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Sun, 26 Dec 2021 17:57:27 +0530 Subject: [PATCH 02/54] Implement registration endpoint --- src/matrix/net/HomeServerApi.ts | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/src/matrix/net/HomeServerApi.ts b/src/matrix/net/HomeServerApi.ts index 4a84adf0..606514ae 100644 --- a/src/matrix/net/HomeServerApi.ts +++ b/src/matrix/net/HomeServerApi.ts @@ -85,7 +85,8 @@ export class HomeServerApi { body: encodedBody, timeout: options?.timeout, uploadProgress: options?.uploadProgress, - format: "json" // response format + format: "json", // response format + cache: options?.cache ?? false }); const hsRequest = new HomeServerRequest(method, url, requestResult, log); @@ -164,8 +165,25 @@ export class HomeServerApi { return this._unauthedRequest("GET", this._url("/login")); } - getRegistrationFlows(): IHomeServerRequest { - return this._unauthedRequest("POST", this._url("/register", CS_V3_PREFIX), undefined, { auth: {} }); + register(username: string, password: string, initialDeviceDisplayName: string, auth?: Record, inhibitLogin?: boolean , options?: IRequestOptions): IHomeServerRequest { + // todo: This is so that we disable cache-buster because it would cause the hs to respond with error + // see https://github.com/matrix-org/synapse/issues/7722 + // need to this about the implications of this later + const _options = options ?? {}; + Object.assign(_options, { cache: true }); + return this._unauthedRequest( + "POST", + this._url("/register", CS_V3_PREFIX), + undefined, + { + auth, + username, + password, + initial_device_displayname: initialDeviceDisplayName, + inhibit_login: inhibitLogin ?? false, + }, + _options + ); } passwordLogin(username: string, password: string, initialDeviceDisplayName: string, options?: IRequestOptions): IHomeServerRequest { From d28ab919bbc3cb10115cf9c1baba9600d55cc754 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Sun, 26 Dec 2021 17:59:04 +0530 Subject: [PATCH 03/54] Implement dummy registration logic --- src/matrix/registration/Registration.ts | 85 +++++++++++++++++++ .../registration/registrationStageFromType.ts | 24 ++++++ .../stages/BaseRegistrationStage.ts | 64 ++++++++++++++ src/matrix/registration/stages/DummyAuth.ts | 33 +++++++ 4 files changed, 206 insertions(+) create mode 100644 src/matrix/registration/Registration.ts create mode 100644 src/matrix/registration/registrationStageFromType.ts create mode 100644 src/matrix/registration/stages/BaseRegistrationStage.ts create mode 100644 src/matrix/registration/stages/DummyAuth.ts diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts new file mode 100644 index 00000000..9dcfdbe2 --- /dev/null +++ b/src/matrix/registration/Registration.ts @@ -0,0 +1,85 @@ +/* +Copyright 2021 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. +*/ + +import type {HomeServerApi} from "../net/HomeServerApi"; +import { registrationStageFromType } from "./registrationStageFromType"; +import type {BaseRegistrationStage} from "./stages/BaseRegistrationStage"; + +export type RegistrationParameters = { + username: string; + password: string; + initialDeviceDisplayName: string; + inhibitLogin: boolean; +} + +// todo: type this later +export type RegistrationResponse = { + [key: string]: any; +} + +export class Registration { + private _hsApi: HomeServerApi; + private _data: RegistrationParameters; + private _firstStage: BaseRegistrationStage; + private _session: string; + + constructor(hsApi: HomeServerApi, data: RegistrationParameters) { + this._hsApi = hsApi; + this._data = data; + } + + private async _fetchFlows(): Promise { + const response = await this._hsApi.register( + this._username, + this._password, + this._initialDeviceDisplayName, + undefined, + this._inhibitLogin).response(); + return response; + } + + async start(): Promise { + const response = await this._fetchFlows(); + this.parseStagesFromResponse(response); + await new Promise(r => setTimeout(r, 2000)); + return this._firstStage; + } + + parseStagesFromResponse(response: RegistrationResponse) { + this._session = response.session; + const flow = response.flows.pop(); + let lastStage: BaseRegistrationStage; + for (const stage of flow.stages) { + const stageClass = registrationStageFromType(stage); + if (!stageClass) { + throw new Error("Unknown stage"); + } + const registrationStage = new stageClass(this._hsApi, this._data, this._session); + if (!this._firstStage) { + this._firstStage = registrationStage; + lastStage = registrationStage; + } else { + lastStage!.setNextStage(registrationStage); + lastStage = registrationStage; + } + } + } + + private get _username() { return this._data.username; } + private get _password() { return this._data.password; } + private get _initialDeviceDisplayName() { return this._data.initialDeviceDisplayName; } + private get _inhibitLogin() { return this._data.inhibitLogin; } +} diff --git a/src/matrix/registration/registrationStageFromType.ts b/src/matrix/registration/registrationStageFromType.ts new file mode 100644 index 00000000..3a9950fd --- /dev/null +++ b/src/matrix/registration/registrationStageFromType.ts @@ -0,0 +1,24 @@ +/* +Copyright 2021 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. +*/ + +import {DummyAuth} from "./stages/DummyAuth"; + +export function registrationStageFromType(type: string): typeof DummyAuth | undefined { + switch (type) { + case "m.login.dummy": + return DummyAuth; + } +} diff --git a/src/matrix/registration/stages/BaseRegistrationStage.ts b/src/matrix/registration/stages/BaseRegistrationStage.ts new file mode 100644 index 00000000..6c5ae256 --- /dev/null +++ b/src/matrix/registration/stages/BaseRegistrationStage.ts @@ -0,0 +1,64 @@ +/* +Copyright 2021 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. +*/ + +export type Auth = { + [key: string]: any; +} + +import type {HomeServerApi} from "../../net/HomeServerApi"; +import type {RegistrationParameters, RegistrationResponse} from "../Registration"; + +export abstract class BaseRegistrationStage { + protected _hsApi: HomeServerApi; + protected _registrationData: RegistrationParameters; + protected _session: string; + protected _nextStage: BaseRegistrationStage; + + constructor(hsApi: HomeServerApi, registrationData: RegistrationParameters, session: string) { + this._hsApi = hsApi; + this._registrationData = registrationData; + this._session = session; + } + + /** + * eg: m.login.recaptcha or m.login.dummy + */ + abstract get type(): string; + + /** + * Finish a registration stage, return value is: + * - the next stage if this stage was completed successfully + * - true if registration is completed + * - an error if something went wrong + */ + abstract complete(auth?: Auth): Promise; + + setNextStage(stage: BaseRegistrationStage) { + this._nextStage = stage; + } + + parseResponse(response: RegistrationResponse) { + if (response.user_id) { + // registration completed successfully + return true; + } + else if (response.completed?.forEach(c => c === this.type)) { + return this._nextStage; + } + const error = response.error ?? "Could not parse response"; + return new Error(error); + } +} diff --git a/src/matrix/registration/stages/DummyAuth.ts b/src/matrix/registration/stages/DummyAuth.ts new file mode 100644 index 00000000..4a5d9bd8 --- /dev/null +++ b/src/matrix/registration/stages/DummyAuth.ts @@ -0,0 +1,33 @@ +/* +Copyright 2021 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. +*/ + +import {BaseRegistrationStage} from "./BaseRegistrationStage"; + +export class DummyAuth extends BaseRegistrationStage { + + async complete() { + const { username, password, initialDeviceDisplayName, inhibitLogin } = this._registrationData; + const response = await this._hsApi.register(username, password, initialDeviceDisplayName, { + session: this._session, + type: this.type + }, inhibitLogin).response(); + return this.parseResponse(response); + } + + get type(): string { + return "m.login.dummy"; + } +} From d76a05952508129048cbb9e53a9939aa0be14229 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Sun, 26 Dec 2021 18:01:38 +0530 Subject: [PATCH 04/54] Temporary fix for 401 errors --- src/matrix/net/HomeServerRequest.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/matrix/net/HomeServerRequest.ts b/src/matrix/net/HomeServerRequest.ts index ea5d2e40..d9c31275 100644 --- a/src/matrix/net/HomeServerRequest.ts +++ b/src/matrix/net/HomeServerRequest.ts @@ -36,7 +36,10 @@ export class HomeServerRequest implements IHomeServerRequest { this._promise = sourceRequest.response().then(response => { log?.set("status", response.status); // ok? - if (response.status >= 200 && response.status < 300) { + // todo: register endpoint indicates our progress in using the user interactive + // authentication using 401 responses + // passing through all 401 responses as a temporary fix + if (response.status >= 200 && response.status < 300 || response.status === 401) { log?.finish(); return response.body; } else { From a59b67ec45db4b7465b358fdabb3cdb4dbd067a8 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Sun, 26 Dec 2021 21:54:27 +0530 Subject: [PATCH 05/54] Fix errors --- src/matrix/registration/Registration.ts | 1 - src/matrix/registration/stages/BaseRegistrationStage.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index 9dcfdbe2..1432f41a 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -54,7 +54,6 @@ export class Registration { async start(): Promise { const response = await this._fetchFlows(); this.parseStagesFromResponse(response); - await new Promise(r => setTimeout(r, 2000)); return this._firstStage; } diff --git a/src/matrix/registration/stages/BaseRegistrationStage.ts b/src/matrix/registration/stages/BaseRegistrationStage.ts index 6c5ae256..51115974 100644 --- a/src/matrix/registration/stages/BaseRegistrationStage.ts +++ b/src/matrix/registration/stages/BaseRegistrationStage.ts @@ -55,7 +55,7 @@ export abstract class BaseRegistrationStage { // registration completed successfully return true; } - else if (response.completed?.forEach(c => c === this.type)) { + else if (response.completed?.find(c => c === this.type)) { return this._nextStage; } const error = response.error ?? "Could not parse response"; From 18e2fc108928f514ca8ff2c4db4abbcda16fc48d Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Mon, 27 Dec 2021 12:54:54 +0530 Subject: [PATCH 06/54] Pass in params to BaseRegistrationStage --- src/matrix/registration/Registration.ts | 5 ++--- src/matrix/registration/stages/BaseRegistrationStage.ts | 4 +++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index 1432f41a..312c442b 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -34,7 +34,6 @@ export class Registration { private _hsApi: HomeServerApi; private _data: RegistrationParameters; private _firstStage: BaseRegistrationStage; - private _session: string; constructor(hsApi: HomeServerApi, data: RegistrationParameters) { this._hsApi = hsApi; @@ -58,7 +57,7 @@ export class Registration { } parseStagesFromResponse(response: RegistrationResponse) { - this._session = response.session; + const { session, params } = response; const flow = response.flows.pop(); let lastStage: BaseRegistrationStage; for (const stage of flow.stages) { @@ -66,7 +65,7 @@ export class Registration { if (!stageClass) { throw new Error("Unknown stage"); } - const registrationStage = new stageClass(this._hsApi, this._data, this._session); + const registrationStage = new stageClass(this._hsApi, this._data, session, params?.[stage]); if (!this._firstStage) { this._firstStage = registrationStage; lastStage = registrationStage; diff --git a/src/matrix/registration/stages/BaseRegistrationStage.ts b/src/matrix/registration/stages/BaseRegistrationStage.ts index 51115974..1458c554 100644 --- a/src/matrix/registration/stages/BaseRegistrationStage.ts +++ b/src/matrix/registration/stages/BaseRegistrationStage.ts @@ -26,11 +26,13 @@ export abstract class BaseRegistrationStage { protected _registrationData: RegistrationParameters; protected _session: string; protected _nextStage: BaseRegistrationStage; + protected _params?: Record - constructor(hsApi: HomeServerApi, registrationData: RegistrationParameters, session: string) { + constructor(hsApi: HomeServerApi, registrationData: RegistrationParameters, session: string, params?: Record) { this._hsApi = hsApi; this._registrationData = registrationData; this._session = session; + this._params = params; } /** From 8ab8726b8f0d57757b17c92998ced34a99c2c6c5 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Mon, 27 Dec 2021 13:14:07 +0530 Subject: [PATCH 07/54] Implement m.login.terms stage --- .../registration/registrationStageFromType.ts | 10 ++++- src/matrix/registration/stages/TermsAuth.ts | 39 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 src/matrix/registration/stages/TermsAuth.ts diff --git a/src/matrix/registration/registrationStageFromType.ts b/src/matrix/registration/registrationStageFromType.ts index 3a9950fd..44913f94 100644 --- a/src/matrix/registration/registrationStageFromType.ts +++ b/src/matrix/registration/registrationStageFromType.ts @@ -14,11 +14,19 @@ See the License for the specific language governing permissions and limitations under the License. */ +import type {BaseRegistrationStage} from "./stages/BaseRegistrationStage"; +import type {HomeServerApi} from "../net/HomeServerApi"; +import type {RegistrationParameters} from "./Registration"; import {DummyAuth} from "./stages/DummyAuth"; +import {TermsAuth} from "./stages/TermsAuth"; -export function registrationStageFromType(type: string): typeof DummyAuth | undefined { +type DerivedFromBaseRegistration = { new(hsApi: HomeServerApi, registrationData: RegistrationParameters, session: string, params?: Record): BaseRegistrationStage } & typeof BaseRegistrationStage | undefined; + +export function registrationStageFromType(type: string): DerivedFromBaseRegistration { switch (type) { case "m.login.dummy": return DummyAuth; + case "m.login.terms": + return TermsAuth; } } diff --git a/src/matrix/registration/stages/TermsAuth.ts b/src/matrix/registration/stages/TermsAuth.ts new file mode 100644 index 00000000..0114d27d --- /dev/null +++ b/src/matrix/registration/stages/TermsAuth.ts @@ -0,0 +1,39 @@ +/* +Copyright 2021 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. +*/ + +import {BaseRegistrationStage} from "./BaseRegistrationStage"; + +export class TermsAuth extends BaseRegistrationStage { + + async complete() { + const { username, password, initialDeviceDisplayName, inhibitLogin } = this._registrationData; + const response = await this._hsApi.register(username, password, initialDeviceDisplayName, { + session: this._session, + type: this.type + }, inhibitLogin).response(); + return this.parseResponse(response); + } + + get type(): string { + return "m.login.terms"; + } + + // todo: add better parsing logic here, also remember that server admins can + // require any sort documents here, even those that are not toc/privacy policies + get privacyPolicy() { + return this._params?.policies["privacy_policy"]; + } +} From 170d7a5e555358eb93d307d4579fe0806618f705 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 5 Jan 2022 12:45:41 +0530 Subject: [PATCH 08/54] Add startRegistration method --- src/matrix/Client.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/matrix/Client.js b/src/matrix/Client.js index f070d24c..bc35703a 100644 --- a/src/matrix/Client.js +++ b/src/matrix/Client.js @@ -30,6 +30,7 @@ import {PasswordLoginMethod} from "./login/PasswordLoginMethod"; import {TokenLoginMethod} from "./login/TokenLoginMethod"; import {SSOLoginHelper} from "./login/SSOLoginHelper"; import {getDehydratedDevice} from "./e2ee/Dehydration.js"; +import {Registration} from "./registration/Registration"; export const LoadStatus = createEnum( "NotLoading", @@ -131,6 +132,19 @@ export class Client { }); } + async startRegistration(homeserver, username, password, initialDeviceDisplayName) { + const request = this._platform.request; + const hsApi = new HomeServerApi({homeserver, request}); + const registration = new Registration(hsApi, { + username, + password, + initialDeviceDisplayName, + inhibitLogin: true + }); + let stage = await registration.start(); + return stage; + } + async startWithLogin(loginMethod, {inspectAccountSetup} = {}) { const currentStatus = this._status.get(); if (currentStatus !== LoadStatus.LoginFailed && From fa2e2bc8f33b0af8b0a649f8a9cc2e25c182a5b8 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 20 Jan 2022 12:34:36 +0530 Subject: [PATCH 09/54] Allow register without providing username --- src/matrix/net/HomeServerApi.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/matrix/net/HomeServerApi.ts b/src/matrix/net/HomeServerApi.ts index 606514ae..62008087 100644 --- a/src/matrix/net/HomeServerApi.ts +++ b/src/matrix/net/HomeServerApi.ts @@ -165,19 +165,20 @@ export class HomeServerApi { return this._unauthedRequest("GET", this._url("/login")); } - register(username: string, password: string, initialDeviceDisplayName: string, auth?: Record, inhibitLogin?: boolean , options?: IRequestOptions): IHomeServerRequest { + register(username: string | null, password: string, initialDeviceDisplayName: string, auth?: Record, inhibitLogin?: boolean , options?: IRequestOptions): IHomeServerRequest { // todo: This is so that we disable cache-buster because it would cause the hs to respond with error // see https://github.com/matrix-org/synapse/issues/7722 // need to this about the implications of this later const _options = options ?? {}; Object.assign(_options, { cache: true }); + const _username = username ?? undefined; return this._unauthedRequest( "POST", this._url("/register", CS_V3_PREFIX), undefined, { auth, - username, + _username, password, initial_device_displayname: initialDeviceDisplayName, inhibit_login: inhibitLogin ?? false, From 792d5c62c52775d1b34fd73b4ed5ca7910ad059d Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 20 Jan 2022 12:35:11 +0530 Subject: [PATCH 10/54] Return username when registration is completed --- src/matrix/registration/stages/BaseRegistrationStage.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/matrix/registration/stages/BaseRegistrationStage.ts b/src/matrix/registration/stages/BaseRegistrationStage.ts index 1458c554..4c15bb5e 100644 --- a/src/matrix/registration/stages/BaseRegistrationStage.ts +++ b/src/matrix/registration/stages/BaseRegistrationStage.ts @@ -43,10 +43,10 @@ export abstract class BaseRegistrationStage { /** * Finish a registration stage, return value is: * - the next stage if this stage was completed successfully - * - true if registration is completed + * - user-id (string) if registration is completed * - an error if something went wrong */ - abstract complete(auth?: Auth): Promise; + abstract complete(auth?: Auth): Promise; setNextStage(stage: BaseRegistrationStage) { this._nextStage = stage; @@ -55,7 +55,7 @@ export abstract class BaseRegistrationStage { parseResponse(response: RegistrationResponse) { if (response.user_id) { // registration completed successfully - return true; + return response.user_id; } else if (response.completed?.find(c => c === this.type)) { return this._nextStage; From 420c12f2023dc16003dc32c48ec302d3a2994e31 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 1 Feb 2022 12:52:52 +0530 Subject: [PATCH 11/54] Copy over username only if it exists --- src/matrix/net/HomeServerApi.ts | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/matrix/net/HomeServerApi.ts b/src/matrix/net/HomeServerApi.ts index 62008087..6a0e0bca 100644 --- a/src/matrix/net/HomeServerApi.ts +++ b/src/matrix/net/HomeServerApi.ts @@ -168,23 +168,19 @@ export class HomeServerApi { register(username: string | null, password: string, initialDeviceDisplayName: string, auth?: Record, inhibitLogin?: boolean , options?: IRequestOptions): IHomeServerRequest { // todo: This is so that we disable cache-buster because it would cause the hs to respond with error // see https://github.com/matrix-org/synapse/issues/7722 - // need to this about the implications of this later const _options = options ?? {}; Object.assign(_options, { cache: true }); - const _username = username ?? undefined; - return this._unauthedRequest( - "POST", - this._url("/register", CS_V3_PREFIX), - undefined, - { - auth, - _username, - password, - initial_device_displayname: initialDeviceDisplayName, - inhibit_login: inhibitLogin ?? false, - }, - _options - ); + const body = { + auth, + password, + initial_device_displayname: initialDeviceDisplayName, + inhibit_login: inhibitLogin ?? false, + }; + if (username) { + // username is optional for registration + Object.assign(body, { username }); + } + return this._unauthedRequest( "POST", this._url("/register", CS_V3_PREFIX), undefined, body, _options); } passwordLogin(username: string, password: string, initialDeviceDisplayName: string, options?: IRequestOptions): IHomeServerRequest { From bb6a885116bd72d64c52679589c8cde682b1926c Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 1 Feb 2022 15:38:55 +0530 Subject: [PATCH 12/54] Specify what errors are ignored in options --- src/matrix/net/HomeServerApi.ts | 13 ++----------- src/matrix/net/HomeServerRequest.ts | 13 ++++++++----- src/platform/types/types.ts | 1 + 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/matrix/net/HomeServerApi.ts b/src/matrix/net/HomeServerApi.ts index 6a0e0bca..a722da30 100644 --- a/src/matrix/net/HomeServerApi.ts +++ b/src/matrix/net/HomeServerApi.ts @@ -58,15 +58,6 @@ export class HomeServerApi { private _baseRequest(method: RequestMethod, url: string, queryParams?: Record, body?: Record, options?: IRequestOptions, accessToken?: string): IHomeServerRequest { const queryString = encodeQueryParams(queryParams); url = `${url}?${queryString}`; - let log: ILogItem | undefined; - if (options?.log) { - const parent = options?.log; - log = parent.child({ - t: "network", - url, - method, - }, parent.level.Info); - } let encodedBody: EncodedBody["body"]; const headers: Map = new Map(); if (accessToken) { @@ -89,7 +80,7 @@ export class HomeServerApi { cache: options?.cache ?? false }); - const hsRequest = new HomeServerRequest(method, url, requestResult, log); + const hsRequest = new HomeServerRequest(method, url, requestResult, options); if (this._reconnector) { hsRequest.response().catch(err => { @@ -169,7 +160,7 @@ export class HomeServerApi { // todo: This is so that we disable cache-buster because it would cause the hs to respond with error // see https://github.com/matrix-org/synapse/issues/7722 const _options = options ?? {}; - Object.assign(_options, { cache: true }); + Object.assign(_options, { cache: true, allowedErrors: [401] }); const body = { auth, password, diff --git a/src/matrix/net/HomeServerRequest.ts b/src/matrix/net/HomeServerRequest.ts index d9c31275..cbbb4e90 100644 --- a/src/matrix/net/HomeServerRequest.ts +++ b/src/matrix/net/HomeServerRequest.ts @@ -18,6 +18,7 @@ limitations under the License. import {HomeServerError, ConnectionError} from "../error.js"; import type {RequestResult} from "../../platform/web/dom/request/fetch.js"; import type {ILogItem} from "../../logging/types"; +import type {IRequestOptions} from "../../platform/types/types.js"; export interface IHomeServerRequest { abort(): void; @@ -30,16 +31,18 @@ export class HomeServerRequest implements IHomeServerRequest { // as we add types for expected responses from hs, this could be a generic class instead private readonly _promise: Promise; - constructor(method: string, url: string, sourceRequest: RequestResult, log?: ILogItem) { + constructor(method: string, url: string, sourceRequest: RequestResult, options?: IRequestOptions) { + let log: ILogItem | undefined; + if (options?.log) { + const parent = options?.log; + log = parent.child({ t: "network", url, method, }, parent.level.Info); + } this._log = log; this._sourceRequest = sourceRequest; this._promise = sourceRequest.response().then(response => { log?.set("status", response.status); // ok? - // todo: register endpoint indicates our progress in using the user interactive - // authentication using 401 responses - // passing through all 401 responses as a temporary fix - if (response.status >= 200 && response.status < 300 || response.status === 401) { + if (response.status >= 200 && response.status < 300 || options?.allowedErrors?.find(e => e === response.status)) { log?.finish(); return response.body; } else { diff --git a/src/platform/types/types.ts b/src/platform/types/types.ts index 58d2216f..0ad569b4 100644 --- a/src/platform/types/types.ts +++ b/src/platform/types/types.ts @@ -28,6 +28,7 @@ export interface IRequestOptions { prefix?: string; method?: string; format?: string; + allowedErrors?: number[]; } export type RequestFunction = (url: string, options: IRequestOptions) => RequestResult; From 5e93e048ab83532f772c2ef0bfd2d141986341af Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 1 Feb 2022 17:07:32 +0530 Subject: [PATCH 13/54] Don't cache GET requests --- src/matrix/net/HomeServerApi.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/matrix/net/HomeServerApi.ts b/src/matrix/net/HomeServerApi.ts index a722da30..45e8a56c 100644 --- a/src/matrix/net/HomeServerApi.ts +++ b/src/matrix/net/HomeServerApi.ts @@ -77,7 +77,7 @@ export class HomeServerApi { timeout: options?.timeout, uploadProgress: options?.uploadProgress, format: "json", // response format - cache: options?.cache ?? false + cache: method !== "GET", }); const hsRequest = new HomeServerRequest(method, url, requestResult, options); @@ -160,7 +160,7 @@ export class HomeServerApi { // todo: This is so that we disable cache-buster because it would cause the hs to respond with error // see https://github.com/matrix-org/synapse/issues/7722 const _options = options ?? {}; - Object.assign(_options, { cache: true, allowedErrors: [401] }); + Object.assign(_options, { allowedErrors: [401] }); const body = { auth, password, From 755f934eb28b2104611385c2098bcd5c482dc2bf Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 1 Feb 2022 17:40:09 +0530 Subject: [PATCH 14/54] No need to explicitly pass in inhibitLogin --- src/matrix/Client.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/matrix/Client.js b/src/matrix/Client.js index bc35703a..22e686d0 100644 --- a/src/matrix/Client.js +++ b/src/matrix/Client.js @@ -139,7 +139,6 @@ export class Client { username, password, initialDeviceDisplayName, - inhibitLogin: true }); let stage = await registration.start(); return stage; From e8dbbd876cf2ccb4b40c75b7a441dc972de5d1fb Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 1 Feb 2022 17:45:14 +0530 Subject: [PATCH 15/54] Give default values to parameters --- src/matrix/net/HomeServerApi.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/matrix/net/HomeServerApi.ts b/src/matrix/net/HomeServerApi.ts index 45e8a56c..e5071b87 100644 --- a/src/matrix/net/HomeServerApi.ts +++ b/src/matrix/net/HomeServerApi.ts @@ -156,22 +156,19 @@ export class HomeServerApi { return this._unauthedRequest("GET", this._url("/login")); } - register(username: string | null, password: string, initialDeviceDisplayName: string, auth?: Record, inhibitLogin?: boolean , options?: IRequestOptions): IHomeServerRequest { - // todo: This is so that we disable cache-buster because it would cause the hs to respond with error - // see https://github.com/matrix-org/synapse/issues/7722 - const _options = options ?? {}; - Object.assign(_options, { allowedErrors: [401] }); + register(username: string | null, password: string, initialDeviceDisplayName: string, auth?: Record, inhibitLogin: boolean = true , options: IRequestOptions = {}): IHomeServerRequest { + Object.assign(options, { allowedErrors: [401] }); const body = { auth, password, initial_device_displayname: initialDeviceDisplayName, - inhibit_login: inhibitLogin ?? false, + inhibit_login: inhibitLogin, }; if (username) { // username is optional for registration Object.assign(body, { username }); } - return this._unauthedRequest( "POST", this._url("/register", CS_V3_PREFIX), undefined, body, _options); + return this._unauthedRequest( "POST", this._url("/register", CS_V3_PREFIX), undefined, body, options); } passwordLogin(username: string, password: string, initialDeviceDisplayName: string, options?: IRequestOptions): IHomeServerRequest { From 5f11790f6bd9b624f41be501e56c2afaca2aca0a Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 1 Feb 2022 17:51:37 +0530 Subject: [PATCH 16/54] Object.assign is overkill here --- src/matrix/net/HomeServerApi.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/matrix/net/HomeServerApi.ts b/src/matrix/net/HomeServerApi.ts index e5071b87..7f7dd16c 100644 --- a/src/matrix/net/HomeServerApi.ts +++ b/src/matrix/net/HomeServerApi.ts @@ -158,7 +158,7 @@ export class HomeServerApi { register(username: string | null, password: string, initialDeviceDisplayName: string, auth?: Record, inhibitLogin: boolean = true , options: IRequestOptions = {}): IHomeServerRequest { Object.assign(options, { allowedErrors: [401] }); - const body = { + const body: any = { auth, password, initial_device_displayname: initialDeviceDisplayName, @@ -166,7 +166,7 @@ export class HomeServerApi { }; if (username) { // username is optional for registration - Object.assign(body, { username }); + body.username = username; } return this._unauthedRequest( "POST", this._url("/register", CS_V3_PREFIX), undefined, body, options); } From 550a560f40330468a7ce05a59e27c295702f842b Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 1 Feb 2022 17:54:08 +0530 Subject: [PATCH 17/54] Remove space --- src/matrix/registration/Registration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index 312c442b..72f0c401 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -15,7 +15,7 @@ limitations under the License. */ import type {HomeServerApi} from "../net/HomeServerApi"; -import { registrationStageFromType } from "./registrationStageFromType"; +import {registrationStageFromType} from "./registrationStageFromType"; import type {BaseRegistrationStage} from "./stages/BaseRegistrationStage"; export type RegistrationParameters = { From a91ba4370df3e218e5cc181098d5cbd20365b38e Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 1 Feb 2022 17:56:43 +0530 Subject: [PATCH 18/54] Change type to show that username is optional --- src/matrix/registration/Registration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index 72f0c401..d0f11a1c 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -19,7 +19,7 @@ import {registrationStageFromType} from "./registrationStageFromType"; import type {BaseRegistrationStage} from "./stages/BaseRegistrationStage"; export type RegistrationParameters = { - username: string; + username: string | null; password: string; initialDeviceDisplayName: string; inhibitLogin: boolean; From 2d4c1065427e6c1b6033face676d3d359694e1a8 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 1 Feb 2022 18:01:33 +0530 Subject: [PATCH 19/54] REFACTOR: Inline method --- src/matrix/registration/Registration.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index d0f11a1c..e9c0b512 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -40,18 +40,13 @@ export class Registration { this._data = data; } - private async _fetchFlows(): Promise { + async start(): Promise { const response = await this._hsApi.register( this._username, this._password, this._initialDeviceDisplayName, undefined, this._inhibitLogin).response(); - return response; - } - - async start(): Promise { - const response = await this._fetchFlows(); this.parseStagesFromResponse(response); return this._firstStage; } From 2f3865d8cc8407c4a1adc27e7155ac6279338e5a Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 1 Feb 2022 18:23:41 +0530 Subject: [PATCH 20/54] firstStage should be a local variable --- src/matrix/registration/Registration.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index e9c0b512..c6e26604 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -33,7 +33,6 @@ export type RegistrationResponse = { export class Registration { private _hsApi: HomeServerApi; private _data: RegistrationParameters; - private _firstStage: BaseRegistrationStage; constructor(hsApi: HomeServerApi, data: RegistrationParameters) { this._hsApi = hsApi; @@ -47,13 +46,13 @@ export class Registration { this._initialDeviceDisplayName, undefined, this._inhibitLogin).response(); - this.parseStagesFromResponse(response); - return this._firstStage; + return this.parseStagesFromResponse(response); } - parseStagesFromResponse(response: RegistrationResponse) { + parseStagesFromResponse(response: RegistrationResponse): BaseRegistrationStage { const { session, params } = response; const flow = response.flows.pop(); + let firstStage: BaseRegistrationStage | undefined; let lastStage: BaseRegistrationStage; for (const stage of flow.stages) { const stageClass = registrationStageFromType(stage); @@ -61,14 +60,15 @@ export class Registration { throw new Error("Unknown stage"); } const registrationStage = new stageClass(this._hsApi, this._data, session, params?.[stage]); - if (!this._firstStage) { - this._firstStage = registrationStage; + if (!firstStage) { + firstStage = registrationStage; lastStage = registrationStage; } else { lastStage!.setNextStage(registrationStage); lastStage = registrationStage; } } + return firstStage!; } private get _username() { return this._data.username; } From 5de1fc145374eeadcad05a660d17010bccceb67b Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 1 Feb 2022 18:26:20 +0530 Subject: [PATCH 21/54] Remove unnecessary getters --- src/matrix/registration/Registration.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index c6e26604..59a6bd95 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -41,11 +41,11 @@ export class Registration { async start(): Promise { const response = await this._hsApi.register( - this._username, - this._password, - this._initialDeviceDisplayName, + this._data.username, + this._data.password, + this._data.initialDeviceDisplayName, undefined, - this._inhibitLogin).response(); + this._data.inhibitLogin).response(); return this.parseStagesFromResponse(response); } @@ -70,9 +70,4 @@ export class Registration { } return firstStage!; } - - private get _username() { return this._data.username; } - private get _password() { return this._data.password; } - private get _initialDeviceDisplayName() { return this._data.initialDeviceDisplayName; } - private get _inhibitLogin() { return this._data.inhibitLogin; } } From 6eba60bd75fb22dd712d4d937b5f42bbb1323e04 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 1 Feb 2022 19:26:51 +0530 Subject: [PATCH 22/54] Use typescript style that was agreed on earlier --- src/matrix/registration/stages/BaseRegistrationStage.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/matrix/registration/stages/BaseRegistrationStage.ts b/src/matrix/registration/stages/BaseRegistrationStage.ts index 4c15bb5e..bea95598 100644 --- a/src/matrix/registration/stages/BaseRegistrationStage.ts +++ b/src/matrix/registration/stages/BaseRegistrationStage.ts @@ -18,6 +18,10 @@ export type Auth = { [key: string]: any; } +type Params = { + [key: string]: any; +} + import type {HomeServerApi} from "../../net/HomeServerApi"; import type {RegistrationParameters, RegistrationResponse} from "../Registration"; @@ -28,7 +32,7 @@ export abstract class BaseRegistrationStage { protected _nextStage: BaseRegistrationStage; protected _params?: Record - constructor(hsApi: HomeServerApi, registrationData: RegistrationParameters, session: string, params?: Record) { + constructor(hsApi: HomeServerApi, registrationData: RegistrationParameters, session: string, params?: Params) { this._hsApi = hsApi; this._registrationData = registrationData; this._session = session; From 7bb7189c6ae65003490601eae55c4eea6685f802 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Tue, 1 Feb 2022 19:29:11 +0530 Subject: [PATCH 23/54] No need for this export --- src/matrix/registration/stages/BaseRegistrationStage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/matrix/registration/stages/BaseRegistrationStage.ts b/src/matrix/registration/stages/BaseRegistrationStage.ts index bea95598..6ffd9187 100644 --- a/src/matrix/registration/stages/BaseRegistrationStage.ts +++ b/src/matrix/registration/stages/BaseRegistrationStage.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -export type Auth = { +type Auth = { [key: string]: any; } From ac7108b882d8a3ac19093f83a6c498e742d5bda2 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 2 Feb 2022 12:25:12 +0530 Subject: [PATCH 24/54] Throw error instead of returning it --- src/matrix/registration/stages/BaseRegistrationStage.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/matrix/registration/stages/BaseRegistrationStage.ts b/src/matrix/registration/stages/BaseRegistrationStage.ts index 6ffd9187..df23c429 100644 --- a/src/matrix/registration/stages/BaseRegistrationStage.ts +++ b/src/matrix/registration/stages/BaseRegistrationStage.ts @@ -48,9 +48,8 @@ export abstract class BaseRegistrationStage { * Finish a registration stage, return value is: * - the next stage if this stage was completed successfully * - user-id (string) if registration is completed - * - an error if something went wrong */ - abstract complete(auth?: Auth): Promise; + abstract complete(auth?: Auth): Promise; setNextStage(stage: BaseRegistrationStage) { this._nextStage = stage; @@ -65,6 +64,6 @@ export abstract class BaseRegistrationStage { return this._nextStage; } const error = response.error ?? "Could not parse response"; - return new Error(error); - } + throw new Error(error); + } } From b482d478b46fab8ec1c8ef91f0e70b141d9eadcd Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 2 Feb 2022 12:25:34 +0530 Subject: [PATCH 25/54] Add a tos getter --- src/matrix/registration/stages/TermsAuth.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/matrix/registration/stages/TermsAuth.ts b/src/matrix/registration/stages/TermsAuth.ts index 0114d27d..7d1647b9 100644 --- a/src/matrix/registration/stages/TermsAuth.ts +++ b/src/matrix/registration/stages/TermsAuth.ts @@ -31,9 +31,11 @@ export class TermsAuth extends BaseRegistrationStage { return "m.login.terms"; } - // todo: add better parsing logic here, also remember that server admins can - // require any sort documents here, even those that are not toc/privacy policies get privacyPolicy() { return this._params?.policies["privacy_policy"]; } + + get termsOfService() { + return this._params?.policies["terms_of_service"]; + } } From 49ade61ef6e2b8fa686dbc4510098975f1df984a Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 2 Feb 2022 12:45:49 +0530 Subject: [PATCH 26/54] Fill in ts types + change names --- src/matrix/registration/Registration.ts | 6 +++--- .../registration/registrationStageFromType.ts | 4 ++-- .../registration/stages/BaseRegistrationStage.ts | 15 +++++++++------ 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index 59a6bd95..dd19fae4 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -18,7 +18,7 @@ import type {HomeServerApi} from "../net/HomeServerApi"; import {registrationStageFromType} from "./registrationStageFromType"; import type {BaseRegistrationStage} from "./stages/BaseRegistrationStage"; -export type RegistrationParameters = { +export type RegistrationDetails = { username: string | null; password: string; initialDeviceDisplayName: string; @@ -32,9 +32,9 @@ export type RegistrationResponse = { export class Registration { private _hsApi: HomeServerApi; - private _data: RegistrationParameters; + private _data: RegistrationDetails; - constructor(hsApi: HomeServerApi, data: RegistrationParameters) { + constructor(hsApi: HomeServerApi, data: RegistrationDetails) { this._hsApi = hsApi; this._data = data; } diff --git a/src/matrix/registration/registrationStageFromType.ts b/src/matrix/registration/registrationStageFromType.ts index 44913f94..31330bc9 100644 --- a/src/matrix/registration/registrationStageFromType.ts +++ b/src/matrix/registration/registrationStageFromType.ts @@ -16,11 +16,11 @@ limitations under the License. import type {BaseRegistrationStage} from "./stages/BaseRegistrationStage"; import type {HomeServerApi} from "../net/HomeServerApi"; -import type {RegistrationParameters} from "./Registration"; +import type {RegistrationDetails} from "./Registration"; import {DummyAuth} from "./stages/DummyAuth"; import {TermsAuth} from "./stages/TermsAuth"; -type DerivedFromBaseRegistration = { new(hsApi: HomeServerApi, registrationData: RegistrationParameters, session: string, params?: Record): BaseRegistrationStage } & typeof BaseRegistrationStage | undefined; +type DerivedFromBaseRegistration = { new(hsApi: HomeServerApi, registrationData: RegistrationDetails, session: string, params?: Record): BaseRegistrationStage } & typeof BaseRegistrationStage | undefined; export function registrationStageFromType(type: string): DerivedFromBaseRegistration { switch (type) { diff --git a/src/matrix/registration/stages/BaseRegistrationStage.ts b/src/matrix/registration/stages/BaseRegistrationStage.ts index df23c429..57c0fa0e 100644 --- a/src/matrix/registration/stages/BaseRegistrationStage.ts +++ b/src/matrix/registration/stages/BaseRegistrationStage.ts @@ -14,25 +14,28 @@ See the License for the specific language governing permissions and limitations under the License. */ -type Auth = { +type AuthenticationData = { + type: string; + session: string; [key: string]: any; } -type Params = { +// contains data needed to complete this stage, eg: link to privacy policy +type RegistrationParams = { [key: string]: any; } import type {HomeServerApi} from "../../net/HomeServerApi"; -import type {RegistrationParameters, RegistrationResponse} from "../Registration"; +import type {RegistrationDetails, RegistrationResponse} from "../Registration"; export abstract class BaseRegistrationStage { protected _hsApi: HomeServerApi; - protected _registrationData: RegistrationParameters; + protected _registrationData: RegistrationDetails; protected _session: string; protected _nextStage: BaseRegistrationStage; protected _params?: Record - constructor(hsApi: HomeServerApi, registrationData: RegistrationParameters, session: string, params?: Params) { + constructor(hsApi: HomeServerApi, registrationData: RegistrationDetails, session: string, params?: RegistrationParams) { this._hsApi = hsApi; this._registrationData = registrationData; this._session = session; @@ -49,7 +52,7 @@ export abstract class BaseRegistrationStage { * - the next stage if this stage was completed successfully * - user-id (string) if registration is completed */ - abstract complete(auth?: Auth): Promise; + abstract complete(auth?: AuthenticationData): Promise; setNextStage(stage: BaseRegistrationStage) { this._nextStage = stage; From 1d4b079d0c815c712f4fe30e790bab16d6dadd7c Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 2 Feb 2022 13:58:03 +0530 Subject: [PATCH 27/54] Type RegistrationResponse --- src/matrix/registration/Registration.ts | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index dd19fae4..cd44dc38 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -23,11 +23,23 @@ export type RegistrationDetails = { password: string; initialDeviceDisplayName: string; inhibitLogin: boolean; -} +} -// todo: type this later export type RegistrationResponse = { - [key: string]: any; + completed: string[]; + flows: Record[]; + params: Record; + session: string; +} & error & success; + +type error = { + errcode: string; + error: string; +} +type success = { + user_id: string; + device_id: string; + access_token?: string; } export class Registration { @@ -52,6 +64,9 @@ export class Registration { parseStagesFromResponse(response: RegistrationResponse): BaseRegistrationStage { const { session, params } = response; const flow = response.flows.pop(); + if (!flow) { + throw new Error("No registration flows available!"); + } let firstStage: BaseRegistrationStage | undefined; let lastStage: BaseRegistrationStage; for (const stage of flow.stages) { From 3a67da88305afe1636a5c48cd882bf78bb89b2c3 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 2 Feb 2022 14:54:10 +0530 Subject: [PATCH 28/54] Refactor type - Change name - Move union type down --- src/matrix/registration/registrationStageFromType.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/matrix/registration/registrationStageFromType.ts b/src/matrix/registration/registrationStageFromType.ts index 31330bc9..45375516 100644 --- a/src/matrix/registration/registrationStageFromType.ts +++ b/src/matrix/registration/registrationStageFromType.ts @@ -20,9 +20,9 @@ import type {RegistrationDetails} from "./Registration"; import {DummyAuth} from "./stages/DummyAuth"; import {TermsAuth} from "./stages/TermsAuth"; -type DerivedFromBaseRegistration = { new(hsApi: HomeServerApi, registrationData: RegistrationDetails, session: string, params?: Record): BaseRegistrationStage } & typeof BaseRegistrationStage | undefined; +type ClassDerivedFromBaseRegistration = { new(hsApi: HomeServerApi, registrationData: RegistrationDetails, session: string, params?: Record): BaseRegistrationStage } & typeof BaseRegistrationStage; -export function registrationStageFromType(type: string): DerivedFromBaseRegistration { +export function registrationStageFromType(type: string): ClassDerivedFromBaseRegistration | undefined{ switch (type) { case "m.login.dummy": return DummyAuth; From 6798a5e429d97e2dcdf7132c2bb748d0852eb69c Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 2 Feb 2022 15:05:03 +0530 Subject: [PATCH 29/54] Move types to types.ts --- src/matrix/registration/Registration.ts | 25 +-------- .../registration/registrationStageFromType.ts | 2 +- .../stages/BaseRegistrationStage.ts | 13 +---- src/matrix/registration/types/type.ts | 55 +++++++++++++++++++ 4 files changed, 58 insertions(+), 37 deletions(-) create mode 100644 src/matrix/registration/types/type.ts diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index cd44dc38..7fb263f3 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -17,30 +17,7 @@ limitations under the License. import type {HomeServerApi} from "../net/HomeServerApi"; import {registrationStageFromType} from "./registrationStageFromType"; import type {BaseRegistrationStage} from "./stages/BaseRegistrationStage"; - -export type RegistrationDetails = { - username: string | null; - password: string; - initialDeviceDisplayName: string; - inhibitLogin: boolean; -} - -export type RegistrationResponse = { - completed: string[]; - flows: Record[]; - params: Record; - session: string; -} & error & success; - -type error = { - errcode: string; - error: string; -} -type success = { - user_id: string; - device_id: string; - access_token?: string; -} +import type {RegistrationDetails, RegistrationResponse} from "./types/type"; export class Registration { private _hsApi: HomeServerApi; diff --git a/src/matrix/registration/registrationStageFromType.ts b/src/matrix/registration/registrationStageFromType.ts index 45375516..28d5c2b0 100644 --- a/src/matrix/registration/registrationStageFromType.ts +++ b/src/matrix/registration/registrationStageFromType.ts @@ -16,7 +16,7 @@ limitations under the License. import type {BaseRegistrationStage} from "./stages/BaseRegistrationStage"; import type {HomeServerApi} from "../net/HomeServerApi"; -import type {RegistrationDetails} from "./Registration"; +import type {RegistrationDetails} from "./types/type"; import {DummyAuth} from "./stages/DummyAuth"; import {TermsAuth} from "./stages/TermsAuth"; diff --git a/src/matrix/registration/stages/BaseRegistrationStage.ts b/src/matrix/registration/stages/BaseRegistrationStage.ts index 57c0fa0e..2dfc0628 100644 --- a/src/matrix/registration/stages/BaseRegistrationStage.ts +++ b/src/matrix/registration/stages/BaseRegistrationStage.ts @@ -14,19 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -type AuthenticationData = { - type: string; - session: string; - [key: string]: any; -} - -// contains data needed to complete this stage, eg: link to privacy policy -type RegistrationParams = { - [key: string]: any; -} - import type {HomeServerApi} from "../../net/HomeServerApi"; -import type {RegistrationDetails, RegistrationResponse} from "../Registration"; +import type {RegistrationDetails, RegistrationResponse, AuthenticationData, RegistrationParams} from "../types/type"; export abstract class BaseRegistrationStage { protected _hsApi: HomeServerApi; diff --git a/src/matrix/registration/types/type.ts b/src/matrix/registration/types/type.ts new file mode 100644 index 00000000..2863ec28 --- /dev/null +++ b/src/matrix/registration/types/type.ts @@ -0,0 +1,55 @@ +/* +Copyright 2021 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. +*/ + +export type RegistrationDetails = { + username: string | null; + password: string; + initialDeviceDisplayName: string; + inhibitLogin: boolean; +} + +export type RegistrationResponse = RegistrationResponse401 & RegistrationResponseError & RegistrationResponseSuccess; + +type RegistrationResponse401 = { + completed: string[]; + flows: Record[]; + params: Record; + session: string; +} + +type RegistrationResponseError = { + errcode: string; + error: string; +} + +type RegistrationResponseSuccess = { + user_id: string; + device_id: string; + access_token?: string; +} + +/* Types for Registration Stage */ + +export type AuthenticationData = { + type: string; + session: string; + [key: string]: any; +} + +// contains additional data needed to complete a stage, eg: link to privacy policy +export type RegistrationParams = { + [key: string]: any; +} From a249a1b2b517b3959f948b200ef4e84b8844464d Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 2 Feb 2022 15:51:02 +0530 Subject: [PATCH 30/54] Implement flow seclector --- src/matrix/registration/Registration.ts | 14 +++++++++----- .../registration/registrationStageFromType.ts | 2 +- .../registration/stages/BaseRegistrationStage.ts | 2 +- .../registration/types/{type.ts => types.ts} | 6 +++++- 4 files changed, 16 insertions(+), 8 deletions(-) rename src/matrix/registration/types/{type.ts => types.ts} (94%) diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index 7fb263f3..15006ce2 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -17,15 +17,19 @@ limitations under the License. import type {HomeServerApi} from "../net/HomeServerApi"; import {registrationStageFromType} from "./registrationStageFromType"; import type {BaseRegistrationStage} from "./stages/BaseRegistrationStage"; -import type {RegistrationDetails, RegistrationResponse} from "./types/type"; +import type {RegistrationDetails, RegistrationResponse, RegistrationFlow} from "./types/types"; + +type FlowSelector = (flows: RegistrationFlow[]) => RegistrationFlow | void; export class Registration { private _hsApi: HomeServerApi; private _data: RegistrationDetails; + private _flowSelector: FlowSelector; - constructor(hsApi: HomeServerApi, data: RegistrationDetails) { + constructor(hsApi: HomeServerApi, data: RegistrationDetails, flowSelector?: FlowSelector) { this._hsApi = hsApi; this._data = data; + this._flowSelector = flowSelector ?? (flows => flows.pop()); } async start(): Promise { @@ -40,16 +44,16 @@ export class Registration { parseStagesFromResponse(response: RegistrationResponse): BaseRegistrationStage { const { session, params } = response; - const flow = response.flows.pop(); + const flow = this._flowSelector(response.flows); if (!flow) { - throw new Error("No registration flows available!"); + throw new Error("flowSelector did not return any flow!"); } let firstStage: BaseRegistrationStage | undefined; let lastStage: BaseRegistrationStage; for (const stage of flow.stages) { const stageClass = registrationStageFromType(stage); if (!stageClass) { - throw new Error("Unknown stage"); + throw new Error(`Unknown stage: ${stage}`); } const registrationStage = new stageClass(this._hsApi, this._data, session, params?.[stage]); if (!firstStage) { diff --git a/src/matrix/registration/registrationStageFromType.ts b/src/matrix/registration/registrationStageFromType.ts index 28d5c2b0..9552d049 100644 --- a/src/matrix/registration/registrationStageFromType.ts +++ b/src/matrix/registration/registrationStageFromType.ts @@ -16,7 +16,7 @@ limitations under the License. import type {BaseRegistrationStage} from "./stages/BaseRegistrationStage"; import type {HomeServerApi} from "../net/HomeServerApi"; -import type {RegistrationDetails} from "./types/type"; +import type {RegistrationDetails} from "./types/types"; import {DummyAuth} from "./stages/DummyAuth"; import {TermsAuth} from "./stages/TermsAuth"; diff --git a/src/matrix/registration/stages/BaseRegistrationStage.ts b/src/matrix/registration/stages/BaseRegistrationStage.ts index 2dfc0628..62325b4c 100644 --- a/src/matrix/registration/stages/BaseRegistrationStage.ts +++ b/src/matrix/registration/stages/BaseRegistrationStage.ts @@ -15,7 +15,7 @@ limitations under the License. */ import type {HomeServerApi} from "../../net/HomeServerApi"; -import type {RegistrationDetails, RegistrationResponse, AuthenticationData, RegistrationParams} from "../types/type"; +import type {RegistrationDetails, RegistrationResponse, AuthenticationData, RegistrationParams} from "../types/types"; export abstract class BaseRegistrationStage { protected _hsApi: HomeServerApi; diff --git a/src/matrix/registration/types/type.ts b/src/matrix/registration/types/types.ts similarity index 94% rename from src/matrix/registration/types/type.ts rename to src/matrix/registration/types/types.ts index 2863ec28..97dca1be 100644 --- a/src/matrix/registration/types/type.ts +++ b/src/matrix/registration/types/types.ts @@ -25,7 +25,7 @@ export type RegistrationResponse = RegistrationResponse401 & RegistrationRespons type RegistrationResponse401 = { completed: string[]; - flows: Record[]; + flows: RegistrationFlow[]; params: Record; session: string; } @@ -41,6 +41,10 @@ type RegistrationResponseSuccess = { access_token?: string; } +export type RegistrationFlow = { + stages: string[]; +} + /* Types for Registration Stage */ export type AuthenticationData = { From fe0add01ee7c24c0b91781db062109424a5366c3 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 2 Feb 2022 16:09:01 +0530 Subject: [PATCH 31/54] Use union of types for RegistrationResponse --- src/matrix/registration/Registration.ts | 4 ++-- src/matrix/registration/stages/BaseRegistrationStage.ts | 6 +++--- src/matrix/registration/types/types.ts | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index 15006ce2..8b4d54f9 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -17,7 +17,7 @@ limitations under the License. import type {HomeServerApi} from "../net/HomeServerApi"; import {registrationStageFromType} from "./registrationStageFromType"; import type {BaseRegistrationStage} from "./stages/BaseRegistrationStage"; -import type {RegistrationDetails, RegistrationResponse, RegistrationFlow} from "./types/types"; +import type {RegistrationDetails, RegistrationFlow, RegistrationResponse401} from "./types/types"; type FlowSelector = (flows: RegistrationFlow[]) => RegistrationFlow | void; @@ -42,7 +42,7 @@ export class Registration { return this.parseStagesFromResponse(response); } - parseStagesFromResponse(response: RegistrationResponse): BaseRegistrationStage { + parseStagesFromResponse(response: RegistrationResponse401): BaseRegistrationStage { const { session, params } = response; const flow = this._flowSelector(response.flows); if (!flow) { diff --git a/src/matrix/registration/stages/BaseRegistrationStage.ts b/src/matrix/registration/stages/BaseRegistrationStage.ts index 62325b4c..7b41379c 100644 --- a/src/matrix/registration/stages/BaseRegistrationStage.ts +++ b/src/matrix/registration/stages/BaseRegistrationStage.ts @@ -48,14 +48,14 @@ export abstract class BaseRegistrationStage { } parseResponse(response: RegistrationResponse) { - if (response.user_id) { + if ("user_id" in response) { // registration completed successfully return response.user_id; } - else if (response.completed?.find(c => c === this.type)) { + else if ("completed" in response && response.completed?.find(c => c === this.type)) { return this._nextStage; } - const error = response.error ?? "Could not parse response"; + const error = "error" in response? response.error: "Could not parse response"; throw new Error(error); } } diff --git a/src/matrix/registration/types/types.ts b/src/matrix/registration/types/types.ts index 97dca1be..5661e268 100644 --- a/src/matrix/registration/types/types.ts +++ b/src/matrix/registration/types/types.ts @@ -21,9 +21,9 @@ export type RegistrationDetails = { inhibitLogin: boolean; } -export type RegistrationResponse = RegistrationResponse401 & RegistrationResponseError & RegistrationResponseSuccess; +export type RegistrationResponse = RegistrationResponse401 | RegistrationResponseError | RegistrationResponseSuccess; -type RegistrationResponse401 = { +export type RegistrationResponse401 = { completed: string[]; flows: RegistrationFlow[]; params: Record; From a351a185a0ac49dcca97731ca17e547e8c4f671a Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Wed, 2 Feb 2022 16:41:38 +0530 Subject: [PATCH 32/54] Give proper names --- src/matrix/registration/Registration.ts | 20 +++++++++---------- .../registration/registrationStageFromType.ts | 4 ++-- .../stages/BaseRegistrationStage.ts | 10 +++++----- src/matrix/registration/stages/DummyAuth.ts | 3 +-- src/matrix/registration/stages/TermsAuth.ts | 3 +-- src/matrix/registration/types/types.ts | 7 +++---- 6 files changed, 22 insertions(+), 25 deletions(-) diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index 8b4d54f9..1d44c50d 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -17,32 +17,32 @@ limitations under the License. import type {HomeServerApi} from "../net/HomeServerApi"; import {registrationStageFromType} from "./registrationStageFromType"; import type {BaseRegistrationStage} from "./stages/BaseRegistrationStage"; -import type {RegistrationDetails, RegistrationFlow, RegistrationResponse401} from "./types/types"; +import type {AccountDetails, RegistrationFlow, RegistrationResponseMoreDataNeeded} from "./types/types"; type FlowSelector = (flows: RegistrationFlow[]) => RegistrationFlow | void; export class Registration { private _hsApi: HomeServerApi; - private _data: RegistrationDetails; + private _accountDetails: AccountDetails; private _flowSelector: FlowSelector; - constructor(hsApi: HomeServerApi, data: RegistrationDetails, flowSelector?: FlowSelector) { + constructor(hsApi: HomeServerApi, accountDetails: AccountDetails, flowSelector?: FlowSelector) { this._hsApi = hsApi; - this._data = data; + this._accountDetails = accountDetails; this._flowSelector = flowSelector ?? (flows => flows.pop()); } async start(): Promise { const response = await this._hsApi.register( - this._data.username, - this._data.password, - this._data.initialDeviceDisplayName, + this._accountDetails.username, + this._accountDetails.password, + this._accountDetails.initialDeviceDisplayName, undefined, - this._data.inhibitLogin).response(); + this._accountDetails.inhibitLogin).response(); return this.parseStagesFromResponse(response); } - parseStagesFromResponse(response: RegistrationResponse401): BaseRegistrationStage { + parseStagesFromResponse(response: RegistrationResponseMoreDataNeeded): BaseRegistrationStage { const { session, params } = response; const flow = this._flowSelector(response.flows); if (!flow) { @@ -55,7 +55,7 @@ export class Registration { if (!stageClass) { throw new Error(`Unknown stage: ${stage}`); } - const registrationStage = new stageClass(this._hsApi, this._data, session, params?.[stage]); + const registrationStage = new stageClass(this._hsApi, this._accountDetails, session, params?.[stage]); if (!firstStage) { firstStage = registrationStage; lastStage = registrationStage; diff --git a/src/matrix/registration/registrationStageFromType.ts b/src/matrix/registration/registrationStageFromType.ts index 9552d049..799451a7 100644 --- a/src/matrix/registration/registrationStageFromType.ts +++ b/src/matrix/registration/registrationStageFromType.ts @@ -16,11 +16,11 @@ limitations under the License. import type {BaseRegistrationStage} from "./stages/BaseRegistrationStage"; import type {HomeServerApi} from "../net/HomeServerApi"; -import type {RegistrationDetails} from "./types/types"; +import type {AccountDetails, RegistrationParams} from "./types/types"; import {DummyAuth} from "./stages/DummyAuth"; import {TermsAuth} from "./stages/TermsAuth"; -type ClassDerivedFromBaseRegistration = { new(hsApi: HomeServerApi, registrationData: RegistrationDetails, session: string, params?: Record): BaseRegistrationStage } & typeof BaseRegistrationStage; +type ClassDerivedFromBaseRegistration = { new(hsApi: HomeServerApi, registrationData: AccountDetails, session: string, params?: RegistrationParams): BaseRegistrationStage } & typeof BaseRegistrationStage; export function registrationStageFromType(type: string): ClassDerivedFromBaseRegistration | undefined{ switch (type) { diff --git a/src/matrix/registration/stages/BaseRegistrationStage.ts b/src/matrix/registration/stages/BaseRegistrationStage.ts index 7b41379c..88f0bad6 100644 --- a/src/matrix/registration/stages/BaseRegistrationStage.ts +++ b/src/matrix/registration/stages/BaseRegistrationStage.ts @@ -15,18 +15,18 @@ limitations under the License. */ import type {HomeServerApi} from "../../net/HomeServerApi"; -import type {RegistrationDetails, RegistrationResponse, AuthenticationData, RegistrationParams} from "../types/types"; +import type {AccountDetails, RegistrationResponse, AuthenticationData, RegistrationParams} from "../types/types"; export abstract class BaseRegistrationStage { protected _hsApi: HomeServerApi; - protected _registrationData: RegistrationDetails; + protected _accountDetails: AccountDetails; protected _session: string; protected _nextStage: BaseRegistrationStage; protected _params?: Record - constructor(hsApi: HomeServerApi, registrationData: RegistrationDetails, session: string, params?: RegistrationParams) { + constructor(hsApi: HomeServerApi, accountDetails: AccountDetails, session: string, params?: RegistrationParams) { this._hsApi = hsApi; - this._registrationData = registrationData; + this._accountDetails = accountDetails; this._session = session; this._params = params; } @@ -52,7 +52,7 @@ export abstract class BaseRegistrationStage { // registration completed successfully return response.user_id; } - else if ("completed" in response && response.completed?.find(c => c === this.type)) { + else if ("completed" in response && response.completed.find(c => c === this.type)) { return this._nextStage; } const error = "error" in response? response.error: "Could not parse response"; diff --git a/src/matrix/registration/stages/DummyAuth.ts b/src/matrix/registration/stages/DummyAuth.ts index 4a5d9bd8..e22409db 100644 --- a/src/matrix/registration/stages/DummyAuth.ts +++ b/src/matrix/registration/stages/DummyAuth.ts @@ -17,9 +17,8 @@ limitations under the License. import {BaseRegistrationStage} from "./BaseRegistrationStage"; export class DummyAuth extends BaseRegistrationStage { - async complete() { - const { username, password, initialDeviceDisplayName, inhibitLogin } = this._registrationData; + const { username, password, initialDeviceDisplayName, inhibitLogin } = this._accountDetails; const response = await this._hsApi.register(username, password, initialDeviceDisplayName, { session: this._session, type: this.type diff --git a/src/matrix/registration/stages/TermsAuth.ts b/src/matrix/registration/stages/TermsAuth.ts index 7d1647b9..e770b13b 100644 --- a/src/matrix/registration/stages/TermsAuth.ts +++ b/src/matrix/registration/stages/TermsAuth.ts @@ -17,9 +17,8 @@ limitations under the License. import {BaseRegistrationStage} from "./BaseRegistrationStage"; export class TermsAuth extends BaseRegistrationStage { - async complete() { - const { username, password, initialDeviceDisplayName, inhibitLogin } = this._registrationData; + const { username, password, initialDeviceDisplayName, inhibitLogin } = this._accountDetails; const response = await this._hsApi.register(username, password, initialDeviceDisplayName, { session: this._session, type: this.type diff --git a/src/matrix/registration/types/types.ts b/src/matrix/registration/types/types.ts index 5661e268..08fc0fc4 100644 --- a/src/matrix/registration/types/types.ts +++ b/src/matrix/registration/types/types.ts @@ -14,16 +14,16 @@ See the License for the specific language governing permissions and limitations under the License. */ -export type RegistrationDetails = { +export type AccountDetails = { username: string | null; password: string; initialDeviceDisplayName: string; inhibitLogin: boolean; } -export type RegistrationResponse = RegistrationResponse401 | RegistrationResponseError | RegistrationResponseSuccess; +export type RegistrationResponse = RegistrationResponseMoreDataNeeded | RegistrationResponseError | RegistrationResponseSuccess; -export type RegistrationResponse401 = { +export type RegistrationResponseMoreDataNeeded = { completed: string[]; flows: RegistrationFlow[]; params: Record; @@ -46,7 +46,6 @@ export type RegistrationFlow = { } /* Types for Registration Stage */ - export type AuthenticationData = { type: string; session: string; From 30cb9f6d15afc5e4ba48a6d697ffbb4e77e56e8d Mon Sep 17 00:00:00 2001 From: R Midhun Suresh Date: Thu, 3 Feb 2022 12:01:08 +0530 Subject: [PATCH 33/54] Use includes instead of elaborate find Co-authored-by: Bruno Windels --- src/matrix/net/HomeServerRequest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/matrix/net/HomeServerRequest.ts b/src/matrix/net/HomeServerRequest.ts index cbbb4e90..c3f49834 100644 --- a/src/matrix/net/HomeServerRequest.ts +++ b/src/matrix/net/HomeServerRequest.ts @@ -42,7 +42,7 @@ export class HomeServerRequest implements IHomeServerRequest { this._promise = sourceRequest.response().then(response => { log?.set("status", response.status); // ok? - if (response.status >= 200 && response.status < 300 || options?.allowedErrors?.find(e => e === response.status)) { + if (response.status >= 200 && response.status < 300 || options?.allowedErrors?.includes(response.status)) { log?.finish(); return response.body; } else { From e13040a49e11cc185c62a808853e93162683b199 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 3 Feb 2022 12:04:13 +0530 Subject: [PATCH 34/54] Don't mutate flows --- src/matrix/registration/Registration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index 1d44c50d..227d78bc 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -29,7 +29,7 @@ export class Registration { constructor(hsApi: HomeServerApi, accountDetails: AccountDetails, flowSelector?: FlowSelector) { this._hsApi = hsApi; this._accountDetails = accountDetails; - this._flowSelector = flowSelector ?? (flows => flows.pop()); + this._flowSelector = flowSelector ?? (flows => flows[0]); } async start(): Promise { From 7bacbec5e9dcd44d3948d2959896ae585d51b2cf Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 3 Feb 2022 12:06:13 +0530 Subject: [PATCH 35/54] Remove type directory --- src/matrix/registration/Registration.ts | 2 +- src/matrix/registration/registrationStageFromType.ts | 2 +- src/matrix/registration/stages/BaseRegistrationStage.ts | 2 +- src/matrix/registration/{types => }/types.ts | 0 4 files changed, 3 insertions(+), 3 deletions(-) rename src/matrix/registration/{types => }/types.ts (100%) diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index 227d78bc..9c7ef11b 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -17,7 +17,7 @@ limitations under the License. import type {HomeServerApi} from "../net/HomeServerApi"; import {registrationStageFromType} from "./registrationStageFromType"; import type {BaseRegistrationStage} from "./stages/BaseRegistrationStage"; -import type {AccountDetails, RegistrationFlow, RegistrationResponseMoreDataNeeded} from "./types/types"; +import type {AccountDetails, RegistrationFlow, RegistrationResponseMoreDataNeeded} from "./types"; type FlowSelector = (flows: RegistrationFlow[]) => RegistrationFlow | void; diff --git a/src/matrix/registration/registrationStageFromType.ts b/src/matrix/registration/registrationStageFromType.ts index 799451a7..6b120a6f 100644 --- a/src/matrix/registration/registrationStageFromType.ts +++ b/src/matrix/registration/registrationStageFromType.ts @@ -16,7 +16,7 @@ limitations under the License. import type {BaseRegistrationStage} from "./stages/BaseRegistrationStage"; import type {HomeServerApi} from "../net/HomeServerApi"; -import type {AccountDetails, RegistrationParams} from "./types/types"; +import type {AccountDetails, RegistrationParams} from "./types"; import {DummyAuth} from "./stages/DummyAuth"; import {TermsAuth} from "./stages/TermsAuth"; diff --git a/src/matrix/registration/stages/BaseRegistrationStage.ts b/src/matrix/registration/stages/BaseRegistrationStage.ts index 88f0bad6..74fe66c7 100644 --- a/src/matrix/registration/stages/BaseRegistrationStage.ts +++ b/src/matrix/registration/stages/BaseRegistrationStage.ts @@ -15,7 +15,7 @@ limitations under the License. */ import type {HomeServerApi} from "../../net/HomeServerApi"; -import type {AccountDetails, RegistrationResponse, AuthenticationData, RegistrationParams} from "../types/types"; +import type {AccountDetails, RegistrationResponse, AuthenticationData, RegistrationParams} from "../types"; export abstract class BaseRegistrationStage { protected _hsApi: HomeServerApi; diff --git a/src/matrix/registration/types/types.ts b/src/matrix/registration/types.ts similarity index 100% rename from src/matrix/registration/types/types.ts rename to src/matrix/registration/types.ts From 2aad5546bf73a50df0abd303146b9b3e25aed975 Mon Sep 17 00:00:00 2001 From: R Midhun Suresh Date: Thu, 3 Feb 2022 12:07:09 +0530 Subject: [PATCH 36/54] No need for Object.assign here either Co-authored-by: Bruno Windels --- src/matrix/net/HomeServerApi.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/matrix/net/HomeServerApi.ts b/src/matrix/net/HomeServerApi.ts index 7f7dd16c..b9651cee 100644 --- a/src/matrix/net/HomeServerApi.ts +++ b/src/matrix/net/HomeServerApi.ts @@ -157,7 +157,7 @@ export class HomeServerApi { } register(username: string | null, password: string, initialDeviceDisplayName: string, auth?: Record, inhibitLogin: boolean = true , options: IRequestOptions = {}): IHomeServerRequest { - Object.assign(options, { allowedErrors: [401] }); + options.allowedErrors = [401]; const body: any = { auth, password, From e64f4ad7b2021bd9f340ff8f123daca9d7ab9fa9 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 3 Feb 2022 15:10:56 +0530 Subject: [PATCH 37/54] Refactor code - Move all code that does /register to Registration.ts - RegistrationStage only deals with the generation of auth data - Change API so that undefined is returned instead of string when registration is over --- src/matrix/Client.js | 3 +- src/matrix/registration/Registration.ts | 38 ++++++++++++++++++- .../stages/BaseRegistrationStage.ts | 21 +++------- src/matrix/registration/stages/DummyAuth.ts | 11 +++--- src/matrix/registration/stages/TermsAuth.ts | 12 +++--- src/matrix/registration/types.ts | 2 +- 6 files changed, 56 insertions(+), 31 deletions(-) diff --git a/src/matrix/Client.js b/src/matrix/Client.js index 22e686d0..b24c1ec9 100644 --- a/src/matrix/Client.js +++ b/src/matrix/Client.js @@ -140,8 +140,7 @@ export class Client { password, initialDeviceDisplayName, }); - let stage = await registration.start(); - return stage; + return registration; } async startWithLogin(loginMethod, {inspectAccountSetup} = {}) { diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index 9c7ef11b..0d408c2a 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -17,7 +17,13 @@ limitations under the License. import type {HomeServerApi} from "../net/HomeServerApi"; import {registrationStageFromType} from "./registrationStageFromType"; import type {BaseRegistrationStage} from "./stages/BaseRegistrationStage"; -import type {AccountDetails, RegistrationFlow, RegistrationResponseMoreDataNeeded} from "./types"; +import type { + AccountDetails, + RegistrationFlow, + RegistrationResponseMoreDataNeeded, + RegistrationResponse, + RegistrationResponseSuccess, +} from "./types"; type FlowSelector = (flows: RegistrationFlow[]) => RegistrationFlow | void; @@ -25,6 +31,7 @@ export class Registration { private _hsApi: HomeServerApi; private _accountDetails: AccountDetails; private _flowSelector: FlowSelector; + private _sessionInfo?: RegistrationResponseSuccess constructor(hsApi: HomeServerApi, accountDetails: AccountDetails, flowSelector?: FlowSelector) { this._hsApi = hsApi; @@ -42,6 +49,18 @@ export class Registration { return this.parseStagesFromResponse(response); } + /** + * Finish a registration stage, return value is: + * - the next stage if this stage was completed successfully + * - undefined if registration is completed + */ + async submitStage(stage: BaseRegistrationStage): Promise { + const auth = stage.generateAuthenticationData(); + const { username, password, initialDeviceDisplayName, inhibitLogin } = this._accountDetails; + const response = await this._hsApi.register(username, password, initialDeviceDisplayName, auth, inhibitLogin).response(); + return this.parseRegistrationResponse(response, stage); + } + parseStagesFromResponse(response: RegistrationResponseMoreDataNeeded): BaseRegistrationStage { const { session, params } = response; const flow = this._flowSelector(response.flows); @@ -66,4 +85,21 @@ export class Registration { } return firstStage!; } + + parseRegistrationResponse(response: RegistrationResponse, currentStage: BaseRegistrationStage) { + if ("user_id" in response) { + // registration completed successfully + this._sessionInfo = response; + return undefined; + } + else if ("completed" in response && response.completed.find(c => c === currentStage.type)) { + return currentStage.nextStage; + } + const error = "error" in response? response.error: "Could not parse response"; + throw new Error(error); + } + + get sessionInfo(): RegistrationResponseSuccess | undefined { + return this._sessionInfo; + } } diff --git a/src/matrix/registration/stages/BaseRegistrationStage.ts b/src/matrix/registration/stages/BaseRegistrationStage.ts index 74fe66c7..dfe71fa5 100644 --- a/src/matrix/registration/stages/BaseRegistrationStage.ts +++ b/src/matrix/registration/stages/BaseRegistrationStage.ts @@ -15,7 +15,7 @@ limitations under the License. */ import type {HomeServerApi} from "../../net/HomeServerApi"; -import type {AccountDetails, RegistrationResponse, AuthenticationData, RegistrationParams} from "../types"; +import type {AccountDetails, AuthenticationData, RegistrationParams} from "../types"; export abstract class BaseRegistrationStage { protected _hsApi: HomeServerApi; @@ -37,25 +37,16 @@ export abstract class BaseRegistrationStage { abstract get type(): string; /** - * Finish a registration stage, return value is: - * - the next stage if this stage was completed successfully - * - user-id (string) if registration is completed + * This method should return auth part that must be provided to + * /register endpoint to successfully complete this stage */ - abstract complete(auth?: AuthenticationData): Promise; + abstract generateAuthenticationData(): AuthenticationData; setNextStage(stage: BaseRegistrationStage) { this._nextStage = stage; } - parseResponse(response: RegistrationResponse) { - if ("user_id" in response) { - // registration completed successfully - return response.user_id; - } - else if ("completed" in response && response.completed.find(c => c === this.type)) { - return this._nextStage; - } - const error = "error" in response? response.error: "Could not parse response"; - throw new Error(error); + get nextStage(): BaseRegistrationStage { + return this._nextStage; } } diff --git a/src/matrix/registration/stages/DummyAuth.ts b/src/matrix/registration/stages/DummyAuth.ts index e22409db..b7f0a6ff 100644 --- a/src/matrix/registration/stages/DummyAuth.ts +++ b/src/matrix/registration/stages/DummyAuth.ts @@ -14,16 +14,15 @@ See the License for the specific language governing permissions and limitations under the License. */ +import {AuthenticationData} from "../types"; import {BaseRegistrationStage} from "./BaseRegistrationStage"; export class DummyAuth extends BaseRegistrationStage { - async complete() { - const { username, password, initialDeviceDisplayName, inhibitLogin } = this._accountDetails; - const response = await this._hsApi.register(username, password, initialDeviceDisplayName, { + generateAuthenticationData(): AuthenticationData { + return { session: this._session, - type: this.type - }, inhibitLogin).response(); - return this.parseResponse(response); + type: this.type, + }; } get type(): string { diff --git a/src/matrix/registration/stages/TermsAuth.ts b/src/matrix/registration/stages/TermsAuth.ts index e770b13b..bf54dd4d 100644 --- a/src/matrix/registration/stages/TermsAuth.ts +++ b/src/matrix/registration/stages/TermsAuth.ts @@ -14,16 +14,16 @@ See the License for the specific language governing permissions and limitations under the License. */ +import {AuthenticationData} from "../types"; import {BaseRegistrationStage} from "./BaseRegistrationStage"; export class TermsAuth extends BaseRegistrationStage { - async complete() { - const { username, password, initialDeviceDisplayName, inhibitLogin } = this._accountDetails; - const response = await this._hsApi.register(username, password, initialDeviceDisplayName, { + generateAuthenticationData(): AuthenticationData { + return { session: this._session, - type: this.type - }, inhibitLogin).response(); - return this.parseResponse(response); + type: this.type, + // No other auth data needed for m.login.terms + }; } get type(): string { diff --git a/src/matrix/registration/types.ts b/src/matrix/registration/types.ts index 08fc0fc4..aa319d43 100644 --- a/src/matrix/registration/types.ts +++ b/src/matrix/registration/types.ts @@ -35,7 +35,7 @@ type RegistrationResponseError = { error: string; } -type RegistrationResponseSuccess = { +export type RegistrationResponseSuccess = { user_id: string; device_id: string; access_token?: string; From c4894f2c240b89e6d85f4095b90e2e5969b53d49 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 3 Feb 2022 18:07:45 +0530 Subject: [PATCH 38/54] completed is not always present --- src/matrix/registration/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/matrix/registration/types.ts b/src/matrix/registration/types.ts index aa319d43..d79fd33a 100644 --- a/src/matrix/registration/types.ts +++ b/src/matrix/registration/types.ts @@ -24,7 +24,7 @@ export type AccountDetails = { export type RegistrationResponse = RegistrationResponseMoreDataNeeded | RegistrationResponseError | RegistrationResponseSuccess; export type RegistrationResponseMoreDataNeeded = { - completed: string[]; + completed?: string[]; flows: RegistrationFlow[]; params: Record; session: string; From 0ad0ecfcc23dd27527f7f6ca0fa7019f044e70da Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 3 Feb 2022 18:08:19 +0530 Subject: [PATCH 39/54] Check response code instead of existence of props --- src/matrix/net/HomeServerRequest.ts | 6 +++++ src/matrix/registration/Registration.ts | 33 ++++++++++++++++--------- src/matrix/registration/types.ts | 3 +++ 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/matrix/net/HomeServerRequest.ts b/src/matrix/net/HomeServerRequest.ts index c3f49834..066d5796 100644 --- a/src/matrix/net/HomeServerRequest.ts +++ b/src/matrix/net/HomeServerRequest.ts @@ -23,6 +23,7 @@ import type {IRequestOptions} from "../../platform/types/types.js"; export interface IHomeServerRequest { abort(): void; response(): Promise; + responseCode(): Promise; } export class HomeServerRequest implements IHomeServerRequest { @@ -110,6 +111,11 @@ export class HomeServerRequest implements IHomeServerRequest { response(): Promise { return this._promise; } + + async responseCode(): Promise { + const response = await this._sourceRequest.response(); + return response.status; + } } import {Request as MockRequest} from "../../mocks/Request.js"; diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index 0d408c2a..9b2c0684 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -57,8 +57,11 @@ export class Registration { async submitStage(stage: BaseRegistrationStage): Promise { const auth = stage.generateAuthenticationData(); const { username, password, initialDeviceDisplayName, inhibitLogin } = this._accountDetails; - const response = await this._hsApi.register(username, password, initialDeviceDisplayName, auth, inhibitLogin).response(); - return this.parseRegistrationResponse(response, stage); + const request = this._hsApi.register(username, password, initialDeviceDisplayName, auth, inhibitLogin); + const response = await request.response(); + const status = await request.responseCode(); + const registrationResponse: RegistrationResponse = { ...response, status }; + return this.parseRegistrationResponse(registrationResponse, stage); } parseStagesFromResponse(response: RegistrationResponseMoreDataNeeded): BaseRegistrationStage { @@ -86,17 +89,23 @@ export class Registration { return firstStage!; } - parseRegistrationResponse(response: RegistrationResponse, currentStage: BaseRegistrationStage) { - if ("user_id" in response) { - // registration completed successfully - this._sessionInfo = response; - return undefined; + async parseRegistrationResponse(response: RegistrationResponse, currentStage: BaseRegistrationStage) { + switch (response.status) { + case 200: + this._sessionInfo = response; + return undefined; + case 401: + if (response.completed?.includes(currentStage.type)) { + return currentStage.nextStage; + } + else { + throw new Error("This stage could not be completed!"); + } + case 400: + default: + const error = "error" in response? response.error: "Could not parse response"; + throw new Error(error); } - else if ("completed" in response && response.completed.find(c => c === currentStage.type)) { - return currentStage.nextStage; - } - const error = "error" in response? response.error: "Could not parse response"; - throw new Error(error); } get sessionInfo(): RegistrationResponseSuccess | undefined { diff --git a/src/matrix/registration/types.ts b/src/matrix/registration/types.ts index d79fd33a..77d051af 100644 --- a/src/matrix/registration/types.ts +++ b/src/matrix/registration/types.ts @@ -28,17 +28,20 @@ export type RegistrationResponseMoreDataNeeded = { flows: RegistrationFlow[]; params: Record; session: string; + status: 401; } type RegistrationResponseError = { errcode: string; error: string; + status: 400; } export type RegistrationResponseSuccess = { user_id: string; device_id: string; access_token?: string; + status: 200; } export type RegistrationFlow = { From 8a3c0afba6aa263819145445f82e5da4bcecb411 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 3 Feb 2022 18:42:02 +0530 Subject: [PATCH 40/54] Fix incorrect types --- src/matrix/net/HomeServerApi.ts | 82 ++++++++++++++++------------- src/matrix/net/HomeServerRequest.ts | 8 ++- src/platform/types/types.ts | 3 -- 3 files changed, 51 insertions(+), 42 deletions(-) diff --git a/src/matrix/net/HomeServerApi.ts b/src/matrix/net/HomeServerApi.ts index b9651cee..88ff32d9 100644 --- a/src/matrix/net/HomeServerApi.ts +++ b/src/matrix/net/HomeServerApi.ts @@ -20,7 +20,7 @@ import {HomeServerRequest} from "./HomeServerRequest"; import type {IHomeServerRequest} from "./HomeServerRequest"; import type {Reconnector} from "./Reconnector"; import type {EncodedBody} from "./common"; -import type {IRequestOptions, RequestFunction} from "../../platform/types/types"; +import type {RequestFunction} from "../../platform/types/types"; import type {ILogItem} from "../../logging/types"; type RequestMethod = "POST" | "GET" | "PUT"; @@ -36,6 +36,14 @@ type Options = { reconnector: Reconnector; }; +type BaseRequestOptions = { + log?: ILogItem; + allowedErrors?: number[]; + uploadProgress?: (loadedBytes: number) => void; + timeout?: number; + prefix?: string; +}; + export class HomeServerApi { private readonly _homeserver: string; private readonly _accessToken: string; @@ -55,7 +63,7 @@ export class HomeServerApi { return this._homeserver + prefix + csPath; } - private _baseRequest(method: RequestMethod, url: string, queryParams?: Record, body?: Record, options?: IRequestOptions, accessToken?: string): IHomeServerRequest { + private _baseRequest(method: RequestMethod, url: string, queryParams?: Record, body?: Record, options?: BaseRequestOptions, accessToken?: string): IHomeServerRequest { const queryString = encodeQueryParams(queryParams); url = `${url}?${queryString}`; let encodedBody: EncodedBody["body"]; @@ -97,27 +105,27 @@ export class HomeServerApi { return hsRequest; } - private _unauthedRequest(method: RequestMethod, url: string, queryParams?: Record, body?: Record, options?: IRequestOptions): IHomeServerRequest { + private _unauthedRequest(method: RequestMethod, url: string, queryParams?: Record, body?: Record, options?: BaseRequestOptions): IHomeServerRequest { return this._baseRequest(method, url, queryParams, body, options); } - private _authedRequest(method: RequestMethod, url: string, queryParams?: Record, body?: Record, options?: IRequestOptions): IHomeServerRequest { + private _authedRequest(method: RequestMethod, url: string, queryParams?: Record, body?: Record, options?: BaseRequestOptions): IHomeServerRequest { return this._baseRequest(method, url, queryParams, body, options, this._accessToken); } - private _post(csPath: string, queryParams: Record, body: Record, options?: IRequestOptions): IHomeServerRequest { + private _post(csPath: string, queryParams: Record, body: Record, options?: BaseRequestOptions): IHomeServerRequest { return this._authedRequest("POST", this._url(csPath, options?.prefix || CS_R0_PREFIX), queryParams, body, options); } - private _put(csPath: string, queryParams: Record, body?: Record, options?: IRequestOptions): IHomeServerRequest { + private _put(csPath: string, queryParams: Record, body?: Record, options?: BaseRequestOptions): IHomeServerRequest { return this._authedRequest("PUT", this._url(csPath, options?.prefix || CS_R0_PREFIX), queryParams, body, options); } - private _get(csPath: string, queryParams?: Record, body?: Record, options?: IRequestOptions): IHomeServerRequest { + private _get(csPath: string, queryParams?: Record, body?: Record, options?: BaseRequestOptions): IHomeServerRequest { return this._authedRequest("GET", this._url(csPath, options?.prefix || CS_R0_PREFIX), queryParams, body, options); } - sync(since: string, filter: string, timeout: number, options?: IRequestOptions): IHomeServerRequest { + sync(since: string, filter: string, timeout: number, options?: BaseRequestOptions): IHomeServerRequest { return this._get("/sync", {since, timeout, filter}, undefined, options); } @@ -126,29 +134,29 @@ export class HomeServerApi { } // params is from, dir and optionally to, limit, filter. - messages(roomId: string, params: Record, options?: IRequestOptions): IHomeServerRequest { + messages(roomId: string, params: Record, options?: BaseRequestOptions): IHomeServerRequest { return this._get(`/rooms/${encodeURIComponent(roomId)}/messages`, params, undefined, options); } // params is at, membership and not_membership - members(roomId: string, params: Record, options?: IRequestOptions): IHomeServerRequest { + members(roomId: string, params: Record, options?: BaseRequestOptions): IHomeServerRequest { return this._get(`/rooms/${encodeURIComponent(roomId)}/members`, params, undefined, options); } - send(roomId: string, eventType: string, txnId: string, content: Record, options?: IRequestOptions): IHomeServerRequest { + send(roomId: string, eventType: string, txnId: string, content: Record, options?: BaseRequestOptions): IHomeServerRequest { return this._put(`/rooms/${encodeURIComponent(roomId)}/send/${encodeURIComponent(eventType)}/${encodeURIComponent(txnId)}`, {}, content, options); } - redact(roomId: string, eventId: string, txnId: string, content: Record, options?: IRequestOptions): IHomeServerRequest { + redact(roomId: string, eventId: string, txnId: string, content: Record, options?: BaseRequestOptions): IHomeServerRequest { return this._put(`/rooms/${encodeURIComponent(roomId)}/redact/${encodeURIComponent(eventId)}/${encodeURIComponent(txnId)}`, {}, content, options); } - receipt(roomId: string, receiptType: string, eventId: string, options?: IRequestOptions): IHomeServerRequest { + receipt(roomId: string, receiptType: string, eventId: string, options?: BaseRequestOptions): IHomeServerRequest { return this._post(`/rooms/${encodeURIComponent(roomId)}/receipt/${encodeURIComponent(receiptType)}/${encodeURIComponent(eventId)}`, {}, {}, options); } - state(roomId: string, eventType: string, stateKey: string, options?: IRequestOptions): IHomeServerRequest { + state(roomId: string, eventType: string, stateKey: string, options?: BaseRequestOptions): IHomeServerRequest { return this._get(`/rooms/${encodeURIComponent(roomId)}/state/${encodeURIComponent(eventType)}/${encodeURIComponent(stateKey)}`, {}, undefined, options); } @@ -156,7 +164,7 @@ export class HomeServerApi { return this._unauthedRequest("GET", this._url("/login")); } - register(username: string | null, password: string, initialDeviceDisplayName: string, auth?: Record, inhibitLogin: boolean = true , options: IRequestOptions = {}): IHomeServerRequest { + register(username: string | null, password: string, initialDeviceDisplayName: string, auth?: Record, inhibitLogin: boolean = true , options: BaseRequestOptions = {}): IHomeServerRequest { options.allowedErrors = [401]; const body: any = { auth, @@ -171,7 +179,7 @@ export class HomeServerApi { return this._unauthedRequest( "POST", this._url("/register", CS_V3_PREFIX), undefined, body, options); } - passwordLogin(username: string, password: string, initialDeviceDisplayName: string, options?: IRequestOptions): IHomeServerRequest { + passwordLogin(username: string, password: string, initialDeviceDisplayName: string, options?: BaseRequestOptions): IHomeServerRequest { return this._unauthedRequest("POST", this._url("/login"), undefined, { "type": "m.login.password", "identifier": { @@ -183,7 +191,7 @@ export class HomeServerApi { }, options); } - tokenLogin(loginToken: string, txnId: string, initialDeviceDisplayName: string, options?: IRequestOptions): IHomeServerRequest { + tokenLogin(loginToken: string, txnId: string, initialDeviceDisplayName: string, options?: BaseRequestOptions): IHomeServerRequest { return this._unauthedRequest("POST", this._url("/login"), undefined, { "type": "m.login.token", "identifier": { @@ -195,15 +203,15 @@ export class HomeServerApi { }, options); } - createFilter(userId: string, filter: Record, options?: IRequestOptions): IHomeServerRequest { + createFilter(userId: string, filter: Record, options?: BaseRequestOptions): IHomeServerRequest { return this._post(`/user/${encodeURIComponent(userId)}/filter`, {}, filter, options); } - versions(options?: IRequestOptions): IHomeServerRequest { + versions(options?: BaseRequestOptions): IHomeServerRequest { return this._unauthedRequest("GET", `${this._homeserver}/_matrix/client/versions`, undefined, undefined, options); } - uploadKeys(dehydratedDeviceId: string, payload: Record, options?: IRequestOptions): IHomeServerRequest { + uploadKeys(dehydratedDeviceId: string, payload: Record, options?: BaseRequestOptions): IHomeServerRequest { let path = "/keys/upload"; if (dehydratedDeviceId) { path = path + `/${encodeURIComponent(dehydratedDeviceId)}`; @@ -211,19 +219,19 @@ export class HomeServerApi { return this._post(path, {}, payload, options); } - queryKeys(queryRequest: Record, options?: IRequestOptions): IHomeServerRequest { + queryKeys(queryRequest: Record, options?: BaseRequestOptions): IHomeServerRequest { return this._post("/keys/query", {}, queryRequest, options); } - claimKeys(payload: Record, options?: IRequestOptions): IHomeServerRequest { + claimKeys(payload: Record, options?: BaseRequestOptions): IHomeServerRequest { return this._post("/keys/claim", {}, payload, options); } - sendToDevice(type: string, payload: Record, txnId: string, options?: IRequestOptions): IHomeServerRequest { + sendToDevice(type: string, payload: Record, txnId: string, options?: BaseRequestOptions): IHomeServerRequest { return this._put(`/sendToDevice/${encodeURIComponent(type)}/${encodeURIComponent(txnId)}`, {}, payload, options); } - roomKeysVersion(version?: string, options?: IRequestOptions): IHomeServerRequest { + roomKeysVersion(version?: string, options?: BaseRequestOptions): IHomeServerRequest { let versionPart = ""; if (version) { versionPart = `/${encodeURIComponent(version)}`; @@ -231,57 +239,57 @@ export class HomeServerApi { return this._get(`/room_keys/version${versionPart}`, undefined, undefined, options); } - roomKeyForRoomAndSession(version: string, roomId: string, sessionId: string, options?: IRequestOptions): IHomeServerRequest { + roomKeyForRoomAndSession(version: string, roomId: string, sessionId: string, options?: BaseRequestOptions): IHomeServerRequest { return this._get(`/room_keys/keys/${encodeURIComponent(roomId)}/${encodeURIComponent(sessionId)}`, {version}, undefined, options); } - uploadRoomKeysToBackup(version: string, payload: Record, options?: IRequestOptions): IHomeServerRequest { + uploadRoomKeysToBackup(version: string, payload: Record, options?: BaseRequestOptions): IHomeServerRequest { return this._put(`/room_keys/keys`, {version}, payload, options); } - uploadAttachment(blob: Blob, filename: string, options?: IRequestOptions): IHomeServerRequest { + uploadAttachment(blob: Blob, filename: string, options?: BaseRequestOptions): IHomeServerRequest { return this._authedRequest("POST", `${this._homeserver}/_matrix/media/r0/upload`, {filename}, blob, options); } - setPusher(pusher: Record, options?: IRequestOptions): IHomeServerRequest { + setPusher(pusher: Record, options?: BaseRequestOptions): IHomeServerRequest { return this._post("/pushers/set", {}, pusher, options); } - getPushers(options?: IRequestOptions): IHomeServerRequest { + getPushers(options?: BaseRequestOptions): IHomeServerRequest { return this._get("/pushers", undefined, undefined, options); } - join(roomId: string, options?: IRequestOptions): IHomeServerRequest { + join(roomId: string, options?: BaseRequestOptions): IHomeServerRequest { return this._post(`/rooms/${encodeURIComponent(roomId)}/join`, {}, {}, options); } - joinIdOrAlias(roomIdOrAlias: string, options?: IRequestOptions): IHomeServerRequest { + joinIdOrAlias(roomIdOrAlias: string, options?: BaseRequestOptions): IHomeServerRequest { return this._post(`/join/${encodeURIComponent(roomIdOrAlias)}`, {}, {}, options); } - leave(roomId: string, options?: IRequestOptions): IHomeServerRequest { + leave(roomId: string, options?: BaseRequestOptions): IHomeServerRequest { return this._post(`/rooms/${encodeURIComponent(roomId)}/leave`, {}, {}, options); } - forget(roomId: string, options?: IRequestOptions): IHomeServerRequest { + forget(roomId: string, options?: BaseRequestOptions): IHomeServerRequest { return this._post(`/rooms/${encodeURIComponent(roomId)}/forget`, {}, {}, options); } - logout(options?: IRequestOptions): IHomeServerRequest { + logout(options?: BaseRequestOptions): IHomeServerRequest { return this._post(`/logout`, {}, {}, options); } - getDehydratedDevice(options: IRequestOptions): IHomeServerRequest { + getDehydratedDevice(options: BaseRequestOptions): IHomeServerRequest { options.prefix = DEHYDRATION_PREFIX; return this._get(`/dehydrated_device`, undefined, undefined, options); } - createDehydratedDevice(payload: Record, options: IRequestOptions): IHomeServerRequest { + createDehydratedDevice(payload: Record, options: BaseRequestOptions): IHomeServerRequest { options.prefix = DEHYDRATION_PREFIX; return this._put(`/dehydrated_device`, {}, payload, options); } - claimDehydratedDevice(deviceId: string, options: IRequestOptions): IHomeServerRequest { + claimDehydratedDevice(deviceId: string, options: BaseRequestOptions): IHomeServerRequest { options.prefix = DEHYDRATION_PREFIX; return this._post(`/dehydrated_device/claim`, {}, {device_id: deviceId}, options); } diff --git a/src/matrix/net/HomeServerRequest.ts b/src/matrix/net/HomeServerRequest.ts index 066d5796..ee4ad2ba 100644 --- a/src/matrix/net/HomeServerRequest.ts +++ b/src/matrix/net/HomeServerRequest.ts @@ -18,7 +18,6 @@ limitations under the License. import {HomeServerError, ConnectionError} from "../error.js"; import type {RequestResult} from "../../platform/web/dom/request/fetch.js"; import type {ILogItem} from "../../logging/types"; -import type {IRequestOptions} from "../../platform/types/types.js"; export interface IHomeServerRequest { abort(): void; @@ -26,13 +25,18 @@ export interface IHomeServerRequest { responseCode(): Promise; } +type HomeServerRequestOptions = { + log?: ILogItem; + allowedErrors?: number[]; +}; + export class HomeServerRequest implements IHomeServerRequest { private readonly _log?: ILogItem; private _sourceRequest?: RequestResult; // as we add types for expected responses from hs, this could be a generic class instead private readonly _promise: Promise; - constructor(method: string, url: string, sourceRequest: RequestResult, options?: IRequestOptions) { + constructor(method: string, url: string, sourceRequest: RequestResult, options?: HomeServerRequestOptions) { let log: ILogItem | undefined; if (options?.log) { const parent = options?.log; diff --git a/src/platform/types/types.ts b/src/platform/types/types.ts index 0ad569b4..cc57d56f 100644 --- a/src/platform/types/types.ts +++ b/src/platform/types/types.ts @@ -24,11 +24,8 @@ export interface IRequestOptions { body?: EncodedBody; headers?: Map; cache?: boolean; - log?: ILogItem; - prefix?: string; method?: string; format?: string; - allowedErrors?: number[]; } export type RequestFunction = (url: string, options: IRequestOptions) => RequestResult; From 89a97537b0d081ef56a8e06b5418b6ff9cd58943 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 3 Feb 2022 19:37:14 +0530 Subject: [PATCH 41/54] Make methods private + some props readonly --- src/matrix/registration/Registration.ts | 10 +++++----- .../registration/stages/BaseRegistrationStage.ts | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index 9b2c0684..d50cbca5 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -28,9 +28,9 @@ import type { type FlowSelector = (flows: RegistrationFlow[]) => RegistrationFlow | void; export class Registration { - private _hsApi: HomeServerApi; - private _accountDetails: AccountDetails; - private _flowSelector: FlowSelector; + private readonly _hsApi: HomeServerApi; + private readonly _accountDetails: AccountDetails; + private readonly _flowSelector: FlowSelector; private _sessionInfo?: RegistrationResponseSuccess constructor(hsApi: HomeServerApi, accountDetails: AccountDetails, flowSelector?: FlowSelector) { @@ -64,7 +64,7 @@ export class Registration { return this.parseRegistrationResponse(registrationResponse, stage); } - parseStagesFromResponse(response: RegistrationResponseMoreDataNeeded): BaseRegistrationStage { + private parseStagesFromResponse(response: RegistrationResponseMoreDataNeeded): BaseRegistrationStage { const { session, params } = response; const flow = this._flowSelector(response.flows); if (!flow) { @@ -89,7 +89,7 @@ export class Registration { return firstStage!; } - async parseRegistrationResponse(response: RegistrationResponse, currentStage: BaseRegistrationStage) { + private async parseRegistrationResponse(response: RegistrationResponse, currentStage: BaseRegistrationStage) { switch (response.status) { case 200: this._sessionInfo = response; diff --git a/src/matrix/registration/stages/BaseRegistrationStage.ts b/src/matrix/registration/stages/BaseRegistrationStage.ts index dfe71fa5..964cc75d 100644 --- a/src/matrix/registration/stages/BaseRegistrationStage.ts +++ b/src/matrix/registration/stages/BaseRegistrationStage.ts @@ -18,11 +18,11 @@ import type {HomeServerApi} from "../../net/HomeServerApi"; import type {AccountDetails, AuthenticationData, RegistrationParams} from "../types"; export abstract class BaseRegistrationStage { - protected _hsApi: HomeServerApi; - protected _accountDetails: AccountDetails; + protected readonly _hsApi: HomeServerApi; + protected readonly _accountDetails: AccountDetails; protected _session: string; protected _nextStage: BaseRegistrationStage; - protected _params?: Record + protected readonly _params?: Record constructor(hsApi: HomeServerApi, accountDetails: AccountDetails, session: string, params?: RegistrationParams) { this._hsApi = hsApi; From b6e1d4a7d5a3f243e2c50951407febe155f92e89 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Thu, 3 Feb 2022 19:37:34 +0530 Subject: [PATCH 42/54] Implement responseCode() --- src/matrix/net/RequestScheduler.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/matrix/net/RequestScheduler.ts b/src/matrix/net/RequestScheduler.ts index 45405da3..e36a3541 100644 --- a/src/matrix/net/RequestScheduler.ts +++ b/src/matrix/net/RequestScheduler.ts @@ -50,6 +50,13 @@ class Request implements IHomeServerRequest { response(): Promise { return this._responsePromise; } + + async responseCode(): Promise { + let resolve; + const promise: Promise = new Promise(r => resolve = r); + this.requestResult?.responseCode().then(code => resolve(code)); + return promise; + } } class HomeServerApiWrapper { From 3d8b9cce41b347eb68b2d363a991874ff4677473 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 4 Feb 2022 15:41:37 +0530 Subject: [PATCH 43/54] Fix responseCode in Request --- src/matrix/net/RequestScheduler.ts | 45 +++++++++++++++++++----------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/src/matrix/net/RequestScheduler.ts b/src/matrix/net/RequestScheduler.ts index e36a3541..e2118c5e 100644 --- a/src/matrix/net/RequestScheduler.ts +++ b/src/matrix/net/RequestScheduler.ts @@ -25,25 +25,33 @@ import type {IHomeServerRequest} from "./HomeServerRequest.js"; class Request implements IHomeServerRequest { public readonly methodName: string; public readonly args: any[]; - public resolve: (result: any) => void; - public reject: (error: Error) => void; - public requestResult?: IHomeServerRequest; + private responseResolve: (result: any) => void; + public responseReject: (error: Error) => void; + private responseCodeResolve: (result: any) => void; + private responseCodeReject: (result: any) => void; + private _requestResult?: IHomeServerRequest; private readonly _responsePromise: Promise; + private readonly _responseCodePromise: Promise; constructor(methodName: string, args: any[]) { this.methodName = methodName; this.args = args; this._responsePromise = new Promise((resolve, reject) => { - this.resolve = resolve; - this.reject = reject; + this.responseResolve = resolve; + this.responseReject = reject; + }); + this._responseCodePromise = new Promise((resolve, reject) => { + this.responseCodeResolve = resolve; + this.responseCodeReject = reject; }); } abort(): void { - if (this.requestResult) { - this.requestResult.abort(); + if (this._requestResult) { + this._requestResult.abort(); } else { - this.reject(new AbortError()); + this.responseReject(new AbortError()); + this.responseCodeReject(new AbortError()); } } @@ -51,11 +59,18 @@ class Request implements IHomeServerRequest { return this._responsePromise; } - async responseCode(): Promise { - let resolve; - const promise: Promise = new Promise(r => resolve = r); - this.requestResult?.responseCode().then(code => resolve(code)); - return promise; + responseCode(): Promise { + return this._responseCodePromise; + } + + set requestResult(result) { + this._requestResult = result; + this._requestResult?.response().then(response => this.responseResolve(response)); + this._requestResult?.responseCode().then(response => this.responseCodeResolve(response)); + } + + get requestResult() { + return this._requestResult; } } @@ -121,8 +136,6 @@ export class RequestScheduler { ].apply(this._hsApi, request.args); // so the request can be aborted request.requestResult = requestResult; - const response = await requestResult.response(); - request.resolve(response); return; } catch (err) { if ( @@ -142,7 +155,7 @@ export class RequestScheduler { await retryDelay.waitForRetry(); } } else { - request.reject(err); + request.responseReject(err); return; } } From 32af7e6f0980b8c9c853dce8e5a665cdade243e4 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 4 Feb 2022 16:23:39 +0530 Subject: [PATCH 44/54] Make more changes - make setter a method - lazily create promise --- src/matrix/net/RequestScheduler.ts | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/matrix/net/RequestScheduler.ts b/src/matrix/net/RequestScheduler.ts index e2118c5e..cee4142f 100644 --- a/src/matrix/net/RequestScheduler.ts +++ b/src/matrix/net/RequestScheduler.ts @@ -31,7 +31,7 @@ class Request implements IHomeServerRequest { private responseCodeReject: (result: any) => void; private _requestResult?: IHomeServerRequest; private readonly _responsePromise: Promise; - private readonly _responseCodePromise: Promise; + private _responseCodePromise: Promise; constructor(methodName: string, args: any[]) { this.methodName = methodName; @@ -40,10 +40,6 @@ class Request implements IHomeServerRequest { this.responseResolve = resolve; this.responseReject = reject; }); - this._responseCodePromise = new Promise((resolve, reject) => { - this.responseCodeResolve = resolve; - this.responseCodeReject = reject; - }); } abort(): void { @@ -60,13 +56,22 @@ class Request implements IHomeServerRequest { } responseCode(): Promise { + if (this.requestResult) { + return this.requestResult.responseCode(); + } + if (!this._responseCodePromise) { + this._responseCodePromise = new Promise((resolve, reject) => { + this.responseCodeResolve = resolve; + this.responseCodeReject = reject; + }); + } return this._responseCodePromise; } - set requestResult(result) { + setRequestResult(result) { this._requestResult = result; this._requestResult?.response().then(response => this.responseResolve(response)); - this._requestResult?.responseCode().then(response => this.responseCodeResolve(response)); + this._requestResult?.responseCode().then(response => this.responseCodeResolve?.(response)); } get requestResult() { @@ -135,7 +140,7 @@ export class RequestScheduler { request.methodName ].apply(this._hsApi, request.args); // so the request can be aborted - request.requestResult = requestResult; + request.setRequestResult(requestResult); return; } catch (err) { if ( From 891375a885b513d90054a02cab066f10ba62b4aa Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 4 Feb 2022 16:35:47 +0530 Subject: [PATCH 45/54] Rename allowerErrors -> allowedStatusCodes --- src/matrix/net/HomeServerApi.ts | 4 ++-- src/matrix/net/HomeServerRequest.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/matrix/net/HomeServerApi.ts b/src/matrix/net/HomeServerApi.ts index 88ff32d9..605607b6 100644 --- a/src/matrix/net/HomeServerApi.ts +++ b/src/matrix/net/HomeServerApi.ts @@ -38,7 +38,7 @@ type Options = { type BaseRequestOptions = { log?: ILogItem; - allowedErrors?: number[]; + allowedStatusCodes?: number[]; uploadProgress?: (loadedBytes: number) => void; timeout?: number; prefix?: string; @@ -165,7 +165,7 @@ export class HomeServerApi { } register(username: string | null, password: string, initialDeviceDisplayName: string, auth?: Record, inhibitLogin: boolean = true , options: BaseRequestOptions = {}): IHomeServerRequest { - options.allowedErrors = [401]; + options.allowedStatusCodes = [401]; const body: any = { auth, password, diff --git a/src/matrix/net/HomeServerRequest.ts b/src/matrix/net/HomeServerRequest.ts index ee4ad2ba..d6745d03 100644 --- a/src/matrix/net/HomeServerRequest.ts +++ b/src/matrix/net/HomeServerRequest.ts @@ -27,7 +27,7 @@ export interface IHomeServerRequest { type HomeServerRequestOptions = { log?: ILogItem; - allowedErrors?: number[]; + allowedStatusCodes?: number[]; }; export class HomeServerRequest implements IHomeServerRequest { @@ -47,7 +47,7 @@ export class HomeServerRequest implements IHomeServerRequest { this._promise = sourceRequest.response().then(response => { log?.set("status", response.status); // ok? - if (response.status >= 200 && response.status < 300 || options?.allowedErrors?.includes(response.status)) { + if (response.status >= 200 && response.status < 300 || options?.allowedStatusCodes?.includes(response.status)) { log?.finish(); return response.body; } else { From e8c480426ae9bf92ac7a946e48a1206c7e457640 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 4 Feb 2022 16:37:43 +0530 Subject: [PATCH 46/54] Remove error code --- src/matrix/registration/Registration.ts | 4 ---- src/matrix/registration/types.ts | 8 +------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index d50cbca5..c3b91e3b 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -101,10 +101,6 @@ export class Registration { else { throw new Error("This stage could not be completed!"); } - case 400: - default: - const error = "error" in response? response.error: "Could not parse response"; - throw new Error(error); } } diff --git a/src/matrix/registration/types.ts b/src/matrix/registration/types.ts index 77d051af..f1ddbe98 100644 --- a/src/matrix/registration/types.ts +++ b/src/matrix/registration/types.ts @@ -21,7 +21,7 @@ export type AccountDetails = { inhibitLogin: boolean; } -export type RegistrationResponse = RegistrationResponseMoreDataNeeded | RegistrationResponseError | RegistrationResponseSuccess; +export type RegistrationResponse = RegistrationResponseMoreDataNeeded | RegistrationResponseSuccess; export type RegistrationResponseMoreDataNeeded = { completed?: string[]; @@ -31,12 +31,6 @@ export type RegistrationResponseMoreDataNeeded = { status: 401; } -type RegistrationResponseError = { - errcode: string; - error: string; - status: 400; -} - export type RegistrationResponseSuccess = { user_id: string; device_id: string; From e66549a0671fcec9a9c7b382df5df2af2c99ef48 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 4 Feb 2022 16:40:49 +0530 Subject: [PATCH 47/54] Remove dead code --- src/matrix/registration/Registration.ts | 2 +- src/matrix/registration/registrationStageFromType.ts | 5 ++--- src/matrix/registration/stages/BaseRegistrationStage.ts | 6 +----- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index c3b91e3b..ad0b461e 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -77,7 +77,7 @@ export class Registration { if (!stageClass) { throw new Error(`Unknown stage: ${stage}`); } - const registrationStage = new stageClass(this._hsApi, this._accountDetails, session, params?.[stage]); + const registrationStage = new stageClass(session, params?.[stage]); if (!firstStage) { firstStage = registrationStage; lastStage = registrationStage; diff --git a/src/matrix/registration/registrationStageFromType.ts b/src/matrix/registration/registrationStageFromType.ts index 6b120a6f..cf08e0ec 100644 --- a/src/matrix/registration/registrationStageFromType.ts +++ b/src/matrix/registration/registrationStageFromType.ts @@ -15,12 +15,11 @@ limitations under the License. */ import type {BaseRegistrationStage} from "./stages/BaseRegistrationStage"; -import type {HomeServerApi} from "../net/HomeServerApi"; -import type {AccountDetails, RegistrationParams} from "./types"; +import type {RegistrationParams} from "./types"; import {DummyAuth} from "./stages/DummyAuth"; import {TermsAuth} from "./stages/TermsAuth"; -type ClassDerivedFromBaseRegistration = { new(hsApi: HomeServerApi, registrationData: AccountDetails, session: string, params?: RegistrationParams): BaseRegistrationStage } & typeof BaseRegistrationStage; +type ClassDerivedFromBaseRegistration = { new(session: string, params?: RegistrationParams): BaseRegistrationStage } & typeof BaseRegistrationStage; export function registrationStageFromType(type: string): ClassDerivedFromBaseRegistration | undefined{ switch (type) { diff --git a/src/matrix/registration/stages/BaseRegistrationStage.ts b/src/matrix/registration/stages/BaseRegistrationStage.ts index 964cc75d..426dbf2c 100644 --- a/src/matrix/registration/stages/BaseRegistrationStage.ts +++ b/src/matrix/registration/stages/BaseRegistrationStage.ts @@ -18,15 +18,11 @@ import type {HomeServerApi} from "../../net/HomeServerApi"; import type {AccountDetails, AuthenticationData, RegistrationParams} from "../types"; export abstract class BaseRegistrationStage { - protected readonly _hsApi: HomeServerApi; - protected readonly _accountDetails: AccountDetails; protected _session: string; protected _nextStage: BaseRegistrationStage; protected readonly _params?: Record - constructor(hsApi: HomeServerApi, accountDetails: AccountDetails, session: string, params?: RegistrationParams) { - this._hsApi = hsApi; - this._accountDetails = accountDetails; + constructor(session: string, params?: RegistrationParams) { this._session = session; this._params = params; } From 22d5505a2b7932d8a8257d9a5e3c3f1f6419b3da Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 4 Feb 2022 16:50:22 +0530 Subject: [PATCH 48/54] Create registration stage in Registration itself --- src/matrix/registration/Registration.ts | 21 +++++++++---- .../registration/registrationStageFromType.ts | 31 ------------------- 2 files changed, 15 insertions(+), 37 deletions(-) delete mode 100644 src/matrix/registration/registrationStageFromType.ts diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index ad0b461e..3d8ec9fc 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -15,14 +15,16 @@ limitations under the License. */ import type {HomeServerApi} from "../net/HomeServerApi"; -import {registrationStageFromType} from "./registrationStageFromType"; import type {BaseRegistrationStage} from "./stages/BaseRegistrationStage"; +import {DummyAuth} from "./stages/DummyAuth"; +import {TermsAuth} from "./stages/TermsAuth"; import type { AccountDetails, RegistrationFlow, RegistrationResponseMoreDataNeeded, RegistrationResponse, RegistrationResponseSuccess, + RegistrationParams, } from "./types"; type FlowSelector = (flows: RegistrationFlow[]) => RegistrationFlow | void; @@ -73,11 +75,7 @@ export class Registration { let firstStage: BaseRegistrationStage | undefined; let lastStage: BaseRegistrationStage; for (const stage of flow.stages) { - const stageClass = registrationStageFromType(stage); - if (!stageClass) { - throw new Error(`Unknown stage: ${stage}`); - } - const registrationStage = new stageClass(session, params?.[stage]); + const registrationStage = this._createRegistrationStage(stage, session, params); if (!firstStage) { firstStage = registrationStage; lastStage = registrationStage; @@ -104,6 +102,17 @@ export class Registration { } } + private _createRegistrationStage(type: string, session: string, params?: RegistrationParams) { + switch (type) { + case "m.login.dummy": + return new DummyAuth(session, params); + case "m.login.terms": + return new TermsAuth(session, params); + default: + throw new Error(`Unknown stage: ${type}`); + } + } + get sessionInfo(): RegistrationResponseSuccess | undefined { return this._sessionInfo; } diff --git a/src/matrix/registration/registrationStageFromType.ts b/src/matrix/registration/registrationStageFromType.ts deleted file mode 100644 index cf08e0ec..00000000 --- a/src/matrix/registration/registrationStageFromType.ts +++ /dev/null @@ -1,31 +0,0 @@ -/* -Copyright 2021 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. -*/ - -import type {BaseRegistrationStage} from "./stages/BaseRegistrationStage"; -import type {RegistrationParams} from "./types"; -import {DummyAuth} from "./stages/DummyAuth"; -import {TermsAuth} from "./stages/TermsAuth"; - -type ClassDerivedFromBaseRegistration = { new(session: string, params?: RegistrationParams): BaseRegistrationStage } & typeof BaseRegistrationStage; - -export function registrationStageFromType(type: string): ClassDerivedFromBaseRegistration | undefined{ - switch (type) { - case "m.login.dummy": - return DummyAuth; - case "m.login.terms": - return TermsAuth; - } -} From 028b96e4c547302389a09efa63cd8e65a22dde68 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 4 Feb 2022 17:11:33 +0530 Subject: [PATCH 49/54] Let type also be undefined --- src/matrix/registration/Registration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index 3d8ec9fc..a0b4eb89 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -73,7 +73,7 @@ export class Registration { throw new Error("flowSelector did not return any flow!"); } let firstStage: BaseRegistrationStage | undefined; - let lastStage: BaseRegistrationStage; + let lastStage: BaseRegistrationStage | undefined; for (const stage of flow.stages) { const registrationStage = this._createRegistrationStage(stage, session, params); if (!firstStage) { From 2ac63e78cade3c7dd635f0cdf28349db39ed069d Mon Sep 17 00:00:00 2001 From: R Midhun Suresh Date: Fri, 4 Feb 2022 17:16:15 +0530 Subject: [PATCH 50/54] mark method as internal Co-authored-by: Bruno Windels --- src/matrix/registration/stages/BaseRegistrationStage.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/matrix/registration/stages/BaseRegistrationStage.ts b/src/matrix/registration/stages/BaseRegistrationStage.ts index 964cc75d..c9350fdb 100644 --- a/src/matrix/registration/stages/BaseRegistrationStage.ts +++ b/src/matrix/registration/stages/BaseRegistrationStage.ts @@ -40,6 +40,7 @@ export abstract class BaseRegistrationStage { * This method should return auth part that must be provided to * /register endpoint to successfully complete this stage */ + /** @internal */ abstract generateAuthenticationData(): AuthenticationData; setNextStage(stage: BaseRegistrationStage) { From 0828ac12b1d2e0bbbe8445f18b12927b9c3f067e Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 4 Feb 2022 17:25:15 +0530 Subject: [PATCH 51/54] Fix params --- src/matrix/registration/Registration.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/matrix/registration/Registration.ts b/src/matrix/registration/Registration.ts index a0b4eb89..c9c9af87 100644 --- a/src/matrix/registration/Registration.ts +++ b/src/matrix/registration/Registration.ts @@ -105,9 +105,9 @@ export class Registration { private _createRegistrationStage(type: string, session: string, params?: RegistrationParams) { switch (type) { case "m.login.dummy": - return new DummyAuth(session, params); + return new DummyAuth(session, params?.[type]); case "m.login.terms": - return new TermsAuth(session, params); + return new TermsAuth(session, params?.[type]); default: throw new Error(`Unknown stage: ${type}`); } From a163cee18d0d21eed3134f8c00fa9a0065e45d12 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 4 Feb 2022 17:25:30 +0530 Subject: [PATCH 52/54] Remove dead imports --- src/matrix/registration/stages/BaseRegistrationStage.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/matrix/registration/stages/BaseRegistrationStage.ts b/src/matrix/registration/stages/BaseRegistrationStage.ts index 71972a64..cc5f46c1 100644 --- a/src/matrix/registration/stages/BaseRegistrationStage.ts +++ b/src/matrix/registration/stages/BaseRegistrationStage.ts @@ -14,8 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import type {HomeServerApi} from "../../net/HomeServerApi"; -import type {AccountDetails, AuthenticationData, RegistrationParams} from "../types"; +import type {AuthenticationData, RegistrationParams} from "../types"; export abstract class BaseRegistrationStage { protected _session: string; From f7f32ac80677c5e0388ca33b84d0d35e9cf68c62 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 4 Feb 2022 17:39:52 +0530 Subject: [PATCH 53/54] responseCodeReject may not exist --- src/matrix/net/RequestScheduler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/matrix/net/RequestScheduler.ts b/src/matrix/net/RequestScheduler.ts index cee4142f..276de639 100644 --- a/src/matrix/net/RequestScheduler.ts +++ b/src/matrix/net/RequestScheduler.ts @@ -47,7 +47,7 @@ class Request implements IHomeServerRequest { this._requestResult.abort(); } else { this.responseReject(new AbortError()); - this.responseCodeReject(new AbortError()); + this.responseCodeReject?.(new AbortError()); } } From 28931f41035ff6db2861b53f083bc2970b89d8a1 Mon Sep 17 00:00:00 2001 From: RMidhunSuresh Date: Fri, 4 Feb 2022 17:48:42 +0530 Subject: [PATCH 54/54] Use async/await --- src/matrix/net/RequestScheduler.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/matrix/net/RequestScheduler.ts b/src/matrix/net/RequestScheduler.ts index 276de639..dc5c501b 100644 --- a/src/matrix/net/RequestScheduler.ts +++ b/src/matrix/net/RequestScheduler.ts @@ -68,10 +68,12 @@ class Request implements IHomeServerRequest { return this._responseCodePromise; } - setRequestResult(result) { + async setRequestResult(result) { this._requestResult = result; - this._requestResult?.response().then(response => this.responseResolve(response)); - this._requestResult?.responseCode().then(response => this.responseCodeResolve?.(response)); + const response = await this._requestResult?.response(); + this.responseResolve(response); + const responseCode = await this._requestResult?.responseCode(); + this.responseCodeResolve(responseCode); } get requestResult() { @@ -140,7 +142,7 @@ export class RequestScheduler { request.methodName ].apply(this._hsApi, request.args); // so the request can be aborted - request.setRequestResult(requestResult); + await request.setRequestResult(requestResult); return; } catch (err) { if (