You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-07-31 15:24:23 +03:00
Improve types around login, registration, UIA and identity servers (#3537)
This commit is contained in:
committed by
GitHub
parent
89cabc4912
commit
1c1ac137d3
@ -94,7 +94,6 @@ describe("InteractiveAuth", () => {
|
|||||||
authData: {
|
authData: {
|
||||||
session: "sessionId",
|
session: "sessionId",
|
||||||
flows: [{ stages: [AuthType.Password] }],
|
flows: [{ stages: [AuthType.Password] }],
|
||||||
errcode: "MockError0",
|
|
||||||
params: {
|
params: {
|
||||||
[AuthType.Password]: { param: "aa" },
|
[AuthType.Password]: { param: "aa" },
|
||||||
},
|
},
|
||||||
|
@ -15,6 +15,7 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { UnstableValue } from "../NamespacedValue";
|
import { UnstableValue } from "../NamespacedValue";
|
||||||
|
import { IClientWellKnown } from "../client";
|
||||||
|
|
||||||
// disable lint because these are wire responses
|
// disable lint because these are wire responses
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
@ -79,19 +80,6 @@ export interface IIdentityProvider {
|
|||||||
brand?: IdentityProviderBrand | string;
|
brand?: IdentityProviderBrand | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Parameters to login request as per https://spec.matrix.org/v1.3/client-server-api/#login
|
|
||||||
*/
|
|
||||||
/* eslint-disable camelcase */
|
|
||||||
export interface ILoginParams {
|
|
||||||
identifier?: object;
|
|
||||||
password?: string;
|
|
||||||
token?: string;
|
|
||||||
device_id?: string;
|
|
||||||
initial_device_display_name?: string;
|
|
||||||
}
|
|
||||||
/* eslint-enable camelcase */
|
|
||||||
|
|
||||||
export enum SSOAction {
|
export enum SSOAction {
|
||||||
/** The user intends to login to an existing account */
|
/** The user intends to login to an existing account */
|
||||||
LOGIN = "login",
|
LOGIN = "login",
|
||||||
@ -100,6 +88,160 @@ export enum SSOAction {
|
|||||||
REGISTER = "register",
|
REGISTER = "register",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A client can identify a user using their Matrix ID.
|
||||||
|
* This can either be the fully qualified Matrix user ID, or just the localpart of the user ID.
|
||||||
|
* @see https://spec.matrix.org/v1.7/client-server-api/#matrix-user-id
|
||||||
|
*/
|
||||||
|
type UserLoginIdentifier = {
|
||||||
|
type: "m.id.user";
|
||||||
|
user: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A client can identify a user using a 3PID associated with the user’s account on the homeserver,
|
||||||
|
* where the 3PID was previously associated using the /account/3pid API.
|
||||||
|
* See the 3PID Types Appendix for a list of Third-party ID media.
|
||||||
|
* @see https://spec.matrix.org/v1.7/client-server-api/#third-party-id
|
||||||
|
*/
|
||||||
|
type ThirdPartyLoginIdentifier = {
|
||||||
|
type: "m.id.thirdparty";
|
||||||
|
medium: string;
|
||||||
|
address: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A client can identify a user using a phone number associated with the user’s account,
|
||||||
|
* where the phone number was previously associated using the /account/3pid API.
|
||||||
|
* The phone number can be passed in as entered by the user; the homeserver will be responsible for canonicalising it.
|
||||||
|
* If the client wishes to canonicalise the phone number,
|
||||||
|
* then it can use the m.id.thirdparty identifier type with a medium of msisdn instead.
|
||||||
|
*
|
||||||
|
* The country is the two-letter uppercase ISO-3166-1 alpha-2 country code that the number in phone should be parsed as if it were dialled from.
|
||||||
|
*
|
||||||
|
* @see https://spec.matrix.org/v1.7/client-server-api/#phone-number
|
||||||
|
*/
|
||||||
|
type PhoneLoginIdentifier = {
|
||||||
|
type: "m.id.phone";
|
||||||
|
country: string;
|
||||||
|
phone: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SpecUserIdentifier = UserLoginIdentifier | ThirdPartyLoginIdentifier | PhoneLoginIdentifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* User Identifiers usable for login & user-interactive authentication.
|
||||||
|
*
|
||||||
|
* Extensibly allows more than Matrix specified identifiers.
|
||||||
|
*/
|
||||||
|
export type UserIdentifier =
|
||||||
|
| SpecUserIdentifier
|
||||||
|
| { type: Exclude<string, SpecUserIdentifier["type"]>; [key: string]: any };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Request body for POST /login request
|
||||||
|
* @see https://spec.matrix.org/v1.7/client-server-api/#post_matrixclientv3login
|
||||||
|
*/
|
||||||
|
export interface LoginRequest {
|
||||||
|
/**
|
||||||
|
* The login type being used.
|
||||||
|
*/
|
||||||
|
type: "m.login.password" | "m.login.token" | string;
|
||||||
|
/**
|
||||||
|
* Third-party identifier for the user.
|
||||||
|
* @deprecated in favour of `identifier`.
|
||||||
|
*/
|
||||||
|
address?: string;
|
||||||
|
/**
|
||||||
|
* ID of the client device.
|
||||||
|
* If this does not correspond to a known client device, a new device will be created.
|
||||||
|
* The given device ID must not be the same as a cross-signing key ID.
|
||||||
|
* The server will auto-generate a device_id if this is not specified.
|
||||||
|
*/
|
||||||
|
device_id?: string;
|
||||||
|
/**
|
||||||
|
* Identification information for a user
|
||||||
|
*/
|
||||||
|
identifier?: UserIdentifier;
|
||||||
|
/**
|
||||||
|
* A display name to assign to the newly-created device.
|
||||||
|
* Ignored if device_id corresponds to a known device.
|
||||||
|
*/
|
||||||
|
initial_device_display_name?: string;
|
||||||
|
/**
|
||||||
|
* When logging in using a third-party identifier, the medium of the identifier.
|
||||||
|
* Must be `email`.
|
||||||
|
* @deprecated in favour of `identifier`.
|
||||||
|
*/
|
||||||
|
medium?: "email";
|
||||||
|
/**
|
||||||
|
* Required when type is `m.login.password`. The user’s password.
|
||||||
|
*/
|
||||||
|
password?: string;
|
||||||
|
/**
|
||||||
|
* If true, the client supports refresh tokens.
|
||||||
|
*/
|
||||||
|
refresh_token?: boolean;
|
||||||
|
/**
|
||||||
|
* Required when type is `m.login.token`. Part of Token-based login.
|
||||||
|
*/
|
||||||
|
token?: string;
|
||||||
|
/**
|
||||||
|
* The fully qualified user ID or just local part of the user ID, to log in.
|
||||||
|
* @deprecated in favour of identifier.
|
||||||
|
*/
|
||||||
|
user?: string;
|
||||||
|
// Extensible
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Export for backwards compatibility
|
||||||
|
export type ILoginParams = LoginRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Response body for POST /login request
|
||||||
|
* @see https://spec.matrix.org/v1.7/client-server-api/#post_matrixclientv3login
|
||||||
|
*/
|
||||||
|
export interface LoginResponse {
|
||||||
|
/**
|
||||||
|
* An access token for the account.
|
||||||
|
* This access token can then be used to authorize other requests.
|
||||||
|
*/
|
||||||
|
access_token: string;
|
||||||
|
/**
|
||||||
|
* ID of the logged-in device.
|
||||||
|
* Will be the same as the corresponding parameter in the request, if one was specified.
|
||||||
|
*/
|
||||||
|
device_id: string;
|
||||||
|
/**
|
||||||
|
* The fully-qualified Matrix ID for the account.
|
||||||
|
*/
|
||||||
|
user_id: string;
|
||||||
|
/**
|
||||||
|
* The lifetime of the access token, in milliseconds.
|
||||||
|
* Once the access token has expired a new access token can be obtained by using the provided refresh token.
|
||||||
|
* If no refresh token is provided, the client will need to re-log in to obtain a new access token.
|
||||||
|
* If not given, the client can assume that the access token will not expire.
|
||||||
|
*/
|
||||||
|
expires_in_ms?: number;
|
||||||
|
/**
|
||||||
|
* A refresh token for the account.
|
||||||
|
* This token can be used to obtain a new access token when it expires by calling the /refresh endpoint.
|
||||||
|
*/
|
||||||
|
refresh_token?: string;
|
||||||
|
/**
|
||||||
|
* Optional client configuration provided by the server.
|
||||||
|
* If present, clients SHOULD use the provided object to reconfigure themselves, optionally validating the URLs within.
|
||||||
|
* This object takes the same form as the one returned from .well-known autodiscovery.
|
||||||
|
*/
|
||||||
|
well_known?: IClientWellKnown;
|
||||||
|
/**
|
||||||
|
* The server_name of the homeserver on which the account has been registered.
|
||||||
|
* @deprecated Clients should extract the server_name from user_id (by splitting at the first colon) if they require it.
|
||||||
|
*/
|
||||||
|
home_server?: string;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The result of a successful [MSC3882](https://github.com/matrix-org/matrix-spec-proposals/pull/3882)
|
* The result of a successful [MSC3882](https://github.com/matrix-org/matrix-spec-proposals/pull/3882)
|
||||||
* `m.login.token` issuance request.
|
* `m.login.token` issuance request.
|
||||||
|
116
src/@types/registration.ts
Normal file
116
src/@types/registration.ts
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 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 { AuthDict } from "../interactive-auth";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The request body of a call to `POST /_matrix/client/v3/register`.
|
||||||
|
*
|
||||||
|
* @see https://spec.matrix.org/v1.7/client-server-api/#post_matrixclientv3register
|
||||||
|
*/
|
||||||
|
export interface RegisterRequest {
|
||||||
|
/**
|
||||||
|
* Additional authentication information for the user-interactive authentication API.
|
||||||
|
* Note that this information is not used to define how the registered user should be authenticated,
|
||||||
|
* but is instead used to authenticate the register call itself.
|
||||||
|
*/
|
||||||
|
auth?: AuthDict;
|
||||||
|
/**
|
||||||
|
* The basis for the localpart of the desired Matrix ID.
|
||||||
|
* If omitted, the homeserver MUST generate a Matrix ID local part.
|
||||||
|
*/
|
||||||
|
username?: string;
|
||||||
|
/**
|
||||||
|
* The desired password for the account.
|
||||||
|
*/
|
||||||
|
password?: string;
|
||||||
|
/**
|
||||||
|
* If true, the client supports refresh tokens.
|
||||||
|
*/
|
||||||
|
refresh_token?: boolean;
|
||||||
|
/**
|
||||||
|
* If true, an access_token and device_id should not be returned from this call, therefore preventing an automatic login.
|
||||||
|
* Defaults to false.
|
||||||
|
*/
|
||||||
|
inhibit_login?: boolean;
|
||||||
|
/**
|
||||||
|
* A display name to assign to the newly-created device.
|
||||||
|
* Ignored if device_id corresponds to a known device.
|
||||||
|
*/
|
||||||
|
initial_device_display_name?: string;
|
||||||
|
/**
|
||||||
|
* @deprecated missing in the spec
|
||||||
|
*/
|
||||||
|
guest_access_token?: string;
|
||||||
|
/**
|
||||||
|
* @deprecated missing in the spec
|
||||||
|
*/
|
||||||
|
x_show_msisdn?: boolean;
|
||||||
|
/**
|
||||||
|
* @deprecated missing in the spec
|
||||||
|
*/
|
||||||
|
bind_msisdn?: boolean;
|
||||||
|
/**
|
||||||
|
* @deprecated missing in the spec
|
||||||
|
*/
|
||||||
|
bind_email?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The result of a successful call to `POST /_matrix/client/v3/register`.
|
||||||
|
*
|
||||||
|
* @see https://spec.matrix.org/v1.7/client-server-api/#post_matrixclientv3register
|
||||||
|
*/
|
||||||
|
export interface RegisterResponse {
|
||||||
|
/**
|
||||||
|
* The fully-qualified Matrix user ID (MXID) that has been registered.
|
||||||
|
*/
|
||||||
|
user_id: string;
|
||||||
|
/**
|
||||||
|
* An access token for the account.
|
||||||
|
* This access token can then be used to authorize other requests.
|
||||||
|
* Required if the inhibit_login option is false.
|
||||||
|
*/
|
||||||
|
access_token?: string;
|
||||||
|
/**
|
||||||
|
* ID of the registered device.
|
||||||
|
* Will be the same as the corresponding parameter in the request, if one was specified.
|
||||||
|
* Required if the inhibit_login option is false.
|
||||||
|
*/
|
||||||
|
device_id?: string;
|
||||||
|
/**
|
||||||
|
* The lifetime of the access token, in milliseconds.
|
||||||
|
* Once the access token has expired a new access token can be obtained by using the provided refresh token.
|
||||||
|
* If no refresh token is provided, the client will need to re-log in to obtain a new access token.
|
||||||
|
* If not given, the client can assume that the access token will not expire.
|
||||||
|
*
|
||||||
|
* Omitted if the inhibit_login option is true.
|
||||||
|
*/
|
||||||
|
expires_in_ms?: number;
|
||||||
|
/**
|
||||||
|
* A refresh token for the account.
|
||||||
|
* This token can be used to obtain a new access token when it expires by calling the /refresh endpoint.
|
||||||
|
*
|
||||||
|
* Omitted if the inhibit_login option is true.
|
||||||
|
*/
|
||||||
|
refresh_token?: string;
|
||||||
|
/**
|
||||||
|
* The server_name of the homeserver on which the account has been registered.
|
||||||
|
*
|
||||||
|
* @deprecated Clients should extract the server_name from user_id (by splitting at the first colon) if they require it.
|
||||||
|
*/
|
||||||
|
home_server?: string;
|
||||||
|
}
|
124
src/client.ts
124
src/client.ts
@ -101,7 +101,7 @@ import {
|
|||||||
import { IIdentityServerProvider } from "./@types/IIdentityServerProvider";
|
import { IIdentityServerProvider } from "./@types/IIdentityServerProvider";
|
||||||
import { MatrixScheduler } from "./scheduler";
|
import { MatrixScheduler } from "./scheduler";
|
||||||
import { BeaconEvent, BeaconEventHandlerMap } from "./models/beacon";
|
import { BeaconEvent, BeaconEventHandlerMap } from "./models/beacon";
|
||||||
import { IAuthData, IAuthDict } from "./interactive-auth";
|
import { AuthDict } from "./interactive-auth";
|
||||||
import { IMinimalEvent, IRoomEvent, IStateEvent } from "./sync-accumulator";
|
import { IMinimalEvent, IRoomEvent, IStateEvent } from "./sync-accumulator";
|
||||||
import { CrossSigningKey, ICreateSecretStorageOpts, IEncryptedEventInfo, IRecoveryKey } from "./crypto/api";
|
import { CrossSigningKey, ICreateSecretStorageOpts, IEncryptedEventInfo, IRecoveryKey } from "./crypto/api";
|
||||||
import { EventTimelineSet } from "./models/event-timeline-set";
|
import { EventTimelineSet } from "./models/event-timeline-set";
|
||||||
@ -178,7 +178,14 @@ import { IThreepid } from "./@types/threepids";
|
|||||||
import { CryptoStore, OutgoingRoomKeyRequest } from "./crypto/store/base";
|
import { CryptoStore, OutgoingRoomKeyRequest } from "./crypto/store/base";
|
||||||
import { GroupCall, IGroupCallDataChannelOptions, GroupCallIntent, GroupCallType } from "./webrtc/groupCall";
|
import { GroupCall, IGroupCallDataChannelOptions, GroupCallIntent, GroupCallType } from "./webrtc/groupCall";
|
||||||
import { MediaHandler } from "./webrtc/mediaHandler";
|
import { MediaHandler } from "./webrtc/mediaHandler";
|
||||||
import { LoginTokenPostResponse, ILoginFlowsResponse, IRefreshTokenResponse, SSOAction } from "./@types/auth";
|
import {
|
||||||
|
LoginTokenPostResponse,
|
||||||
|
ILoginFlowsResponse,
|
||||||
|
IRefreshTokenResponse,
|
||||||
|
SSOAction,
|
||||||
|
LoginResponse,
|
||||||
|
LoginRequest,
|
||||||
|
} from "./@types/auth";
|
||||||
import { TypedEventEmitter } from "./models/typed-event-emitter";
|
import { TypedEventEmitter } from "./models/typed-event-emitter";
|
||||||
import { MAIN_ROOM_TIMELINE, ReceiptType } from "./@types/read_receipts";
|
import { MAIN_ROOM_TIMELINE, ReceiptType } from "./@types/read_receipts";
|
||||||
import { MSC3575SlidingSyncRequest, MSC3575SlidingSyncResponse, SlidingSync } from "./sliding-sync";
|
import { MSC3575SlidingSyncRequest, MSC3575SlidingSyncResponse, SlidingSync } from "./sliding-sync";
|
||||||
@ -209,6 +216,7 @@ import {
|
|||||||
ServerSideSecretStorage,
|
ServerSideSecretStorage,
|
||||||
ServerSideSecretStorageImpl,
|
ServerSideSecretStorageImpl,
|
||||||
} from "./secret-storage";
|
} from "./secret-storage";
|
||||||
|
import { RegisterRequest, RegisterResponse } from "./@types/registration";
|
||||||
|
|
||||||
export type Store = IStore;
|
export type Store = IStore;
|
||||||
|
|
||||||
@ -717,18 +725,8 @@ interface IJoinedMembersResponse {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IRegisterRequestParams {
|
// Re-export for backwards compatibility
|
||||||
auth?: IAuthDict;
|
export type IRegisterRequestParams = RegisterRequest;
|
||||||
username?: string;
|
|
||||||
password?: string;
|
|
||||||
refresh_token?: boolean;
|
|
||||||
guest_access_token?: string;
|
|
||||||
x_show_msisdn?: boolean;
|
|
||||||
bind_msisdn?: boolean;
|
|
||||||
bind_email?: boolean;
|
|
||||||
inhibit_login?: boolean;
|
|
||||||
initial_device_display_name?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IPublicRoomsChunkRoom {
|
export interface IPublicRoomsChunkRoom {
|
||||||
room_id: string;
|
room_id: string;
|
||||||
@ -7653,7 +7651,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
* @param bindThreepids - Set key 'email' to true to bind any email
|
* @param bindThreepids - Set key 'email' to true to bind any email
|
||||||
* threepid uses during registration in the identity server. Set 'msisdn' to
|
* threepid uses during registration in the identity server. Set 'msisdn' to
|
||||||
* true to bind msisdn.
|
* true to bind msisdn.
|
||||||
* @returns Promise which resolves: TODO
|
* @returns Promise which resolves to a RegisterResponse object
|
||||||
* @returns Rejects: with an error response.
|
* @returns Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
public register(
|
public register(
|
||||||
@ -7664,7 +7662,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
bindThreepids?: boolean | null | { email?: boolean; msisdn?: boolean },
|
bindThreepids?: boolean | null | { email?: boolean; msisdn?: boolean },
|
||||||
guestAccessToken?: string,
|
guestAccessToken?: string,
|
||||||
inhibitLogin?: boolean,
|
inhibitLogin?: boolean,
|
||||||
): Promise<IAuthData> {
|
): Promise<RegisterResponse> {
|
||||||
// backwards compat
|
// backwards compat
|
||||||
if (bindThreepids === true) {
|
if (bindThreepids === true) {
|
||||||
bindThreepids = { email: true };
|
bindThreepids = { email: true };
|
||||||
@ -7675,7 +7673,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
auth.session = sessionId;
|
auth.session = sessionId;
|
||||||
}
|
}
|
||||||
|
|
||||||
const params: IRegisterRequestParams = {
|
const params: RegisterRequest = {
|
||||||
auth: auth,
|
auth: auth,
|
||||||
refresh_token: true, // always ask for a refresh token - does nothing if unsupported
|
refresh_token: true, // always ask for a refresh token - does nothing if unsupported
|
||||||
};
|
};
|
||||||
@ -7731,8 +7729,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
* `{ user_id, device_id, access_token, home_server }`
|
* `{ user_id, device_id, access_token, home_server }`
|
||||||
* @returns Rejects: with an error response.
|
* @returns Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
public registerGuest({ body }: { body?: any } = {}): Promise<any> {
|
public registerGuest({ body }: { body?: RegisterRequest } = {}): Promise<RegisterResponse> {
|
||||||
// TODO: Types
|
|
||||||
return this.registerRequest(body || {}, "guest");
|
return this.registerRequest(body || {}, "guest");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7742,7 +7739,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
* @returns Promise which resolves: to the /register response
|
* @returns Promise which resolves: to the /register response
|
||||||
* @returns Rejects: with an error response.
|
* @returns Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
public registerRequest(data: IRegisterRequestParams, kind?: string): Promise<IAuthData> {
|
public registerRequest(data: RegisterRequest, kind?: string): Promise<RegisterResponse> {
|
||||||
const params: { kind?: string } = {};
|
const params: { kind?: string } = {};
|
||||||
if (kind) {
|
if (kind) {
|
||||||
params.kind = kind;
|
params.kind = kind;
|
||||||
@ -7795,23 +7792,15 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns Promise which resolves: TODO
|
* @returns Promise which resolves to a LoginResponse object
|
||||||
* @returns Rejects: with an error response.
|
* @returns Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
public login(loginType: string, data: any): Promise<any> {
|
public login(loginType: LoginRequest["type"], data: Omit<LoginRequest, "type">): Promise<LoginResponse> {
|
||||||
// TODO: Types
|
|
||||||
const loginData = {
|
|
||||||
type: loginType,
|
|
||||||
};
|
|
||||||
|
|
||||||
// merge data into loginData
|
|
||||||
Object.assign(loginData, data);
|
|
||||||
|
|
||||||
return this.http
|
return this.http
|
||||||
.authedRequest<{
|
.authedRequest<LoginResponse>(Method.Post, "/login", undefined, {
|
||||||
access_token?: string;
|
...data,
|
||||||
user_id?: string;
|
type: loginType,
|
||||||
}>(Method.Post, "/login", undefined, loginData)
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.access_token && response.user_id) {
|
if (response.access_token && response.user_id) {
|
||||||
this.http.opts.accessToken = response.access_token;
|
this.http.opts.accessToken = response.access_token;
|
||||||
@ -7824,11 +7813,10 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns Promise which resolves: TODO
|
* @returns Promise which resolves to a LoginResponse object
|
||||||
* @returns Rejects: with an error response.
|
* @returns Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
public loginWithPassword(user: string, password: string): Promise<any> {
|
public loginWithPassword(user: string, password: string): Promise<LoginResponse> {
|
||||||
// TODO: Types
|
|
||||||
return this.login("m.login.password", {
|
return this.login("m.login.password", {
|
||||||
user: user,
|
user: user,
|
||||||
password: password,
|
password: password,
|
||||||
@ -7837,11 +7825,11 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param relayState - URL Callback after SAML2 Authentication
|
* @param relayState - URL Callback after SAML2 Authentication
|
||||||
* @returns Promise which resolves: TODO
|
* @returns Promise which resolves to a LoginResponse object
|
||||||
* @returns Rejects: with an error response.
|
* @returns Rejects: with an error response.
|
||||||
|
* @deprecated this isn't in the Matrix spec anymore
|
||||||
*/
|
*/
|
||||||
public loginWithSAML2(relayState: string): Promise<any> {
|
public loginWithSAML2(relayState: string): Promise<LoginResponse> {
|
||||||
// TODO: Types
|
|
||||||
return this.login("m.login.saml2", {
|
return this.login("m.login.saml2", {
|
||||||
relay_state: relayState,
|
relay_state: relayState,
|
||||||
});
|
});
|
||||||
@ -7881,11 +7869,10 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @param token - Login token previously received from homeserver
|
* @param token - Login token previously received from homeserver
|
||||||
* @returns Promise which resolves: TODO
|
* @returns Promise which resolves to a LoginResponse object
|
||||||
* @returns Rejects: with an error response.
|
* @returns Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
public loginWithToken(token: string): Promise<any> {
|
public loginWithToken(token: string): Promise<LoginResponse> {
|
||||||
// TODO: Types
|
|
||||||
return this.login("m.login.token", {
|
return this.login("m.login.token", {
|
||||||
token: token,
|
token: token,
|
||||||
});
|
});
|
||||||
@ -7929,7 +7916,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
* to false.
|
* to false.
|
||||||
* @returns Promise which resolves: On success, the empty object
|
* @returns Promise which resolves: On success, the empty object
|
||||||
*/
|
*/
|
||||||
public deactivateAccount(auth?: any, erase?: boolean): Promise<{}> {
|
public deactivateAccount(auth?: any, erase?: boolean): Promise<{ id_server_unbind_result: IdServerUnbindResult }> {
|
||||||
const body: any = {};
|
const body: any = {};
|
||||||
if (auth) {
|
if (auth) {
|
||||||
body.auth = auth;
|
body.auth = auth;
|
||||||
@ -7950,7 +7937,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
* @returns Promise which resolves: On success, the token response
|
* @returns Promise which resolves: On success, the token response
|
||||||
* or UIA auth data.
|
* or UIA auth data.
|
||||||
*/
|
*/
|
||||||
public async requestLoginToken(auth?: IAuthDict): Promise<UIAResponse<LoginTokenPostResponse>> {
|
public async requestLoginToken(auth?: AuthDict): Promise<UIAResponse<LoginTokenPostResponse>> {
|
||||||
// use capabilities to determine which revision of the MSC is being used
|
// use capabilities to determine which revision of the MSC is being used
|
||||||
const capabilities = await this.getCapabilities();
|
const capabilities = await this.getCapabilities();
|
||||||
// use r1 endpoint if capability is exposed otherwise use old r0 endpoint
|
// use r1 endpoint if capability is exposed otherwise use old r0 endpoint
|
||||||
@ -8590,7 +8577,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
* @returns Promise which resolves: to an empty object `{}`
|
* @returns Promise which resolves: to an empty object `{}`
|
||||||
* @returns Rejects: with an error response.
|
* @returns Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
public setPassword(authDict: IAuthDict, newPassword: string, logoutDevices?: boolean): Promise<{}> {
|
public setPassword(authDict: AuthDict, newPassword: string, logoutDevices?: boolean): Promise<{}> {
|
||||||
const path = "/account/password";
|
const path = "/account/password";
|
||||||
const data = {
|
const data = {
|
||||||
auth: authDict,
|
auth: authDict,
|
||||||
@ -8648,7 +8635,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
* @returns Promise which resolves: result object
|
* @returns Promise which resolves: result object
|
||||||
* @returns Rejects: with an error response.
|
* @returns Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
public deleteDevice(deviceId: string, auth?: IAuthDict): Promise<IAuthData | {}> {
|
public deleteDevice(deviceId: string, auth?: AuthDict): Promise<{}> {
|
||||||
const path = utils.encodeUri("/devices/$device_id", {
|
const path = utils.encodeUri("/devices/$device_id", {
|
||||||
$device_id: deviceId,
|
$device_id: deviceId,
|
||||||
});
|
});
|
||||||
@ -8670,7 +8657,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
* @returns Promise which resolves: result object
|
* @returns Promise which resolves: result object
|
||||||
* @returns Rejects: with an error response.
|
* @returns Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
public deleteMultipleDevices(devices: string[], auth?: IAuthDict): Promise<IAuthData | {}> {
|
public deleteMultipleDevices(devices: string[], auth?: AuthDict): Promise<{}> {
|
||||||
const body: any = { devices };
|
const body: any = { devices };
|
||||||
|
|
||||||
if (auth) {
|
if (auth) {
|
||||||
@ -8955,7 +8942,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
return this.http.authedRequest(Method.Get, "/keys/changes", qps);
|
return this.http.authedRequest(Method.Get, "/keys/changes", qps);
|
||||||
}
|
}
|
||||||
|
|
||||||
public uploadDeviceSigningKeys(auth?: IAuthDict, keys?: CrossSigningKeys): Promise<{}> {
|
public uploadDeviceSigningKeys(auth?: AuthDict, keys?: CrossSigningKeys): Promise<{}> {
|
||||||
// API returns empty object
|
// API returns empty object
|
||||||
const data = Object.assign({}, keys);
|
const data = Object.assign({}, keys);
|
||||||
if (auth) Object.assign(data, { auth });
|
if (auth) Object.assign(data, { auth });
|
||||||
@ -9168,8 +9155,17 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
* @param identityAccessToken - The access token for the identity server.
|
* @param identityAccessToken - The access token for the identity server.
|
||||||
* @returns The hashing information for the identity server.
|
* @returns The hashing information for the identity server.
|
||||||
*/
|
*/
|
||||||
public getIdentityHashDetails(identityAccessToken: string): Promise<any> {
|
public getIdentityHashDetails(identityAccessToken: string): Promise<{
|
||||||
// TODO: Types
|
/**
|
||||||
|
* The algorithms the server supports. Must contain at least sha256.
|
||||||
|
*/
|
||||||
|
algorithms: string[];
|
||||||
|
/**
|
||||||
|
* The pepper the client MUST use in hashing identifiers,
|
||||||
|
* and MUST supply to the /lookup endpoint when performing lookups.
|
||||||
|
*/
|
||||||
|
lookup_pepper: string;
|
||||||
|
}> {
|
||||||
return this.http.idServerRequest(
|
return this.http.idServerRequest(
|
||||||
Method.Get,
|
Method.Get,
|
||||||
"/hash_details",
|
"/hash_details",
|
||||||
@ -9277,8 +9273,18 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
* exists
|
* exists
|
||||||
* @returns Rejects: with an error response.
|
* @returns Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
public async lookupThreePid(medium: string, address: string, identityAccessToken: string): Promise<any> {
|
public async lookupThreePid(
|
||||||
// TODO: Types
|
medium: string,
|
||||||
|
address: string,
|
||||||
|
identityAccessToken: string,
|
||||||
|
): Promise<
|
||||||
|
| {
|
||||||
|
address: string;
|
||||||
|
medium: string;
|
||||||
|
mxid: string;
|
||||||
|
}
|
||||||
|
| {}
|
||||||
|
> {
|
||||||
// Note: we're using the V2 API by calling this function, but our
|
// Note: we're using the V2 API by calling this function, but our
|
||||||
// function contract requires a V1 response. We therefore have to
|
// function contract requires a V1 response. We therefore have to
|
||||||
// convert it manually.
|
// convert it manually.
|
||||||
@ -9314,8 +9320,12 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
* @returns Promise which resolves: Lookup results from IS.
|
* @returns Promise which resolves: Lookup results from IS.
|
||||||
* @returns Rejects: with an error response.
|
* @returns Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
public async bulkLookupThreePids(query: [string, string][], identityAccessToken: string): Promise<any> {
|
public async bulkLookupThreePids(
|
||||||
// TODO: Types
|
query: [string, string][],
|
||||||
|
identityAccessToken: string,
|
||||||
|
): Promise<{
|
||||||
|
threepids: [medium: string, address: string, mxid: string][];
|
||||||
|
}> {
|
||||||
// Note: we're using the V2 API by calling this function, but our
|
// Note: we're using the V2 API by calling this function, but our
|
||||||
// function contract requires a V1 response. We therefore have to
|
// function contract requires a V1 response. We therefore have to
|
||||||
// convert it manually.
|
// convert it manually.
|
||||||
@ -9353,8 +9363,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
* @returns Promise which resolves: an object with account info.
|
* @returns Promise which resolves: an object with account info.
|
||||||
* @returns Rejects: with an error response.
|
* @returns Rejects: with an error response.
|
||||||
*/
|
*/
|
||||||
public getIdentityAccount(identityAccessToken: string): Promise<any> {
|
public getIdentityAccount(identityAccessToken: string): Promise<{ user_id: string }> {
|
||||||
// TODO: Types
|
|
||||||
return this.http.idServerRequest(Method.Get, "/account", undefined, IdentityPrefix.V2, identityAccessToken);
|
return this.http.idServerRequest(Method.Get, "/account", undefined, IdentityPrefix.V2, identityAccessToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9447,7 +9456,6 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
* @returns Promise which resolves to the result object
|
* @returns Promise which resolves to the result object
|
||||||
*/
|
*/
|
||||||
public getThirdpartyUser(protocol: string, params: any): Promise<IThirdPartyUser[]> {
|
public getThirdpartyUser(protocol: string, params: any): Promise<IThirdPartyUser[]> {
|
||||||
// TODO: Types
|
|
||||||
const path = utils.encodeUri("/thirdparty/user/$protocol", {
|
const path = utils.encodeUri("/thirdparty/user/$protocol", {
|
||||||
$protocol: protocol,
|
$protocol: protocol,
|
||||||
});
|
});
|
||||||
|
@ -21,6 +21,7 @@ import { MatrixClient } from "./client";
|
|||||||
import { defer, IDeferred } from "./utils";
|
import { defer, IDeferred } from "./utils";
|
||||||
import { MatrixError } from "./http-api";
|
import { MatrixError } from "./http-api";
|
||||||
import { UIAResponse } from "./@types/uia";
|
import { UIAResponse } from "./@types/uia";
|
||||||
|
import { UserIdentifier } from "./@types/auth";
|
||||||
|
|
||||||
const EMAIL_STAGE_TYPE = "m.login.email.identity";
|
const EMAIL_STAGE_TYPE = "m.login.email.identity";
|
||||||
const MSISDN_STAGE_TYPE = "m.login.msisdn";
|
const MSISDN_STAGE_TYPE = "m.login.msisdn";
|
||||||
@ -51,22 +52,25 @@ export interface IStageStatus {
|
|||||||
* @see https://spec.matrix.org/v1.6/client-server-api/#user-interactive-api-in-the-rest-api
|
* @see https://spec.matrix.org/v1.6/client-server-api/#user-interactive-api-in-the-rest-api
|
||||||
*/
|
*/
|
||||||
export interface IAuthData {
|
export interface IAuthData {
|
||||||
// XXX: many of the fields here (`type`, `available_flows`, `required_stages`, etc) look like they
|
/**
|
||||||
// shouldn't be here. They aren't in the spec and it's unclear what they are supposed to do. Be wary of using them.
|
* This is a session identifier that the client must pass back to the home server,
|
||||||
|
* if one is provided, in subsequent attempts to authenticate in the same API call.
|
||||||
|
*/
|
||||||
session?: string;
|
session?: string;
|
||||||
type?: string;
|
/**
|
||||||
|
* A list of the stages the client has completed successfully
|
||||||
|
*/
|
||||||
completed?: string[];
|
completed?: string[];
|
||||||
|
/**
|
||||||
|
* A list of the login flows supported by the server for this API.
|
||||||
|
*/
|
||||||
flows?: UIAFlow[];
|
flows?: UIAFlow[];
|
||||||
available_flows?: UIAFlow[];
|
/**
|
||||||
stages?: string[];
|
* Contains any information that the client will need to know in order to use a given type of authentication.
|
||||||
required_stages?: AuthType[];
|
* For each login type presented, that type may be present as a key in this dictionary.
|
||||||
|
* For example, the public part of an OAuth client ID could be given here.
|
||||||
|
*/
|
||||||
params?: Record<string, Record<string, any>>;
|
params?: Record<string, Record<string, any>>;
|
||||||
data?: Record<string, string>;
|
|
||||||
errcode?: string;
|
|
||||||
error?: string;
|
|
||||||
user_id?: string;
|
|
||||||
device_id?: string;
|
|
||||||
access_token?: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AuthType {
|
export enum AuthType {
|
||||||
@ -85,30 +89,62 @@ export enum AuthType {
|
|||||||
UnstableRegistrationToken = "org.matrix.msc3231.login.registration_token",
|
UnstableRegistrationToken = "org.matrix.msc3231.login.registration_token",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://spec.matrix.org/v1.7/client-server-api/#password-based
|
||||||
|
*/
|
||||||
|
type PasswordDict = {
|
||||||
|
type: AuthType.Password;
|
||||||
|
identifier: UserIdentifier;
|
||||||
|
password: string;
|
||||||
|
session: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://spec.matrix.org/v1.7/client-server-api/#google-recaptcha
|
||||||
|
*/
|
||||||
|
type RecaptchaDict = {
|
||||||
|
type: AuthType.Recaptcha;
|
||||||
|
response: string;
|
||||||
|
session: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface ThreepidCreds {
|
||||||
|
sid: string;
|
||||||
|
client_secret: string;
|
||||||
|
id_server: string;
|
||||||
|
id_access_token: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://spec.matrix.org/v1.7/client-server-api/#email-based-identity--homeserver
|
||||||
|
*/
|
||||||
|
type EmailIdentityDict = {
|
||||||
|
type: AuthType.Email;
|
||||||
|
threepid_creds: ThreepidCreds;
|
||||||
|
/**
|
||||||
|
* @deprecated in favour of `threepid_creds` - kept for backwards compatibility
|
||||||
|
*/
|
||||||
|
threepidCreds?: ThreepidCreds;
|
||||||
|
session: string;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The parameters which are submitted as the `auth` dict in a UIA request
|
* The parameters which are submitted as the `auth` dict in a UIA request
|
||||||
*
|
*
|
||||||
* @see https://spec.matrix.org/v1.6/client-server-api/#authentication-types
|
* @see https://spec.matrix.org/v1.6/client-server-api/#authentication-types
|
||||||
*/
|
*/
|
||||||
export interface IAuthDict {
|
export type AuthDict =
|
||||||
// [key: string]: any;
|
| PasswordDict
|
||||||
type?: string;
|
| RecaptchaDict
|
||||||
session?: string;
|
| EmailIdentityDict
|
||||||
// TODO: Remove `user` once servers support proper UIA
|
| { type: Exclude<string, AuthType>; [key: string]: any }
|
||||||
// See https://github.com/vector-im/element-web/issues/10312
|
| {};
|
||||||
user?: string;
|
|
||||||
identifier?: any;
|
/**
|
||||||
password?: string;
|
* Backwards compatible export
|
||||||
response?: string;
|
* @deprecated in favour of AuthDict
|
||||||
// TODO: Remove `threepid_creds` once servers support proper UIA
|
*/
|
||||||
// See https://github.com/vector-im/element-web/issues/10312
|
export type IAuthDict = AuthDict;
|
||||||
// See https://github.com/matrix-org/matrix-doc/issues/2220
|
|
||||||
// eslint-disable-next-line camelcase
|
|
||||||
threepid_creds?: any;
|
|
||||||
threepidCreds?: any;
|
|
||||||
// For m.login.registration_token type
|
|
||||||
token?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class NoAuthFlowFoundError extends Error {
|
export class NoAuthFlowFoundError extends Error {
|
||||||
public name = "NoAuthFlowFoundError";
|
public name = "NoAuthFlowFoundError";
|
||||||
@ -129,7 +165,7 @@ export class NoAuthFlowFoundError extends Error {
|
|||||||
*/
|
*/
|
||||||
export type UIAuthCallback<T> = (makeRequest: (authData: IAuthDict) => Promise<UIAResponse<T>>) => Promise<T>;
|
export type UIAuthCallback<T> = (makeRequest: (authData: IAuthDict) => Promise<UIAResponse<T>>) => Promise<T>;
|
||||||
|
|
||||||
interface IOpts {
|
interface IOpts<T> {
|
||||||
/**
|
/**
|
||||||
* A matrix client to use for the auth process
|
* A matrix client to use for the auth process
|
||||||
*/
|
*/
|
||||||
@ -170,7 +206,7 @@ interface IOpts {
|
|||||||
* The busyChanged callback should be used instead of the background flag.
|
* The busyChanged callback should be used instead of the background flag.
|
||||||
* Should return a promise which resolves to the successful response or rejects with a MatrixError.
|
* Should return a promise which resolves to the successful response or rejects with a MatrixError.
|
||||||
*/
|
*/
|
||||||
doRequest(auth: IAuthDict | null, background: boolean): Promise<IAuthData>;
|
doRequest(auth: AuthDict | null, background: boolean): Promise<T>;
|
||||||
/**
|
/**
|
||||||
* Called when the status of the UI auth changes,
|
* Called when the status of the UI auth changes,
|
||||||
* ie. when the state of an auth stage changes of when the auth flow moves to a new stage.
|
* ie. when the state of an auth stage changes of when the auth flow moves to a new stage.
|
||||||
@ -215,21 +251,23 @@ interface IOpts {
|
|||||||
* submitAuthDict.
|
* submitAuthDict.
|
||||||
*
|
*
|
||||||
* @param opts - options object
|
* @param opts - options object
|
||||||
|
* @typeParam T - the return type of the request when it is successful
|
||||||
*/
|
*/
|
||||||
export class InteractiveAuth {
|
export class InteractiveAuth<T> {
|
||||||
private readonly matrixClient: MatrixClient;
|
private readonly matrixClient: MatrixClient;
|
||||||
private readonly inputs: IInputs;
|
private readonly inputs: IInputs;
|
||||||
private readonly clientSecret: string;
|
private readonly clientSecret: string;
|
||||||
private readonly requestCallback: IOpts["doRequest"];
|
private readonly requestCallback: IOpts<T>["doRequest"];
|
||||||
private readonly busyChangedCallback?: IOpts["busyChanged"];
|
private readonly busyChangedCallback?: IOpts<T>["busyChanged"];
|
||||||
private readonly stateUpdatedCallback: IOpts["stateUpdated"];
|
private readonly stateUpdatedCallback: IOpts<T>["stateUpdated"];
|
||||||
private readonly requestEmailTokenCallback: IOpts["requestEmailToken"];
|
private readonly requestEmailTokenCallback: IOpts<T>["requestEmailToken"];
|
||||||
private readonly supportedStages?: Set<string>;
|
private readonly supportedStages?: Set<string>;
|
||||||
|
|
||||||
|
// The current latest data received from the server during the user interactive auth flow.
|
||||||
private data: IAuthData;
|
private data: IAuthData;
|
||||||
private emailSid?: string;
|
private emailSid?: string;
|
||||||
private requestingEmailToken = false;
|
private requestingEmailToken = false;
|
||||||
private attemptAuthDeferred: IDeferred<IAuthData> | null = null;
|
private attemptAuthDeferred: IDeferred<T> | null = null;
|
||||||
private chosenFlow: UIAFlow | null = null;
|
private chosenFlow: UIAFlow | null = null;
|
||||||
private currentStage: string | null = null;
|
private currentStage: string | null = null;
|
||||||
|
|
||||||
@ -239,9 +277,9 @@ export class InteractiveAuth {
|
|||||||
// the promise the will resolve/reject when it completes
|
// the promise the will resolve/reject when it completes
|
||||||
private submitPromise: Promise<void> | null = null;
|
private submitPromise: Promise<void> | null = null;
|
||||||
|
|
||||||
public constructor(opts: IOpts) {
|
public constructor(opts: IOpts<T>) {
|
||||||
this.matrixClient = opts.matrixClient;
|
this.matrixClient = opts.matrixClient;
|
||||||
this.data = opts.authData || {};
|
this.data = opts.authData || { flows: [] };
|
||||||
this.requestCallback = opts.doRequest;
|
this.requestCallback = opts.doRequest;
|
||||||
this.busyChangedCallback = opts.busyChanged;
|
this.busyChangedCallback = opts.busyChanged;
|
||||||
// startAuthStage included for backwards compat
|
// startAuthStage included for backwards compat
|
||||||
@ -262,7 +300,7 @@ export class InteractiveAuth {
|
|||||||
* or rejects with the error on failure. Rejects with NoAuthFlowFoundError if
|
* or rejects with the error on failure. Rejects with NoAuthFlowFoundError if
|
||||||
* no suitable authentication flow can be found
|
* no suitable authentication flow can be found
|
||||||
*/
|
*/
|
||||||
public attemptAuth(): Promise<IAuthData> {
|
public async attemptAuth(): Promise<T> {
|
||||||
// This promise will be quite long-lived and will resolve when the
|
// This promise will be quite long-lived and will resolve when the
|
||||||
// request is authenticated and completes successfully.
|
// request is authenticated and completes successfully.
|
||||||
this.attemptAuthDeferred = defer();
|
this.attemptAuthDeferred = defer();
|
||||||
@ -270,10 +308,10 @@ export class InteractiveAuth {
|
|||||||
const promise = this.attemptAuthDeferred.promise;
|
const promise = this.attemptAuthDeferred.promise;
|
||||||
|
|
||||||
// if we have no flows, try a request to acquire the flows
|
// if we have no flows, try a request to acquire the flows
|
||||||
if (!this.data?.flows) {
|
if (!(this.data as IAuthData)?.flows?.length) {
|
||||||
this.busyChangedCallback?.(true);
|
this.busyChangedCallback?.(true);
|
||||||
// use the existing sessionId, if one is present.
|
// use the existing sessionId, if one is present.
|
||||||
const auth = this.data.session ? { session: this.data.session } : null;
|
const auth = (this.data as IAuthData).session ? { session: (this.data as IAuthData).session } : null;
|
||||||
this.doRequest(auth).finally(() => {
|
this.doRequest(auth).finally(() => {
|
||||||
this.busyChangedCallback?.(false);
|
this.busyChangedCallback?.(false);
|
||||||
});
|
});
|
||||||
@ -290,7 +328,7 @@ export class InteractiveAuth {
|
|||||||
* be resolved.
|
* be resolved.
|
||||||
*/
|
*/
|
||||||
public async poll(): Promise<void> {
|
public async poll(): Promise<void> {
|
||||||
if (!this.data.session) return;
|
if (!(this.data as IAuthData).session) return;
|
||||||
// likewise don't poll if there is no auth session in progress
|
// likewise don't poll if there is no auth session in progress
|
||||||
if (!this.attemptAuthDeferred) return;
|
if (!this.attemptAuthDeferred) return;
|
||||||
// if we currently have a request in flight, there's no point making
|
// if we currently have a request in flight, there's no point making
|
||||||
@ -330,7 +368,7 @@ export class InteractiveAuth {
|
|||||||
* @returns session id
|
* @returns session id
|
||||||
*/
|
*/
|
||||||
public getSessionId(): string | undefined {
|
public getSessionId(): string | undefined {
|
||||||
return this.data?.session;
|
return (this.data as IAuthData)?.session;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -350,7 +388,7 @@ export class InteractiveAuth {
|
|||||||
* @returns any parameters from the server for this stage
|
* @returns any parameters from the server for this stage
|
||||||
*/
|
*/
|
||||||
public getStageParams(loginType: string): Record<string, any> | undefined {
|
public getStageParams(loginType: string): Record<string, any> | undefined {
|
||||||
return this.data.params?.[loginType];
|
return (this.data as IAuthData)?.params?.[loginType];
|
||||||
}
|
}
|
||||||
|
|
||||||
public getChosenFlow(): UIAFlow | null {
|
public getChosenFlow(): UIAFlow | null {
|
||||||
@ -391,9 +429,9 @@ export class InteractiveAuth {
|
|||||||
|
|
||||||
// use the sessionid from the last request, if one is present.
|
// use the sessionid from the last request, if one is present.
|
||||||
let auth: IAuthDict;
|
let auth: IAuthDict;
|
||||||
if (this.data.session) {
|
if ((this.data as IAuthData)?.session) {
|
||||||
auth = {
|
auth = {
|
||||||
session: this.data.session,
|
session: (this.data as IAuthData).session,
|
||||||
};
|
};
|
||||||
Object.assign(auth, authData);
|
Object.assign(auth, authData);
|
||||||
} else {
|
} else {
|
||||||
@ -451,7 +489,7 @@ export class InteractiveAuth {
|
|||||||
this.inputs.emailAddress!,
|
this.inputs.emailAddress!,
|
||||||
this.clientSecret,
|
this.clientSecret,
|
||||||
this.emailAttempt++,
|
this.emailAttempt++,
|
||||||
this.data.session!,
|
(this.data as IAuthData).session!,
|
||||||
);
|
);
|
||||||
this.emailSid = requestTokenResult.sid;
|
this.emailSid = requestTokenResult.sid;
|
||||||
logger.trace("Email token request succeeded");
|
logger.trace("Email token request succeeded");
|
||||||
@ -480,10 +518,12 @@ export class InteractiveAuth {
|
|||||||
this.attemptAuthDeferred!.resolve(result);
|
this.attemptAuthDeferred!.resolve(result);
|
||||||
this.attemptAuthDeferred = null;
|
this.attemptAuthDeferred = null;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
const matrixError = error instanceof MatrixError ? error : null;
|
||||||
|
|
||||||
// sometimes UI auth errors don't come with flows
|
// sometimes UI auth errors don't come with flows
|
||||||
const errorFlows = (<MatrixError>error).data?.flows ?? null;
|
const errorFlows = matrixError?.data?.flows ?? null;
|
||||||
const haveFlows = this.data.flows || Boolean(errorFlows);
|
const haveFlows = (this.data as IAuthData)?.flows || Boolean(errorFlows);
|
||||||
if ((<MatrixError>error).httpStatus !== 401 || !(<MatrixError>error).data || !haveFlows) {
|
if (!matrixError || matrixError.httpStatus !== 401 || !matrixError.data || !haveFlows) {
|
||||||
// doesn't look like an interactive-auth failure.
|
// doesn't look like an interactive-auth failure.
|
||||||
if (!background) {
|
if (!background) {
|
||||||
this.attemptAuthDeferred?.reject(error);
|
this.attemptAuthDeferred?.reject(error);
|
||||||
@ -494,24 +534,22 @@ export class InteractiveAuth {
|
|||||||
logger.log("Background poll request failed doing UI auth: ignoring", error);
|
logger.log("Background poll request failed doing UI auth: ignoring", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!(<MatrixError>error).data) {
|
if (matrixError && !matrixError.data) {
|
||||||
(<MatrixError>error).data = {};
|
matrixError.data = {};
|
||||||
}
|
}
|
||||||
// if the error didn't come with flows, completed flows or session ID,
|
// if the error didn't come with flows, completed flows or session ID,
|
||||||
// copy over the ones we have. Synapse sometimes sends responses without
|
// copy over the ones we have. Synapse sometimes sends responses without
|
||||||
// any UI auth data (eg. when polling for email validation, if the email
|
// any UI auth data (eg. when polling for email validation, if the email
|
||||||
// has not yet been validated). This appears to be a Synapse bug, which
|
// has not yet been validated). This appears to be a Synapse bug, which
|
||||||
// we workaround here.
|
// we workaround here.
|
||||||
if (
|
if (matrixError && !matrixError.data.flows && !matrixError.data.completed && !matrixError.data.session) {
|
||||||
!(<MatrixError>error).data.flows &&
|
matrixError.data.flows = (this.data as IAuthData).flows;
|
||||||
!(<MatrixError>error).data.completed &&
|
matrixError.data.completed = (this.data as IAuthData).completed;
|
||||||
!(<MatrixError>error).data.session
|
matrixError.data.session = (this.data as IAuthData).session;
|
||||||
) {
|
}
|
||||||
(<MatrixError>error).data.flows = this.data.flows;
|
if (matrixError) {
|
||||||
(<MatrixError>error).data.completed = this.data.completed;
|
this.data = matrixError.data as IAuthData;
|
||||||
(<MatrixError>error).data.session = this.data.session;
|
|
||||||
}
|
}
|
||||||
this.data = (<MatrixError>error).data;
|
|
||||||
try {
|
try {
|
||||||
this.startNextAuthStage();
|
this.startNextAuthStage();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -563,14 +601,6 @@ export class InteractiveAuth {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.data?.errcode || this.data?.error) {
|
|
||||||
this.stateUpdatedCallback(nextStage, {
|
|
||||||
errcode: this.data?.errcode || "",
|
|
||||||
error: this.data?.error || "",
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.stateUpdatedCallback(nextStage, nextStage === EMAIL_STAGE_TYPE ? { emailSid: this.emailSid } : {});
|
this.stateUpdatedCallback(nextStage, nextStage === EMAIL_STAGE_TYPE ? { emailSid: this.emailSid } : {});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -618,7 +648,7 @@ export class InteractiveAuth {
|
|||||||
* @throws {@link NoAuthFlowFoundError} If no suitable authentication flow can be found
|
* @throws {@link NoAuthFlowFoundError} If no suitable authentication flow can be found
|
||||||
*/
|
*/
|
||||||
private chooseFlow(): UIAFlow {
|
private chooseFlow(): UIAFlow {
|
||||||
const flows = this.data.flows || [];
|
const flows = (this.data as IAuthData)?.flows || [];
|
||||||
|
|
||||||
// we've been given an email or we've already done an email part
|
// we've been given an email or we've already done an email part
|
||||||
const haveEmail = Boolean(this.inputs.emailAddress) || Boolean(this.emailSid);
|
const haveEmail = Boolean(this.inputs.emailAddress) || Boolean(this.emailSid);
|
||||||
@ -659,7 +689,7 @@ export class InteractiveAuth {
|
|||||||
* @returns login type
|
* @returns login type
|
||||||
*/
|
*/
|
||||||
private firstUncompletedStage(flow: UIAFlow): AuthType | string | undefined {
|
private firstUncompletedStage(flow: UIAFlow): AuthType | string | undefined {
|
||||||
const completed = this.data.completed || [];
|
const completed = (this.data as IAuthData)?.completed || [];
|
||||||
return flow.stages.find((stageType) => !completed.includes(stageType));
|
return flow.stages.find((stageType) => !completed.includes(stageType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1376,10 +1376,10 @@ export class MatrixEvent extends TypedEventEmitter<MatrixEventEmittedEvents, Mat
|
|||||||
const relation = this.getWireContent()?.["m.relates_to"];
|
const relation = this.getWireContent()?.["m.relates_to"];
|
||||||
if (
|
if (
|
||||||
this.isState() &&
|
this.isState() &&
|
||||||
relation?.rel_type &&
|
!!relation?.rel_type &&
|
||||||
([RelationType.Replace, RelationType.Thread] as string[]).includes(relation.rel_type)
|
([RelationType.Replace, RelationType.Thread] as string[]).includes(relation.rel_type)
|
||||||
) {
|
) {
|
||||||
// State events cannot be m.replace relations
|
// State events cannot be m.replace or m.thread relations
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return !!(relation?.rel_type && relation.event_id && (relType ? relation.rel_type === relType : true));
|
return !!(relation?.rel_type && relation.event_id && (relType ? relation.rel_type === relType : true));
|
||||||
|
Reference in New Issue
Block a user