Conform more of the codebase to strictNullChecks + noImplicitAny (#11179)
This commit is contained in:
parent
7c211b0587
commit
a294ba2ad4
17 changed files with 104 additions and 88 deletions
|
@ -236,7 +236,7 @@ export default class AddThreepid {
|
||||||
continueKind: "primary",
|
continueKind: "primary",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
|
const { finished } = Modal.createDialog(InteractiveAuthDialog<{}>, {
|
||||||
title: _t("Add Email Address"),
|
title: _t("Add Email Address"),
|
||||||
matrixClient: this.matrixClient,
|
matrixClient: this.matrixClient,
|
||||||
authData: err.data,
|
authData: err.data,
|
||||||
|
@ -357,7 +357,7 @@ export default class AddThreepid {
|
||||||
continueKind: "primary",
|
continueKind: "primary",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
|
const { finished } = Modal.createDialog(InteractiveAuthDialog<{}>, {
|
||||||
title: _t("Add Phone Number"),
|
title: _t("Add Phone Number"),
|
||||||
matrixClient: this.matrixClient,
|
matrixClient: this.matrixClient,
|
||||||
authData: err.data,
|
authData: err.data,
|
||||||
|
|
|
@ -327,7 +327,7 @@ function registerAsGuest(hsUrl: string, isUrl?: string, defaultDeviceDisplayName
|
||||||
{
|
{
|
||||||
userId: creds.user_id,
|
userId: creds.user_id,
|
||||||
deviceId: creds.device_id,
|
deviceId: creds.device_id,
|
||||||
accessToken: creds.access_token,
|
accessToken: creds.access_token!,
|
||||||
homeserverUrl: hsUrl,
|
homeserverUrl: hsUrl,
|
||||||
identityServerUrl: isUrl,
|
identityServerUrl: isUrl,
|
||||||
guest: true,
|
guest: true,
|
||||||
|
@ -920,10 +920,8 @@ async function clearStorage(opts?: { deleteEverything?: boolean }): Promise<void
|
||||||
|
|
||||||
// now restore those invites and registration time
|
// now restore those invites and registration time
|
||||||
if (!opts?.deleteEverything) {
|
if (!opts?.deleteEverything) {
|
||||||
pendingInvites.forEach((i) => {
|
pendingInvites.forEach(({ roomId, ...invite }) => {
|
||||||
const roomId = i.roomId;
|
ThreepidInviteStore.instance.storeInvite(roomId, invite);
|
||||||
delete i.roomId; // delete to avoid confusing the store
|
|
||||||
ThreepidInviteStore.instance.storeInvite(roomId, i);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (registrationTime) {
|
if (registrationTime) {
|
||||||
|
|
|
@ -19,7 +19,7 @@ limitations under the License.
|
||||||
import { createClient } from "matrix-js-sdk/src/matrix";
|
import { createClient } from "matrix-js-sdk/src/matrix";
|
||||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { DELEGATED_OIDC_COMPATIBILITY, ILoginFlow, ILoginParams, LoginFlow } from "matrix-js-sdk/src/@types/auth";
|
import { DELEGATED_OIDC_COMPATIBILITY, ILoginFlow, LoginFlow, LoginRequest } from "matrix-js-sdk/src/@types/auth";
|
||||||
|
|
||||||
import { IMatrixClientCreds } from "./MatrixClientPeg";
|
import { IMatrixClientCreds } from "./MatrixClientPeg";
|
||||||
import SecurityCustomisations from "./customisations/Security";
|
import SecurityCustomisations from "./customisations/Security";
|
||||||
|
@ -238,7 +238,7 @@ export async function sendLoginRequest(
|
||||||
hsUrl: string,
|
hsUrl: string,
|
||||||
isUrl: string | undefined,
|
isUrl: string | undefined,
|
||||||
loginType: string,
|
loginType: string,
|
||||||
loginParams: ILoginParams,
|
loginParams: Omit<LoginRequest, "type">,
|
||||||
): Promise<IMatrixClientCreds> {
|
): Promise<IMatrixClientCreds> {
|
||||||
const client = createClient({
|
const client = createClient({
|
||||||
baseUrl: hsUrl,
|
baseUrl: hsUrl,
|
||||||
|
|
|
@ -49,7 +49,7 @@ export interface IMatrixClientCreds {
|
||||||
identityServerUrl?: string;
|
identityServerUrl?: string;
|
||||||
userId: string;
|
userId: string;
|
||||||
deviceId?: string;
|
deviceId?: string;
|
||||||
accessToken?: string;
|
accessToken: string;
|
||||||
guest?: boolean;
|
guest?: boolean;
|
||||||
pickleKey?: string;
|
pickleKey?: string;
|
||||||
freshLogin?: boolean;
|
freshLogin?: boolean;
|
||||||
|
@ -79,8 +79,6 @@ export interface IMatrixClientPeg {
|
||||||
assign(): Promise<any>;
|
assign(): Promise<any>;
|
||||||
start(): Promise<any>;
|
start(): Promise<any>;
|
||||||
|
|
||||||
getCredentials(): IMatrixClientCreds;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If we've registered a user ID we set this to the ID of the
|
* If we've registered a user ID we set this to the ID of the
|
||||||
* user we've just registered. If they then go & log in, we
|
* user we've just registered. If they then go & log in, we
|
||||||
|
@ -138,10 +136,6 @@ class MatrixClientPegClass implements IMatrixClientPeg {
|
||||||
private matrixClient: MatrixClient | null = null;
|
private matrixClient: MatrixClient | null = null;
|
||||||
private justRegisteredUserId: string | null = null;
|
private justRegisteredUserId: string | null = null;
|
||||||
|
|
||||||
// the credentials used to init the current client object.
|
|
||||||
// used if we tear it down & recreate it with a different store
|
|
||||||
private currentClientCreds: IMatrixClientCreds | null = null;
|
|
||||||
|
|
||||||
public get(): MatrixClient | null {
|
public get(): MatrixClient | null {
|
||||||
return this.matrixClient;
|
return this.matrixClient;
|
||||||
}
|
}
|
||||||
|
@ -195,7 +189,6 @@ class MatrixClientPegClass implements IMatrixClientPeg {
|
||||||
}
|
}
|
||||||
|
|
||||||
public replaceUsingCreds(creds: IMatrixClientCreds): void {
|
public replaceUsingCreds(creds: IMatrixClientCreds): void {
|
||||||
this.currentClientCreds = creds;
|
|
||||||
this.createClient(creds);
|
this.createClient(creds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,29 +328,6 @@ class MatrixClientPegClass implements IMatrixClientPeg {
|
||||||
logger.log(`MatrixClientPeg: MatrixClient started`);
|
logger.log(`MatrixClientPeg: MatrixClient started`);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCredentials(): IMatrixClientCreds {
|
|
||||||
if (!this.matrixClient) {
|
|
||||||
throw new Error("createClient must be called first");
|
|
||||||
}
|
|
||||||
|
|
||||||
let copiedCredentials: IMatrixClientCreds | null = this.currentClientCreds;
|
|
||||||
if (this.currentClientCreds?.userId !== this.matrixClient?.credentials?.userId) {
|
|
||||||
// cached credentials belong to a different user - don't use them
|
|
||||||
copiedCredentials = null;
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
// Copy the cached credentials before overriding what we can.
|
|
||||||
...(copiedCredentials ?? {}),
|
|
||||||
|
|
||||||
homeserverUrl: this.matrixClient.baseUrl,
|
|
||||||
identityServerUrl: this.matrixClient.idBaseUrl,
|
|
||||||
userId: this.matrixClient.getSafeUserId(),
|
|
||||||
deviceId: this.matrixClient.getDeviceId() ?? undefined,
|
|
||||||
accessToken: this.matrixClient.getAccessToken() ?? undefined,
|
|
||||||
guest: this.matrixClient.isGuest(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public getHomeserverName(): string {
|
public getHomeserverName(): string {
|
||||||
const matches = /^@[^:]+:(.+)$/.exec(this.safeGet().getSafeUserId());
|
const matches = /^@[^:]+:(.+)$/.exec(this.safeGet().getSafeUserId());
|
||||||
if (matches === null || matches.length < 1) {
|
if (matches === null || matches.length < 1) {
|
||||||
|
|
|
@ -25,20 +25,19 @@ import {
|
||||||
} from "matrix-js-sdk/src/interactive-auth";
|
} from "matrix-js-sdk/src/interactive-auth";
|
||||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { UIAResponse } from "matrix-js-sdk/src/@types/uia";
|
|
||||||
|
|
||||||
import getEntryComponentForLoginType, { IStageComponent } from "../views/auth/InteractiveAuthEntryComponents";
|
import getEntryComponentForLoginType, { IStageComponent } from "../views/auth/InteractiveAuthEntryComponents";
|
||||||
import Spinner from "../views/elements/Spinner";
|
import Spinner from "../views/elements/Spinner";
|
||||||
|
|
||||||
export const ERROR_USER_CANCELLED = new Error("User cancelled auth session");
|
export const ERROR_USER_CANCELLED = new Error("User cancelled auth session");
|
||||||
|
|
||||||
type InteractiveAuthCallbackSuccess = (
|
type InteractiveAuthCallbackSuccess<T> = (
|
||||||
success: true,
|
success: true,
|
||||||
response?: IAuthData,
|
response: T,
|
||||||
extra?: { emailSid?: string; clientSecret?: string },
|
extra?: { emailSid?: string; clientSecret?: string },
|
||||||
) => void;
|
) => void;
|
||||||
type InteractiveAuthCallbackFailure = (success: false, response: IAuthData | Error) => void;
|
type InteractiveAuthCallbackFailure = (success: false, response: IAuthData | Error) => void;
|
||||||
export type InteractiveAuthCallback = InteractiveAuthCallbackSuccess & InteractiveAuthCallbackFailure;
|
export type InteractiveAuthCallback<T> = InteractiveAuthCallbackSuccess<T> & InteractiveAuthCallbackFailure;
|
||||||
|
|
||||||
export interface InteractiveAuthProps<T> {
|
export interface InteractiveAuthProps<T> {
|
||||||
// matrix client to use for UI auth requests
|
// matrix client to use for UI auth requests
|
||||||
|
@ -62,7 +61,7 @@ export interface InteractiveAuthProps<T> {
|
||||||
continueText?: string;
|
continueText?: string;
|
||||||
continueKind?: string;
|
continueKind?: string;
|
||||||
// callback
|
// callback
|
||||||
makeRequest(auth: IAuthDict | null): Promise<UIAResponse<T>>;
|
makeRequest(auth: IAuthDict | null): Promise<T>;
|
||||||
// callback called when the auth process has finished,
|
// callback called when the auth process has finished,
|
||||||
// successfully or unsuccessfully.
|
// successfully or unsuccessfully.
|
||||||
// @param {boolean} status True if the operation requiring
|
// @param {boolean} status True if the operation requiring
|
||||||
|
@ -75,7 +74,7 @@ export interface InteractiveAuthProps<T> {
|
||||||
// the auth session.
|
// the auth session.
|
||||||
// * clientSecret {string} The client secret used in auth
|
// * clientSecret {string} The client secret used in auth
|
||||||
// sessions with the ID server.
|
// sessions with the ID server.
|
||||||
onAuthFinished: InteractiveAuthCallback;
|
onAuthFinished: InteractiveAuthCallback<T>;
|
||||||
// As js-sdk interactive-auth
|
// As js-sdk interactive-auth
|
||||||
requestEmailToken?(email: string, secret: string, attempt: number, session: string): Promise<{ sid: string }>;
|
requestEmailToken?(email: string, secret: string, attempt: number, session: string): Promise<{ sid: string }>;
|
||||||
// Called when the stage changes, or the stage's phase changes. First
|
// Called when the stage changes, or the stage's phase changes. First
|
||||||
|
@ -94,7 +93,7 @@ interface IState {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class InteractiveAuthComponent<T> extends React.Component<InteractiveAuthProps<T>, IState> {
|
export default class InteractiveAuthComponent<T> extends React.Component<InteractiveAuthProps<T>, IState> {
|
||||||
private readonly authLogic: InteractiveAuth;
|
private readonly authLogic: InteractiveAuth<T>;
|
||||||
private readonly intervalId: number | null = null;
|
private readonly intervalId: number | null = null;
|
||||||
private readonly stageComponent = createRef<IStageComponent>();
|
private readonly stageComponent = createRef<IStageComponent>();
|
||||||
|
|
||||||
|
@ -108,7 +107,7 @@ export default class InteractiveAuthComponent<T> extends React.Component<Interac
|
||||||
submitButtonEnabled: false,
|
submitButtonEnabled: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.authLogic = new InteractiveAuth({
|
this.authLogic = new InteractiveAuth<T>({
|
||||||
authData: this.props.authData,
|
authData: this.props.authData,
|
||||||
doRequest: this.requestCallback,
|
doRequest: this.requestCallback,
|
||||||
busyChanged: this.onBusyChanged,
|
busyChanged: this.onBusyChanged,
|
||||||
|
@ -211,7 +210,7 @@ export default class InteractiveAuthComponent<T> extends React.Component<Interac
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
private requestCallback = (auth: IAuthDict | null, background: boolean): Promise<UIAResponse<T>> => {
|
private requestCallback = (auth: IAuthDict | null, background: boolean): Promise<T> => {
|
||||||
// This wrapper just exists because the js-sdk passes a second
|
// This wrapper just exists because the js-sdk passes a second
|
||||||
// 'busy' param for backwards compat. This throws the tests off
|
// 'busy' param for backwards compat. This throws the tests off
|
||||||
// so discard it here.
|
// so discard it here.
|
||||||
|
|
|
@ -14,12 +14,13 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { AuthType, createClient, IAuthDict, IAuthData, IInputs, MatrixError } from "matrix-js-sdk/src/matrix";
|
import { AuthType, createClient, IAuthData, IAuthDict, IInputs, MatrixError } from "matrix-js-sdk/src/matrix";
|
||||||
import React, { Fragment, ReactNode } from "react";
|
import React, { Fragment, ReactNode } from "react";
|
||||||
import { IRegisterRequestParams, IRequestTokenResponse, MatrixClient } from "matrix-js-sdk/src/client";
|
import { IRegisterRequestParams, IRequestTokenResponse, MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
import { ISSOFlow, SSOAction } from "matrix-js-sdk/src/@types/auth";
|
import { ISSOFlow, SSOAction } from "matrix-js-sdk/src/@types/auth";
|
||||||
|
import { RegisterResponse } from "matrix-js-sdk/src/@types/registration";
|
||||||
|
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import { adminContactStrings, messageForResourceLimitError, resourceLimitStrings } from "../../../utils/ErrorUtils";
|
import { adminContactStrings, messageForResourceLimitError, resourceLimitStrings } from "../../../utils/ErrorUtils";
|
||||||
|
@ -305,7 +306,7 @@ export default class Registration extends React.Component<IProps, IState> {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
private onUIAuthFinished: InteractiveAuthCallback = async (success, response): Promise<void> => {
|
private onUIAuthFinished: InteractiveAuthCallback<RegisterResponse> = async (success, response): Promise<void> => {
|
||||||
if (!this.state.matrixClient) throw new Error("Matrix client has not yet been loaded");
|
if (!this.state.matrixClient) throw new Error("Matrix client has not yet been loaded");
|
||||||
|
|
||||||
debuglog("Registration: ui authentication finished: ", { success, response });
|
debuglog("Registration: ui authentication finished: ", { success, response });
|
||||||
|
@ -329,8 +330,8 @@ export default class Registration extends React.Component<IProps, IState> {
|
||||||
<p>{errorDetail}</p>
|
<p>{errorDetail}</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if ((response as IAuthData).required_stages?.includes(AuthType.Msisdn)) {
|
} else if ((response as IAuthData).flows?.some((flow) => flow.stages.includes(AuthType.Msisdn))) {
|
||||||
const flows = (response as IAuthData).available_flows ?? [];
|
const flows = (response as IAuthData).flows ?? [];
|
||||||
const msisdnAvailable = flows.some((flow) => flow.stages.includes(AuthType.Msisdn));
|
const msisdnAvailable = flows.some((flow) => flow.stages.includes(AuthType.Msisdn));
|
||||||
if (!msisdnAvailable) {
|
if (!msisdnAvailable) {
|
||||||
errorText = _t("This server does not support authentication with a phone number.");
|
errorText = _t("This server does not support authentication with a phone number.");
|
||||||
|
@ -349,15 +350,15 @@ export default class Registration extends React.Component<IProps, IState> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const userId = (response as IAuthData).user_id;
|
const userId = (response as RegisterResponse).user_id;
|
||||||
const accessToken = (response as IAuthData).access_token;
|
const accessToken = (response as RegisterResponse).access_token;
|
||||||
if (!userId || !accessToken) throw new Error("Registration failed");
|
if (!userId || !accessToken) throw new Error("Registration failed");
|
||||||
|
|
||||||
MatrixClientPeg.setJustRegisteredUserId(userId);
|
MatrixClientPeg.setJustRegisteredUserId(userId);
|
||||||
|
|
||||||
const newState: Partial<IState> = {
|
const newState: Partial<IState> = {
|
||||||
doingUIAuth: false,
|
doingUIAuth: false,
|
||||||
registeredUsername: (response as IAuthData).user_id,
|
registeredUsername: userId,
|
||||||
differentLoggedInUserId: undefined,
|
differentLoggedInUserId: undefined,
|
||||||
completedNoSignin: false,
|
completedNoSignin: false,
|
||||||
// we're still busy until we get unmounted: don't show the registration form again
|
// we're still busy until we get unmounted: don't show the registration form again
|
||||||
|
@ -370,10 +371,8 @@ export default class Registration extends React.Component<IProps, IState> {
|
||||||
// starting the registration process. This isn't perfect since it's possible
|
// starting the registration process. This isn't perfect since it's possible
|
||||||
// the user had a separate guest session they didn't actually mean to replace.
|
// the user had a separate guest session they didn't actually mean to replace.
|
||||||
const [sessionOwner, sessionIsGuest] = await Lifecycle.getStoredSessionOwner();
|
const [sessionOwner, sessionIsGuest] = await Lifecycle.getStoredSessionOwner();
|
||||||
if (sessionOwner && !sessionIsGuest && sessionOwner !== (response as IAuthData).user_id) {
|
if (sessionOwner && !sessionIsGuest && sessionOwner !== userId) {
|
||||||
logger.log(
|
logger.log(`Found a session for ${sessionOwner} but ${userId} has just registered.`);
|
||||||
`Found a session for ${sessionOwner} but ${(response as IAuthData).user_id} has just registered.`,
|
|
||||||
);
|
|
||||||
newState.differentLoggedInUserId = sessionOwner;
|
newState.differentLoggedInUserId = sessionOwner;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -390,7 +389,7 @@ export default class Registration extends React.Component<IProps, IState> {
|
||||||
// as the client that started registration may be gone by the time we've verified the email, and only the client
|
// as the client that started registration may be gone by the time we've verified the email, and only the client
|
||||||
// that verified the email is guaranteed to exist, we'll always do the login in that client.
|
// that verified the email is guaranteed to exist, we'll always do the login in that client.
|
||||||
const hasEmail = Boolean(this.state.formVals.email);
|
const hasEmail = Boolean(this.state.formVals.email);
|
||||||
const hasAccessToken = Boolean((response as IAuthData).access_token);
|
const hasAccessToken = Boolean(accessToken);
|
||||||
debuglog("Registration: ui auth finished:", { hasEmail, hasAccessToken });
|
debuglog("Registration: ui auth finished:", { hasEmail, hasAccessToken });
|
||||||
// don’t log in if we found a session for a different user
|
// don’t log in if we found a session for a different user
|
||||||
if (!hasEmail && hasAccessToken && !newState.differentLoggedInUserId) {
|
if (!hasEmail && hasAccessToken && !newState.differentLoggedInUserId) {
|
||||||
|
@ -399,7 +398,7 @@ export default class Registration extends React.Component<IProps, IState> {
|
||||||
await this.props.onLoggedIn(
|
await this.props.onLoggedIn(
|
||||||
{
|
{
|
||||||
userId,
|
userId,
|
||||||
deviceId: (response as IAuthData).device_id,
|
deviceId: (response as RegisterResponse).device_id!,
|
||||||
homeserverUrl: this.state.matrixClient.getHomeserverUrl(),
|
homeserverUrl: this.state.matrixClient.getHomeserverUrl(),
|
||||||
identityServerUrl: this.state.matrixClient.getIdentityServerUrl(),
|
identityServerUrl: this.state.matrixClient.getIdentityServerUrl(),
|
||||||
accessToken,
|
accessToken,
|
||||||
|
@ -461,7 +460,7 @@ export default class Registration extends React.Component<IProps, IState> {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
private makeRegisterRequest = (auth: IAuthDict | null): Promise<IAuthData> => {
|
private makeRegisterRequest = (auth: IAuthDict | null): Promise<RegisterResponse> => {
|
||||||
if (!this.state.matrixClient) throw new Error("Matrix client has not yet been loaded");
|
if (!this.state.matrixClient) throw new Error("Matrix client has not yet been loaded");
|
||||||
|
|
||||||
const registerParams: IRegisterRequestParams = {
|
const registerParams: IRegisterRequestParams = {
|
||||||
|
|
|
@ -18,6 +18,7 @@ limitations under the License.
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { AuthType, IAuthData } from "matrix-js-sdk/src/interactive-auth";
|
import { AuthType, IAuthData } from "matrix-js-sdk/src/interactive-auth";
|
||||||
import { logger } from "matrix-js-sdk/src/logger";
|
import { logger } from "matrix-js-sdk/src/logger";
|
||||||
|
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
|
@ -109,7 +110,10 @@ export default class DeactivateAccountDialog extends React.Component<IProps, ISt
|
||||||
this.setState({ bodyText, continueText, continueKind });
|
this.setState({ bodyText, continueText, continueKind });
|
||||||
};
|
};
|
||||||
|
|
||||||
private onUIAuthFinished: InteractiveAuthCallback = (success, result) => {
|
private onUIAuthFinished: InteractiveAuthCallback<Awaited<ReturnType<MatrixClient["deactivateAccount"]>>> = (
|
||||||
|
success,
|
||||||
|
result,
|
||||||
|
) => {
|
||||||
if (success) return; // great! makeRequest() will be called too.
|
if (success) return; // great! makeRequest() will be called too.
|
||||||
|
|
||||||
if (result === ERROR_USER_CANCELLED) {
|
if (result === ERROR_USER_CANCELLED) {
|
||||||
|
|
|
@ -18,7 +18,8 @@ limitations under the License.
|
||||||
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||||
import { AuthType, IAuthData } from "matrix-js-sdk/src/interactive-auth";
|
import { AuthType } from "matrix-js-sdk/src/interactive-auth";
|
||||||
|
import { UIAResponse } from "matrix-js-sdk/src/@types/uia";
|
||||||
|
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import AccessibleButton from "../elements/AccessibleButton";
|
import AccessibleButton from "../elements/AccessibleButton";
|
||||||
|
@ -70,7 +71,7 @@ export interface InteractiveAuthDialogProps<T = unknown>
|
||||||
// Default is defined in _getDefaultDialogAesthetics()
|
// Default is defined in _getDefaultDialogAesthetics()
|
||||||
aestheticsForStagePhases?: DialogAesthetics;
|
aestheticsForStagePhases?: DialogAesthetics;
|
||||||
|
|
||||||
onFinished(success?: boolean, result?: IAuthData | Error | null): void;
|
onFinished(success?: boolean, result?: UIAResponse<T> | Error | null): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IState {
|
interface IState {
|
||||||
|
@ -116,7 +117,7 @@ export default class InteractiveAuthDialog<T> extends React.Component<Interactiv
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private onAuthFinished: InteractiveAuthCallback = (success, result): void => {
|
private onAuthFinished: InteractiveAuthCallback<T> = (success, result): void => {
|
||||||
if (success) {
|
if (success) {
|
||||||
this.props.onFinished(true, result);
|
this.props.onFinished(true, result);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -760,7 +760,7 @@ export default class InviteDialog extends React.PureComponent<Props, IInviteDial
|
||||||
const lookup = await MatrixClientPeg.safeGet().lookupThreePid("email", term, token);
|
const lookup = await MatrixClientPeg.safeGet().lookupThreePid("email", term, token);
|
||||||
if (term !== this.state.filterText) return; // abandon hope
|
if (term !== this.state.filterText) return; // abandon hope
|
||||||
|
|
||||||
if (!lookup || !lookup.mxid) {
|
if (!lookup || !("mxid" in lookup)) {
|
||||||
// We weren't able to find anyone - we're already suggesting the plain email
|
// We weren't able to find anyone - we're already suggesting the plain email
|
||||||
// as an alternative, so do nothing.
|
// as an alternative, so do nothing.
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -25,7 +25,7 @@ import { RoomPreviewOpts, RoomViewLifecycle } from "@matrix-org/react-sdk-module
|
||||||
|
|
||||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||||
import dis from "../../../dispatcher/dispatcher";
|
import dis from "../../../dispatcher/dispatcher";
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t, UserFriendlyError } from "../../../languageHandler";
|
||||||
import SdkConfig from "../../../SdkConfig";
|
import SdkConfig from "../../../SdkConfig";
|
||||||
import IdentityAuthClient from "../../../IdentityAuthClient";
|
import IdentityAuthClient from "../../../IdentityAuthClient";
|
||||||
import InviteReason from "../elements/InviteReason";
|
import InviteReason from "../elements/InviteReason";
|
||||||
|
@ -153,6 +153,9 @@ export default class RoomPreviewBar extends React.Component<IProps, IState> {
|
||||||
this.props.invitedEmail,
|
this.props.invitedEmail,
|
||||||
identityAccessToken!,
|
identityAccessToken!,
|
||||||
);
|
);
|
||||||
|
if (!("mxid" in result)) {
|
||||||
|
throw new UserFriendlyError("Unable to find user by email");
|
||||||
|
}
|
||||||
this.setState({ invitedEmailMxid: result.mxid });
|
this.setState({ invitedEmailMxid: result.mxid });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.setState({ threePidFetchError: err as MatrixError });
|
this.setState({ threePidFetchError: err as MatrixError });
|
||||||
|
|
|
@ -32,7 +32,7 @@ const makeDeleteRequest =
|
||||||
export const deleteDevicesWithInteractiveAuth = async (
|
export const deleteDevicesWithInteractiveAuth = async (
|
||||||
matrixClient: MatrixClient,
|
matrixClient: MatrixClient,
|
||||||
deviceIds: string[],
|
deviceIds: string[],
|
||||||
onFinished: InteractiveAuthCallback,
|
onFinished: InteractiveAuthCallback<void>,
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
if (!deviceIds.length) {
|
if (!deviceIds.length) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -2076,6 +2076,7 @@
|
||||||
"Currently removing messages in %(count)s rooms|one": "Currently removing messages in %(count)s room",
|
"Currently removing messages in %(count)s rooms|one": "Currently removing messages in %(count)s room",
|
||||||
"%(spaceName)s menu": "%(spaceName)s menu",
|
"%(spaceName)s menu": "%(spaceName)s menu",
|
||||||
"Home options": "Home options",
|
"Home options": "Home options",
|
||||||
|
"Unable to find user by email": "Unable to find user by email",
|
||||||
"Joining space…": "Joining space…",
|
"Joining space…": "Joining space…",
|
||||||
"Joining room…": "Joining room…",
|
"Joining room…": "Joining room…",
|
||||||
"Joining…": "Joining…",
|
"Joining…": "Joining…",
|
||||||
|
|
|
@ -418,7 +418,11 @@ describe("<MatrixChat />", () => {
|
||||||
// this is used to create a temporary client during login
|
// this is used to create a temporary client during login
|
||||||
jest.spyOn(MatrixJs, "createClient").mockReturnValue(loginClient);
|
jest.spyOn(MatrixJs, "createClient").mockReturnValue(loginClient);
|
||||||
|
|
||||||
loginClient.login.mockClear().mockResolvedValue({});
|
loginClient.login.mockClear().mockResolvedValue({
|
||||||
|
access_token: "TOKEN",
|
||||||
|
device_id: "IMADEVICE",
|
||||||
|
user_id: userId,
|
||||||
|
});
|
||||||
loginClient.loginFlows.mockClear().mockResolvedValue({ flows: [{ type: "m.login.password" }] });
|
loginClient.loginFlows.mockClear().mockResolvedValue({ flows: [{ type: "m.login.password" }] });
|
||||||
|
|
||||||
loginClient.getProfileInfo.mockResolvedValue({
|
loginClient.getProfileInfo.mockResolvedValue({
|
||||||
|
|
|
@ -54,7 +54,11 @@ describe("Login", function () {
|
||||||
disable_custom_urls: true,
|
disable_custom_urls: true,
|
||||||
oidc_static_client_ids: oidcStaticClientsConfig,
|
oidc_static_client_ids: oidcStaticClientsConfig,
|
||||||
});
|
});
|
||||||
mockClient.login.mockClear().mockResolvedValue({});
|
mockClient.login.mockClear().mockResolvedValue({
|
||||||
|
access_token: "TOKEN",
|
||||||
|
device_id: "IAMADEVICE",
|
||||||
|
user_id: "@user:server",
|
||||||
|
});
|
||||||
mockClient.loginFlows.mockClear().mockResolvedValue({ flows: [{ type: "m.login.password" }] });
|
mockClient.loginFlows.mockClear().mockResolvedValue({ flows: [{ type: "m.login.password" }] });
|
||||||
mocked(createClient).mockImplementation((opts) => {
|
mocked(createClient).mockImplementation((opts) => {
|
||||||
mockClient.idBaseUrl = opts.idBaseUrl;
|
mockClient.idBaseUrl = opts.idBaseUrl;
|
||||||
|
|
|
@ -19,6 +19,7 @@ import React from "react";
|
||||||
import { fireEvent, render, screen, act } from "@testing-library/react";
|
import { fireEvent, render, screen, act } from "@testing-library/react";
|
||||||
import userEvent from "@testing-library/user-event";
|
import userEvent from "@testing-library/user-event";
|
||||||
import { mocked } from "jest-mock";
|
import { mocked } from "jest-mock";
|
||||||
|
import { MatrixError } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import InteractiveAuthDialog from "../../../../src/components/views/dialogs/InteractiveAuthDialog";
|
import InteractiveAuthDialog from "../../../../src/components/views/dialogs/InteractiveAuthDialog";
|
||||||
import { clearAllModals, flushPromises, getMockClientWithEventEmitter, unmockClientPeg } from "../../../test-utils";
|
import { clearAllModals, flushPromises, getMockClientWithEventEmitter, unmockClientPeg } from "../../../test-utils";
|
||||||
|
@ -130,7 +131,7 @@ describe("InteractiveAuthDialog", function () {
|
||||||
const successfulResult = { test: 1 };
|
const successfulResult = { test: 1 };
|
||||||
const makeRequest = jest
|
const makeRequest = jest
|
||||||
.fn()
|
.fn()
|
||||||
.mockRejectedValueOnce({ httpStatus: 401, data: { flows: [{ stages: ["m.login.sso"] }] } })
|
.mockRejectedValueOnce(new MatrixError({ data: { flows: [{ stages: ["m.login.sso"] }] } }, 401))
|
||||||
.mockResolvedValue(successfulResult);
|
.mockResolvedValue(successfulResult);
|
||||||
|
|
||||||
mockClient.credentials = { userId: "@user:id" };
|
mockClient.credentials = { userId: "@user:id" };
|
||||||
|
|
|
@ -332,16 +332,18 @@ describe("<RoomPreviewBar />", () => {
|
||||||
{ medium: "not-email", address: "address 2" },
|
{ medium: "not-email", address: "address 2" },
|
||||||
];
|
];
|
||||||
|
|
||||||
const testJoinButton = (props: ComponentProps<typeof RoomPreviewBar>) => async () => {
|
const testJoinButton =
|
||||||
const onJoinClick = jest.fn();
|
(props: ComponentProps<typeof RoomPreviewBar>, expectSecondaryButton = false) =>
|
||||||
const onRejectClick = jest.fn();
|
async () => {
|
||||||
const component = getComponent({ ...props, onJoinClick, onRejectClick });
|
const onJoinClick = jest.fn();
|
||||||
await new Promise(setImmediate);
|
const onRejectClick = jest.fn();
|
||||||
expect(getPrimaryActionButton(component)).toBeTruthy();
|
const component = getComponent({ ...props, onJoinClick, onRejectClick });
|
||||||
expect(getSecondaryActionButton(component)).toBeFalsy();
|
await new Promise(setImmediate);
|
||||||
fireEvent.click(getPrimaryActionButton(component)!);
|
expect(getPrimaryActionButton(component)).toBeTruthy();
|
||||||
expect(onJoinClick).toHaveBeenCalled();
|
if (expectSecondaryButton) expect(getSecondaryActionButton(component)).toBeFalsy();
|
||||||
};
|
fireEvent.click(getPrimaryActionButton(component)!);
|
||||||
|
expect(onJoinClick).toHaveBeenCalled();
|
||||||
|
};
|
||||||
|
|
||||||
describe("when client fails to get 3PIDs", () => {
|
describe("when client fails to get 3PIDs", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
@ -399,7 +401,7 @@ describe("<RoomPreviewBar />", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders email mismatch message when invite email mxid doesnt match", async () => {
|
it("renders email mismatch message when invite email mxid doesnt match", async () => {
|
||||||
MatrixClientPeg.safeGet().lookupThreePid = jest.fn().mockReturnValue("not userid");
|
MatrixClientPeg.safeGet().lookupThreePid = jest.fn().mockReturnValue({ mxid: "not userid" });
|
||||||
const component = getComponent({ inviterName, invitedEmail });
|
const component = getComponent({ inviterName, invitedEmail });
|
||||||
await new Promise(setImmediate);
|
await new Promise(setImmediate);
|
||||||
|
|
||||||
|
@ -413,12 +415,12 @@ describe("<RoomPreviewBar />", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("renders invite message when invite email mxid match", async () => {
|
it("renders invite message when invite email mxid match", async () => {
|
||||||
MatrixClientPeg.safeGet().lookupThreePid = jest.fn().mockReturnValue(userId);
|
MatrixClientPeg.safeGet().lookupThreePid = jest.fn().mockReturnValue({ mxid: userId });
|
||||||
const component = getComponent({ inviterName, invitedEmail });
|
const component = getComponent({ inviterName, invitedEmail });
|
||||||
await new Promise(setImmediate);
|
await new Promise(setImmediate);
|
||||||
|
|
||||||
expect(getMessage(component)).toMatchSnapshot();
|
expect(getMessage(component)).toMatchSnapshot();
|
||||||
await testJoinButton({ inviterName, invitedEmail })();
|
await testJoinButton({ inviterName, invitedEmail }, false)();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -116,10 +116,40 @@ exports[`<RoomPreviewBar /> with an invite with an invited email when client has
|
||||||
class="mx_RoomPreviewBar_message"
|
class="mx_RoomPreviewBar_message"
|
||||||
>
|
>
|
||||||
<h3>
|
<h3>
|
||||||
This invite to RoomPreviewBar-test-room was sent to test@test.com
|
Do you want to join RoomPreviewBar-test-room?
|
||||||
</h3>
|
</h3>
|
||||||
<p>
|
<p>
|
||||||
Share this email in Settings to receive invites directly in Element.
|
<span
|
||||||
|
class="mx_BaseAvatar"
|
||||||
|
role="presentation"
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
aria-hidden="true"
|
||||||
|
class="mx_BaseAvatar_initial"
|
||||||
|
style="font-size: 23.400000000000002px; width: 36px; line-height: 36px;"
|
||||||
|
>
|
||||||
|
R
|
||||||
|
</span>
|
||||||
|
<img
|
||||||
|
alt=""
|
||||||
|
aria-hidden="true"
|
||||||
|
class="mx_BaseAvatar_image"
|
||||||
|
data-testid="avatar-img"
|
||||||
|
loading="lazy"
|
||||||
|
src="data:image/png;base64,00"
|
||||||
|
style="width: 36px; height: 36px;"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<span>
|
||||||
|
<span
|
||||||
|
class="mx_RoomPreviewBar_inviter"
|
||||||
|
>
|
||||||
|
@inviter:test.com
|
||||||
|
</span>
|
||||||
|
invited you
|
||||||
|
</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
Loading…
Reference in a new issue