You've already forked matrix-react-sdk
							
							
				mirror of
				https://github.com/matrix-org/matrix-react-sdk.git
				synced 2025-11-04 11:51:45 +03:00 
			
		
		
		
	Add types to InteractiveAuthEntryComponents
This commit is contained in:
		
							
								
								
									
										14
									
								
								src/Terms.ts
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								src/Terms.ts
									
									
									
									
									
								
							@@ -36,14 +36,18 @@ export class Service {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface Policy {
 | 
					export interface LocalisedPolicy {
 | 
				
			||||||
 | 
					    name: string;
 | 
				
			||||||
 | 
					    url: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface Policy {
 | 
				
			||||||
    // @ts-ignore: No great way to express indexed types together with other keys
 | 
					    // @ts-ignore: No great way to express indexed types together with other keys
 | 
				
			||||||
    version: string;
 | 
					    version: string;
 | 
				
			||||||
    [lang: string]: {
 | 
					    [lang: string]: LocalisedPolicy;
 | 
				
			||||||
        url: string;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
type Policies = {
 | 
					
 | 
				
			||||||
 | 
					export type Policies = {
 | 
				
			||||||
    [policy: string]: Policy,
 | 
					    [policy: string]: Policy,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,5 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
Copyright 2016 OpenMarket Ltd
 | 
					Copyright 2016-2021 The Matrix.org Foundation C.I.C.
 | 
				
			||||||
Copyright 2017 Vector Creations Ltd
 | 
					 | 
				
			||||||
Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Licensed under the Apache License, Version 2.0 (the "License");
 | 
					Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||||
you may not use this file except in compliance with the License.
 | 
					you may not use this file except in compliance with the License.
 | 
				
			||||||
@@ -16,9 +14,9 @@ See the License for the specific language governing permissions and
 | 
				
			|||||||
limitations under the License.
 | 
					limitations under the License.
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import React, {createRef} from 'react';
 | 
					import React, { ChangeEvent, createRef, FormEvent, MouseEvent } from 'react';
 | 
				
			||||||
import PropTypes from 'prop-types';
 | 
					import classNames from 'classnames';
 | 
				
			||||||
import classnames from 'classnames';
 | 
					import { MatrixClient } from "matrix-js-sdk/src/client";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import * as sdk from '../../../index';
 | 
					import * as sdk from '../../../index';
 | 
				
			||||||
import { _t } from '../../../languageHandler';
 | 
					import { _t } from '../../../languageHandler';
 | 
				
			||||||
@@ -27,6 +25,7 @@ import AccessibleButton from "../elements/AccessibleButton";
 | 
				
			|||||||
import Spinner from "../elements/Spinner";
 | 
					import Spinner from "../elements/Spinner";
 | 
				
			||||||
import CountlyAnalytics from "../../../CountlyAnalytics";
 | 
					import CountlyAnalytics from "../../../CountlyAnalytics";
 | 
				
			||||||
import {replaceableComponent} from "../../../utils/replaceableComponent";
 | 
					import {replaceableComponent} from "../../../utils/replaceableComponent";
 | 
				
			||||||
 | 
					import { LocalisedPolicy, Policies } from '../../../Terms';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* This file contains a collection of components which are used by the
 | 
					/* This file contains a collection of components which are used by the
 | 
				
			||||||
 * InteractiveAuth to prompt the user to enter the information needed
 | 
					 * InteractiveAuth to prompt the user to enter the information needed
 | 
				
			||||||
@@ -74,21 +73,49 @@ import {replaceableComponent} from "../../../utils/replaceableComponent";
 | 
				
			|||||||
 *    focus: set the input focus appropriately in the form.
 | 
					 *    focus: set the input focus appropriately in the form.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum AuthType {
 | 
				
			||||||
 | 
					    Password = "m.login.password",
 | 
				
			||||||
 | 
					    Recaptcha = "m.login.recaptcha",
 | 
				
			||||||
 | 
					    Terms = "m.login.terms",
 | 
				
			||||||
 | 
					    Email = "m.login.email.identity",
 | 
				
			||||||
 | 
					    Msisdn = "m.login.msisdn",
 | 
				
			||||||
 | 
					    Sso = "m.login.sso",
 | 
				
			||||||
 | 
					    SsoUnstable = "org.matrix.login.sso",
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* eslint-disable camelcase */
 | 
				
			||||||
 | 
					interface IAuthDict {
 | 
				
			||||||
 | 
					    type?: AuthType;
 | 
				
			||||||
 | 
					    // TODO: Remove `user` once servers support proper UIA
 | 
				
			||||||
 | 
					    // See https://github.com/vector-im/element-web/issues/10312
 | 
				
			||||||
 | 
					    user?: string;
 | 
				
			||||||
 | 
					    identifier?: object;
 | 
				
			||||||
 | 
					    password?: string;
 | 
				
			||||||
 | 
					    response?: string;
 | 
				
			||||||
 | 
					    // TODO: Remove `threepid_creds` once servers support proper UIA
 | 
				
			||||||
 | 
					    // See https://github.com/vector-im/element-web/issues/10312
 | 
				
			||||||
 | 
					    // See https://github.com/matrix-org/matrix-doc/issues/2220
 | 
				
			||||||
 | 
					    threepid_creds?: object;
 | 
				
			||||||
 | 
					    threepidCreds?: object;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/* eslint-enable camelcase */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const DEFAULT_PHASE = 0;
 | 
					export const DEFAULT_PHASE = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@replaceableComponent("views.auth.PasswordAuthEntry")
 | 
					interface IAuthEntryProps {
 | 
				
			||||||
export class PasswordAuthEntry extends React.Component {
 | 
					    matrixClient: MatrixClient;
 | 
				
			||||||
    static LOGIN_TYPE = "m.login.password";
 | 
					    loginType: string;
 | 
				
			||||||
 | 
					    authSessionId: string;
 | 
				
			||||||
 | 
					    submitAuthDict: (auth: IAuthDict) => void;
 | 
				
			||||||
 | 
					    errorText?: string;
 | 
				
			||||||
 | 
					    // Is the auth logic currently waiting for something to happen?
 | 
				
			||||||
 | 
					    busy?: boolean;
 | 
				
			||||||
 | 
					    onPhaseChange: (phase: number) => void;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static propTypes = {
 | 
					@replaceableComponent("views.auth.PasswordAuthEntry")
 | 
				
			||||||
        matrixClient: PropTypes.object.isRequired,
 | 
					export class PasswordAuthEntry extends React.Component<IAuthEntryProps> {
 | 
				
			||||||
        submitAuthDict: PropTypes.func.isRequired,
 | 
					    static LOGIN_TYPE = AuthType.Password;
 | 
				
			||||||
        errorText: PropTypes.string,
 | 
					 | 
				
			||||||
        // is the auth logic currently waiting for something to
 | 
					 | 
				
			||||||
        // happen?
 | 
					 | 
				
			||||||
        busy: PropTypes.bool,
 | 
					 | 
				
			||||||
        onPhaseChange: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    componentDidMount() {
 | 
					    componentDidMount() {
 | 
				
			||||||
        this.props.onPhaseChange(DEFAULT_PHASE);
 | 
					        this.props.onPhaseChange(DEFAULT_PHASE);
 | 
				
			||||||
@@ -98,12 +125,12 @@ export class PasswordAuthEntry extends React.Component {
 | 
				
			|||||||
        password: "",
 | 
					        password: "",
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onSubmit = e => {
 | 
					    private onSubmit = (e: FormEvent) => {
 | 
				
			||||||
        e.preventDefault();
 | 
					        e.preventDefault();
 | 
				
			||||||
        if (this.props.busy) return;
 | 
					        if (this.props.busy) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.props.submitAuthDict({
 | 
					        this.props.submitAuthDict({
 | 
				
			||||||
            type: PasswordAuthEntry.LOGIN_TYPE,
 | 
					            type: AuthType.Password,
 | 
				
			||||||
            // TODO: Remove `user` once servers support proper UIA
 | 
					            // TODO: Remove `user` once servers support proper UIA
 | 
				
			||||||
            // See https://github.com/vector-im/element-web/issues/10312
 | 
					            // See https://github.com/vector-im/element-web/issues/10312
 | 
				
			||||||
            user: this.props.matrixClient.credentials.userId,
 | 
					            user: this.props.matrixClient.credentials.userId,
 | 
				
			||||||
@@ -115,7 +142,7 @@ export class PasswordAuthEntry extends React.Component {
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onPasswordFieldChange = ev => {
 | 
					    private onPasswordFieldChange = (ev: ChangeEvent<HTMLInputElement>) => {
 | 
				
			||||||
        // enable the submit button iff the password is non-empty
 | 
					        // enable the submit button iff the password is non-empty
 | 
				
			||||||
        this.setState({
 | 
					        this.setState({
 | 
				
			||||||
            password: ev.target.value,
 | 
					            password: ev.target.value,
 | 
				
			||||||
@@ -123,7 +150,7 @@ export class PasswordAuthEntry extends React.Component {
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    render() {
 | 
					    render() {
 | 
				
			||||||
        const passwordBoxClass = classnames({
 | 
					        const passwordBoxClass = classNames({
 | 
				
			||||||
            "error": this.props.errorText,
 | 
					            "error": this.props.errorText,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -155,7 +182,7 @@ export class PasswordAuthEntry extends React.Component {
 | 
				
			|||||||
        return (
 | 
					        return (
 | 
				
			||||||
            <div>
 | 
					            <div>
 | 
				
			||||||
                <p>{ _t("Confirm your identity by entering your account password below.") }</p>
 | 
					                <p>{ _t("Confirm your identity by entering your account password below.") }</p>
 | 
				
			||||||
                <form onSubmit={this._onSubmit} className="mx_InteractiveAuthEntryComponents_passwordSection">
 | 
					                <form onSubmit={this.onSubmit} className="mx_InteractiveAuthEntryComponents_passwordSection">
 | 
				
			||||||
                    <Field
 | 
					                    <Field
 | 
				
			||||||
                        className={passwordBoxClass}
 | 
					                        className={passwordBoxClass}
 | 
				
			||||||
                        type="password"
 | 
					                        type="password"
 | 
				
			||||||
@@ -163,7 +190,7 @@ export class PasswordAuthEntry extends React.Component {
 | 
				
			|||||||
                        label={_t('Password')}
 | 
					                        label={_t('Password')}
 | 
				
			||||||
                        autoFocus={true}
 | 
					                        autoFocus={true}
 | 
				
			||||||
                        value={this.state.password}
 | 
					                        value={this.state.password}
 | 
				
			||||||
                        onChange={this._onPasswordFieldChange}
 | 
					                        onChange={this.onPasswordFieldChange}
 | 
				
			||||||
                    />
 | 
					                    />
 | 
				
			||||||
                    <div className="mx_button_row">
 | 
					                    <div className="mx_button_row">
 | 
				
			||||||
                        { submitButtonOrSpinner }
 | 
					                        { submitButtonOrSpinner }
 | 
				
			||||||
@@ -175,26 +202,26 @@ export class PasswordAuthEntry extends React.Component {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@replaceableComponent("views.auth.RecaptchaAuthEntry")
 | 
					/* eslint-disable camelcase */
 | 
				
			||||||
export class RecaptchaAuthEntry extends React.Component {
 | 
					interface IRecaptchaAuthEntryProps extends IAuthEntryProps {
 | 
				
			||||||
    static LOGIN_TYPE = "m.login.recaptcha";
 | 
					    stageParams?: {
 | 
				
			||||||
 | 
					        public_key?: string;
 | 
				
			||||||
    static propTypes = {
 | 
					 | 
				
			||||||
        submitAuthDict: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
        stageParams: PropTypes.object.isRequired,
 | 
					 | 
				
			||||||
        errorText: PropTypes.string,
 | 
					 | 
				
			||||||
        busy: PropTypes.bool,
 | 
					 | 
				
			||||||
        onPhaseChange: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					/* eslint-enable camelcase */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@replaceableComponent("views.auth.RecaptchaAuthEntry")
 | 
				
			||||||
 | 
					export class RecaptchaAuthEntry extends React.Component<IRecaptchaAuthEntryProps> {
 | 
				
			||||||
 | 
					    static LOGIN_TYPE = AuthType.Recaptcha;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    componentDidMount() {
 | 
					    componentDidMount() {
 | 
				
			||||||
        this.props.onPhaseChange(DEFAULT_PHASE);
 | 
					        this.props.onPhaseChange(DEFAULT_PHASE);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onCaptchaResponse = response => {
 | 
					    private onCaptchaResponse = (response: string) => {
 | 
				
			||||||
        CountlyAnalytics.instance.track("onboarding_grecaptcha_submit");
 | 
					        CountlyAnalytics.instance.track("onboarding_grecaptcha_submit");
 | 
				
			||||||
        this.props.submitAuthDict({
 | 
					        this.props.submitAuthDict({
 | 
				
			||||||
            type: RecaptchaAuthEntry.LOGIN_TYPE,
 | 
					            type: AuthType.Recaptcha,
 | 
				
			||||||
            response: response,
 | 
					            response: response,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
@@ -230,7 +257,7 @@ export class RecaptchaAuthEntry extends React.Component {
 | 
				
			|||||||
        return (
 | 
					        return (
 | 
				
			||||||
            <div>
 | 
					            <div>
 | 
				
			||||||
                <CaptchaForm sitePublicKey={sitePublicKey}
 | 
					                <CaptchaForm sitePublicKey={sitePublicKey}
 | 
				
			||||||
                    onCaptchaResponse={this._onCaptchaResponse}
 | 
					                    onCaptchaResponse={this.onCaptchaResponse}
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
                { errorSection }
 | 
					                { errorSection }
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
@@ -238,18 +265,28 @@ export class RecaptchaAuthEntry extends React.Component {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@replaceableComponent("views.auth.TermsAuthEntry")
 | 
					interface ITermsAuthEntryProps extends IAuthEntryProps {
 | 
				
			||||||
export class TermsAuthEntry extends React.Component {
 | 
					    stageParams?: {
 | 
				
			||||||
    static LOGIN_TYPE = "m.login.terms";
 | 
					        policies?: Policies;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    static propTypes = {
 | 
					 | 
				
			||||||
        submitAuthDict: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
        stageParams: PropTypes.object.isRequired,
 | 
					 | 
				
			||||||
        errorText: PropTypes.string,
 | 
					 | 
				
			||||||
        busy: PropTypes.bool,
 | 
					 | 
				
			||||||
        showContinue: PropTypes.bool,
 | 
					 | 
				
			||||||
        onPhaseChange: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					    showContinue: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface LocalisedPolicyWithId extends LocalisedPolicy {
 | 
				
			||||||
 | 
					    id: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface ITermsAuthEntryState {
 | 
				
			||||||
 | 
					    policies: LocalisedPolicyWithId[];
 | 
				
			||||||
 | 
					    toggledPolicies: {
 | 
				
			||||||
 | 
					        [policy: string]: boolean;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    errorText?: string;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@replaceableComponent("views.auth.TermsAuthEntry")
 | 
				
			||||||
 | 
					export class TermsAuthEntry extends React.Component<ITermsAuthEntryProps, ITermsAuthEntryState> {
 | 
				
			||||||
 | 
					    static LOGIN_TYPE = AuthType.Terms;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(props) {
 | 
					    constructor(props) {
 | 
				
			||||||
        super(props);
 | 
					        super(props);
 | 
				
			||||||
@@ -294,8 +331,11 @@ export class TermsAuthEntry extends React.Component {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            initToggles[policyId] = false;
 | 
					            initToggles[policyId] = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            langPolicy.id = policyId;
 | 
					            pickedPolicies.push({
 | 
				
			||||||
            pickedPolicies.push(langPolicy);
 | 
					                id: policyId,
 | 
				
			||||||
 | 
					                name: langPolicy.name,
 | 
				
			||||||
 | 
					                url: langPolicy.url,
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.state = {
 | 
					        this.state = {
 | 
				
			||||||
@@ -312,10 +352,10 @@ export class TermsAuthEntry extends React.Component {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    tryContinue = () => {
 | 
					    tryContinue = () => {
 | 
				
			||||||
        this._trySubmit();
 | 
					        this.trySubmit();
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _togglePolicy(policyId) {
 | 
					    private togglePolicy(policyId: string) {
 | 
				
			||||||
        const newToggles = {};
 | 
					        const newToggles = {};
 | 
				
			||||||
        for (const policy of this.state.policies) {
 | 
					        for (const policy of this.state.policies) {
 | 
				
			||||||
            let checked = this.state.toggledPolicies[policy.id];
 | 
					            let checked = this.state.toggledPolicies[policy.id];
 | 
				
			||||||
@@ -326,7 +366,7 @@ export class TermsAuthEntry extends React.Component {
 | 
				
			|||||||
        this.setState({"toggledPolicies": newToggles});
 | 
					        this.setState({"toggledPolicies": newToggles});
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _trySubmit = () => {
 | 
					    private trySubmit = () => {
 | 
				
			||||||
        let allChecked = true;
 | 
					        let allChecked = true;
 | 
				
			||||||
        for (const policy of this.state.policies) {
 | 
					        for (const policy of this.state.policies) {
 | 
				
			||||||
            const checked = this.state.toggledPolicies[policy.id];
 | 
					            const checked = this.state.toggledPolicies[policy.id];
 | 
				
			||||||
@@ -334,7 +374,7 @@ export class TermsAuthEntry extends React.Component {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (allChecked) {
 | 
					        if (allChecked) {
 | 
				
			||||||
            this.props.submitAuthDict({type: TermsAuthEntry.LOGIN_TYPE});
 | 
					            this.props.submitAuthDict({type: AuthType.Terms});
 | 
				
			||||||
            CountlyAnalytics.instance.track("onboarding_terms_complete");
 | 
					            CountlyAnalytics.instance.track("onboarding_terms_complete");
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            this.setState({errorText: _t("Please review and accept all of the homeserver's policies")});
 | 
					            this.setState({errorText: _t("Please review and accept all of the homeserver's policies")});
 | 
				
			||||||
@@ -356,7 +396,7 @@ export class TermsAuthEntry extends React.Component {
 | 
				
			|||||||
            checkboxes.push(
 | 
					            checkboxes.push(
 | 
				
			||||||
                // XXX: replace with StyledCheckbox
 | 
					                // XXX: replace with StyledCheckbox
 | 
				
			||||||
                <label key={"policy_checkbox_" + policy.id} className="mx_InteractiveAuthEntryComponents_termsPolicy">
 | 
					                <label key={"policy_checkbox_" + policy.id} className="mx_InteractiveAuthEntryComponents_termsPolicy">
 | 
				
			||||||
                    <input type="checkbox" onChange={() => this._togglePolicy(policy.id)} checked={checked} />
 | 
					                    <input type="checkbox" onChange={() => this.togglePolicy(policy.id)} checked={checked} />
 | 
				
			||||||
                    <a href={policy.url} target="_blank" rel="noreferrer noopener">{ policy.name }</a>
 | 
					                    <a href={policy.url} target="_blank" rel="noreferrer noopener">{ policy.name }</a>
 | 
				
			||||||
                </label>,
 | 
					                </label>,
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
@@ -375,7 +415,7 @@ export class TermsAuthEntry extends React.Component {
 | 
				
			|||||||
        if (this.props.showContinue !== false) {
 | 
					        if (this.props.showContinue !== false) {
 | 
				
			||||||
            // XXX: button classes
 | 
					            // XXX: button classes
 | 
				
			||||||
            submitButton = <button className="mx_InteractiveAuthEntryComponents_termsSubmit mx_GeneralButton"
 | 
					            submitButton = <button className="mx_InteractiveAuthEntryComponents_termsSubmit mx_GeneralButton"
 | 
				
			||||||
                onClick={this._trySubmit} disabled={!allChecked}>{_t("Accept")}</button>;
 | 
					                onClick={this.trySubmit} disabled={!allChecked}>{_t("Accept")}</button>;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return (
 | 
					        return (
 | 
				
			||||||
@@ -389,21 +429,18 @@ export class TermsAuthEntry extends React.Component {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@replaceableComponent("views.auth.EmailIdentityAuthEntry")
 | 
					interface IEmailIdentityAuthEntryProps extends IAuthEntryProps {
 | 
				
			||||||
export class EmailIdentityAuthEntry extends React.Component {
 | 
					    inputs?: {
 | 
				
			||||||
    static LOGIN_TYPE = "m.login.email.identity";
 | 
					        emailAddress?: string;
 | 
				
			||||||
 | 
					 | 
				
			||||||
    static propTypes = {
 | 
					 | 
				
			||||||
        matrixClient: PropTypes.object.isRequired,
 | 
					 | 
				
			||||||
        submitAuthDict: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
        authSessionId: PropTypes.string.isRequired,
 | 
					 | 
				
			||||||
        clientSecret: PropTypes.string.isRequired,
 | 
					 | 
				
			||||||
        inputs: PropTypes.object.isRequired,
 | 
					 | 
				
			||||||
        stageState: PropTypes.object.isRequired,
 | 
					 | 
				
			||||||
        fail: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
        setEmailSid: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
        onPhaseChange: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					    stageState?: {
 | 
				
			||||||
 | 
					        emailSid: string;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@replaceableComponent("views.auth.EmailIdentityAuthEntry")
 | 
				
			||||||
 | 
					export class EmailIdentityAuthEntry extends React.Component<IEmailIdentityAuthEntryProps> {
 | 
				
			||||||
 | 
					    static LOGIN_TYPE = AuthType.Email;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    componentDidMount() {
 | 
					    componentDidMount() {
 | 
				
			||||||
        this.props.onPhaseChange(DEFAULT_PHASE);
 | 
					        this.props.onPhaseChange(DEFAULT_PHASE);
 | 
				
			||||||
@@ -427,7 +464,7 @@ export class EmailIdentityAuthEntry extends React.Component {
 | 
				
			|||||||
            return (
 | 
					            return (
 | 
				
			||||||
                <div className="mx_InteractiveAuthEntryComponents_emailWrapper">
 | 
					                <div className="mx_InteractiveAuthEntryComponents_emailWrapper">
 | 
				
			||||||
                    <p>{ _t("A confirmation email has been sent to %(emailAddress)s",
 | 
					                    <p>{ _t("A confirmation email has been sent to %(emailAddress)s",
 | 
				
			||||||
                        { emailAddress: (sub) => <b>{ this.props.inputs.emailAddress }</b> },
 | 
					                        { emailAddress: <b>{ this.props.inputs.emailAddress }</b> },
 | 
				
			||||||
                    ) }
 | 
					                    ) }
 | 
				
			||||||
                    </p>
 | 
					                    </p>
 | 
				
			||||||
                    <p>{ _t("Open the link in the email to continue registration.") }</p>
 | 
					                    <p>{ _t("Open the link in the email to continue registration.") }</p>
 | 
				
			||||||
@@ -437,37 +474,34 @@ export class EmailIdentityAuthEntry extends React.Component {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@replaceableComponent("views.auth.MsisdnAuthEntry")
 | 
					interface IMsisdnAuthEntryProps extends IAuthEntryProps {
 | 
				
			||||||
export class MsisdnAuthEntry extends React.Component {
 | 
					    inputs: {
 | 
				
			||||||
    static LOGIN_TYPE = "m.login.msisdn";
 | 
					        phoneCountry: string;
 | 
				
			||||||
 | 
					        phoneNumber: string;
 | 
				
			||||||
    static propTypes = {
 | 
					 | 
				
			||||||
        inputs: PropTypes.shape({
 | 
					 | 
				
			||||||
            phoneCountry: PropTypes.string,
 | 
					 | 
				
			||||||
            phoneNumber: PropTypes.string,
 | 
					 | 
				
			||||||
        }),
 | 
					 | 
				
			||||||
        fail: PropTypes.func,
 | 
					 | 
				
			||||||
        clientSecret: PropTypes.func,
 | 
					 | 
				
			||||||
        submitAuthDict: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
        matrixClient: PropTypes.object,
 | 
					 | 
				
			||||||
        onPhaseChange: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					    clientSecret: string;
 | 
				
			||||||
 | 
					    fail: (error: Error) => void;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@replaceableComponent("views.auth.MsisdnAuthEntry")
 | 
				
			||||||
 | 
					export class MsisdnAuthEntry extends React.Component<IMsisdnAuthEntryProps> {
 | 
				
			||||||
 | 
					    static LOGIN_TYPE = AuthType.Msisdn;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private submitUrl: string;
 | 
				
			||||||
 | 
					    private sid: string;
 | 
				
			||||||
 | 
					    private msisdn: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    state = {
 | 
					    state = {
 | 
				
			||||||
        token: '',
 | 
					        token: '',
 | 
				
			||||||
        requestingToken: false,
 | 
					        requestingToken: false,
 | 
				
			||||||
 | 
					        errorText: '',
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    componentDidMount() {
 | 
					    componentDidMount() {
 | 
				
			||||||
        this.props.onPhaseChange(DEFAULT_PHASE);
 | 
					        this.props.onPhaseChange(DEFAULT_PHASE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this._submitUrl = null;
 | 
					 | 
				
			||||||
        this._sid = null;
 | 
					 | 
				
			||||||
        this._msisdn = null;
 | 
					 | 
				
			||||||
        this._tokenBox = null;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        this.setState({requestingToken: true});
 | 
					        this.setState({requestingToken: true});
 | 
				
			||||||
        this._requestMsisdnToken().catch((e) => {
 | 
					        this.requestMsisdnToken().catch((e) => {
 | 
				
			||||||
            this.props.fail(e);
 | 
					            this.props.fail(e);
 | 
				
			||||||
        }).finally(() => {
 | 
					        }).finally(() => {
 | 
				
			||||||
            this.setState({requestingToken: false});
 | 
					            this.setState({requestingToken: false});
 | 
				
			||||||
@@ -477,26 +511,26 @@ export class MsisdnAuthEntry extends React.Component {
 | 
				
			|||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * Requests a verification token by SMS.
 | 
					     * Requests a verification token by SMS.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    _requestMsisdnToken() {
 | 
					    private requestMsisdnToken(): Promise<void> {
 | 
				
			||||||
        return this.props.matrixClient.requestRegisterMsisdnToken(
 | 
					        return this.props.matrixClient.requestRegisterMsisdnToken(
 | 
				
			||||||
            this.props.inputs.phoneCountry,
 | 
					            this.props.inputs.phoneCountry,
 | 
				
			||||||
            this.props.inputs.phoneNumber,
 | 
					            this.props.inputs.phoneNumber,
 | 
				
			||||||
            this.props.clientSecret,
 | 
					            this.props.clientSecret,
 | 
				
			||||||
            1, // TODO: Multiple send attempts?
 | 
					            1, // TODO: Multiple send attempts?
 | 
				
			||||||
        ).then((result) => {
 | 
					        ).then((result) => {
 | 
				
			||||||
            this._submitUrl = result.submit_url;
 | 
					            this.submitUrl = result.submit_url;
 | 
				
			||||||
            this._sid = result.sid;
 | 
					            this.sid = result.sid;
 | 
				
			||||||
            this._msisdn = result.msisdn;
 | 
					            this.msisdn = result.msisdn;
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onTokenChange = e => {
 | 
					    private onTokenChange = (e: ChangeEvent<HTMLInputElement>) => {
 | 
				
			||||||
        this.setState({
 | 
					        this.setState({
 | 
				
			||||||
            token: e.target.value,
 | 
					            token: e.target.value,
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onFormSubmit = async e => {
 | 
					    private onFormSubmit = async (e: FormEvent) => {
 | 
				
			||||||
        e.preventDefault();
 | 
					        e.preventDefault();
 | 
				
			||||||
        if (this.state.token == '') return;
 | 
					        if (this.state.token == '') return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -506,20 +540,20 @@ export class MsisdnAuthEntry extends React.Component {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            let result;
 | 
					            let result;
 | 
				
			||||||
            if (this._submitUrl) {
 | 
					            if (this.submitUrl) {
 | 
				
			||||||
                result = await this.props.matrixClient.submitMsisdnTokenOtherUrl(
 | 
					                result = await this.props.matrixClient.submitMsisdnTokenOtherUrl(
 | 
				
			||||||
                    this._submitUrl, this._sid, this.props.clientSecret, this.state.token,
 | 
					                    this.submitUrl, this.sid, this.props.clientSecret, this.state.token,
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                throw new Error("The registration with MSISDN flow is misconfigured");
 | 
					                throw new Error("The registration with MSISDN flow is misconfigured");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (result.success) {
 | 
					            if (result.success) {
 | 
				
			||||||
                const creds = {
 | 
					                const creds = {
 | 
				
			||||||
                    sid: this._sid,
 | 
					                    sid: this.sid,
 | 
				
			||||||
                    client_secret: this.props.clientSecret,
 | 
					                    client_secret: this.props.clientSecret,
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
                this.props.submitAuthDict({
 | 
					                this.props.submitAuthDict({
 | 
				
			||||||
                    type: MsisdnAuthEntry.LOGIN_TYPE,
 | 
					                    type: AuthType.Msisdn,
 | 
				
			||||||
                    // TODO: Remove `threepid_creds` once servers support proper UIA
 | 
					                    // TODO: Remove `threepid_creds` once servers support proper UIA
 | 
				
			||||||
                    // See https://github.com/vector-im/element-web/issues/10312
 | 
					                    // See https://github.com/vector-im/element-web/issues/10312
 | 
				
			||||||
                    // See https://github.com/matrix-org/matrix-doc/issues/2220
 | 
					                    // See https://github.com/matrix-org/matrix-doc/issues/2220
 | 
				
			||||||
@@ -543,7 +577,7 @@ export class MsisdnAuthEntry extends React.Component {
 | 
				
			|||||||
            return <Loader />;
 | 
					            return <Loader />;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            const enableSubmit = Boolean(this.state.token);
 | 
					            const enableSubmit = Boolean(this.state.token);
 | 
				
			||||||
            const submitClasses = classnames({
 | 
					            const submitClasses = classNames({
 | 
				
			||||||
                mx_InteractiveAuthEntryComponents_msisdnSubmit: true,
 | 
					                mx_InteractiveAuthEntryComponents_msisdnSubmit: true,
 | 
				
			||||||
                mx_GeneralButton: true,
 | 
					                mx_GeneralButton: true,
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
@@ -558,16 +592,16 @@ export class MsisdnAuthEntry extends React.Component {
 | 
				
			|||||||
            return (
 | 
					            return (
 | 
				
			||||||
                <div>
 | 
					                <div>
 | 
				
			||||||
                    <p>{ _t("A text message has been sent to %(msisdn)s",
 | 
					                    <p>{ _t("A text message has been sent to %(msisdn)s",
 | 
				
			||||||
                        { msisdn: <i>{ this._msisdn }</i> },
 | 
					                        { msisdn: <i>{ this.msisdn }</i> },
 | 
				
			||||||
                    ) }
 | 
					                    ) }
 | 
				
			||||||
                    </p>
 | 
					                    </p>
 | 
				
			||||||
                    <p>{ _t("Please enter the code it contains:") }</p>
 | 
					                    <p>{ _t("Please enter the code it contains:") }</p>
 | 
				
			||||||
                    <div className="mx_InteractiveAuthEntryComponents_msisdnWrapper">
 | 
					                    <div className="mx_InteractiveAuthEntryComponents_msisdnWrapper">
 | 
				
			||||||
                        <form onSubmit={this._onFormSubmit}>
 | 
					                        <form onSubmit={this.onFormSubmit}>
 | 
				
			||||||
                            <input type="text"
 | 
					                            <input type="text"
 | 
				
			||||||
                                className="mx_InteractiveAuthEntryComponents_msisdnEntry"
 | 
					                                className="mx_InteractiveAuthEntryComponents_msisdnEntry"
 | 
				
			||||||
                                value={this.state.token}
 | 
					                                value={this.state.token}
 | 
				
			||||||
                                onChange={this._onTokenChange}
 | 
					                                onChange={this.onTokenChange}
 | 
				
			||||||
                                aria-label={ _t("Code")}
 | 
					                                aria-label={ _t("Code")}
 | 
				
			||||||
                            />
 | 
					                            />
 | 
				
			||||||
                            <br />
 | 
					                            <br />
 | 
				
			||||||
@@ -584,40 +618,40 @@ export class MsisdnAuthEntry extends React.Component {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@replaceableComponent("views.auth.SSOAuthEntry")
 | 
					interface ISSOAuthEntryProps extends IAuthEntryProps {
 | 
				
			||||||
export class SSOAuthEntry extends React.Component {
 | 
					    continueText?: string;
 | 
				
			||||||
    static propTypes = {
 | 
					    continueKind?: string;
 | 
				
			||||||
        matrixClient: PropTypes.object.isRequired,
 | 
					    onCancel?: () => void;
 | 
				
			||||||
        authSessionId: PropTypes.string.isRequired,
 | 
					}
 | 
				
			||||||
        loginType: PropTypes.string.isRequired,
 | 
					 | 
				
			||||||
        submitAuthDict: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
        errorText: PropTypes.string,
 | 
					 | 
				
			||||||
        onPhaseChange: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
        continueText: PropTypes.string,
 | 
					 | 
				
			||||||
        continueKind: PropTypes.string,
 | 
					 | 
				
			||||||
        onCancel: PropTypes.func,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static LOGIN_TYPE = "m.login.sso";
 | 
					interface ISSOAuthEntryState {
 | 
				
			||||||
    static UNSTABLE_LOGIN_TYPE = "org.matrix.login.sso";
 | 
					    phase: number;
 | 
				
			||||||
 | 
					    attemptFailed: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@replaceableComponent("views.auth.SSOAuthEntry")
 | 
				
			||||||
 | 
					export class SSOAuthEntry extends React.Component<ISSOAuthEntryProps, ISSOAuthEntryState> {
 | 
				
			||||||
 | 
					    static LOGIN_TYPE = AuthType.Sso;
 | 
				
			||||||
 | 
					    static UNSTABLE_LOGIN_TYPE = AuthType.SsoUnstable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static PHASE_PREAUTH = 1; // button to start SSO
 | 
					    static PHASE_PREAUTH = 1; // button to start SSO
 | 
				
			||||||
    static PHASE_POSTAUTH = 2; // button to confirm SSO completed
 | 
					    static PHASE_POSTAUTH = 2; // button to confirm SSO completed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _ssoUrl: string;
 | 
					    private ssoUrl: string;
 | 
				
			||||||
 | 
					    private popupWindow: Window;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(props) {
 | 
					    constructor(props) {
 | 
				
			||||||
        super(props);
 | 
					        super(props);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // We actually send the user through fallback auth so we don't have to
 | 
					        // We actually send the user through fallback auth so we don't have to
 | 
				
			||||||
        // deal with a redirect back to us, losing application context.
 | 
					        // deal with a redirect back to us, losing application context.
 | 
				
			||||||
        this._ssoUrl = props.matrixClient.getFallbackAuthUrl(
 | 
					        this.ssoUrl = props.matrixClient.getFallbackAuthUrl(
 | 
				
			||||||
            this.props.loginType,
 | 
					            this.props.loginType,
 | 
				
			||||||
            this.props.authSessionId,
 | 
					            this.props.authSessionId,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this._popupWindow = null;
 | 
					        this.popupWindow = null;
 | 
				
			||||||
        window.addEventListener("message", this._onReceiveMessage);
 | 
					        window.addEventListener("message", this.onReceiveMessage);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.state = {
 | 
					        this.state = {
 | 
				
			||||||
            phase: SSOAuthEntry.PHASE_PREAUTH,
 | 
					            phase: SSOAuthEntry.PHASE_PREAUTH,
 | 
				
			||||||
@@ -625,15 +659,15 @@ export class SSOAuthEntry extends React.Component {
 | 
				
			|||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    componentDidMount(): void {
 | 
					    componentDidMount() {
 | 
				
			||||||
        this.props.onPhaseChange(SSOAuthEntry.PHASE_PREAUTH);
 | 
					        this.props.onPhaseChange(SSOAuthEntry.PHASE_PREAUTH);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    componentWillUnmount() {
 | 
					    componentWillUnmount() {
 | 
				
			||||||
        window.removeEventListener("message", this._onReceiveMessage);
 | 
					        window.removeEventListener("message", this.onReceiveMessage);
 | 
				
			||||||
        if (this._popupWindow) {
 | 
					        if (this.popupWindow) {
 | 
				
			||||||
            this._popupWindow.close();
 | 
					            this.popupWindow.close();
 | 
				
			||||||
            this._popupWindow = null;
 | 
					            this.popupWindow = null;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -643,11 +677,11 @@ export class SSOAuthEntry extends React.Component {
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onReceiveMessage = event => {
 | 
					    private onReceiveMessage = (event: MessageEvent) => {
 | 
				
			||||||
        if (event.data === "authDone" && event.origin === this.props.matrixClient.getHomeserverUrl()) {
 | 
					        if (event.data === "authDone" && event.origin === this.props.matrixClient.getHomeserverUrl()) {
 | 
				
			||||||
            if (this._popupWindow) {
 | 
					            if (this.popupWindow) {
 | 
				
			||||||
                this._popupWindow.close();
 | 
					                this.popupWindow.close();
 | 
				
			||||||
                this._popupWindow = null;
 | 
					                this.popupWindow = null;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
@@ -657,7 +691,7 @@ export class SSOAuthEntry extends React.Component {
 | 
				
			|||||||
        // certainly will need to open the thing in a new tab to avoid losing application
 | 
					        // certainly will need to open the thing in a new tab to avoid losing application
 | 
				
			||||||
        // context.
 | 
					        // context.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this._popupWindow = window.open(this._ssoUrl, "_blank");
 | 
					        this.popupWindow = window.open(this.ssoUrl, "_blank");
 | 
				
			||||||
        this.setState({phase: SSOAuthEntry.PHASE_POSTAUTH});
 | 
					        this.setState({phase: SSOAuthEntry.PHASE_POSTAUTH});
 | 
				
			||||||
        this.props.onPhaseChange(SSOAuthEntry.PHASE_POSTAUTH);
 | 
					        this.props.onPhaseChange(SSOAuthEntry.PHASE_POSTAUTH);
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
@@ -716,46 +750,37 @@ export class SSOAuthEntry extends React.Component {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@replaceableComponent("views.auth.FallbackAuthEntry")
 | 
					@replaceableComponent("views.auth.FallbackAuthEntry")
 | 
				
			||||||
export class FallbackAuthEntry extends React.Component {
 | 
					export class FallbackAuthEntry extends React.Component<IAuthEntryProps> {
 | 
				
			||||||
    static propTypes = {
 | 
					    private popupWindow: Window;
 | 
				
			||||||
        matrixClient: PropTypes.object.isRequired,
 | 
					    private fallbackButton = createRef<HTMLAnchorElement>();
 | 
				
			||||||
        authSessionId: PropTypes.string.isRequired,
 | 
					 | 
				
			||||||
        loginType: PropTypes.string.isRequired,
 | 
					 | 
				
			||||||
        submitAuthDict: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
        errorText: PropTypes.string,
 | 
					 | 
				
			||||||
        onPhaseChange: PropTypes.func.isRequired,
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(props) {
 | 
					    constructor(props) {
 | 
				
			||||||
        super(props);
 | 
					        super(props);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // we have to make the user click a button, as browsers will block
 | 
					        // we have to make the user click a button, as browsers will block
 | 
				
			||||||
        // the popup if we open it immediately.
 | 
					        // the popup if we open it immediately.
 | 
				
			||||||
        this._popupWindow = null;
 | 
					        this.popupWindow = null;
 | 
				
			||||||
        window.addEventListener("message", this._onReceiveMessage);
 | 
					        window.addEventListener("message", this.onReceiveMessage);
 | 
				
			||||||
 | 
					 | 
				
			||||||
        this._fallbackButton = createRef();
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    componentDidMount() {
 | 
					    componentDidMount() {
 | 
				
			||||||
        this.props.onPhaseChange(DEFAULT_PHASE);
 | 
					        this.props.onPhaseChange(DEFAULT_PHASE);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    componentWillUnmount() {
 | 
					    componentWillUnmount() {
 | 
				
			||||||
        window.removeEventListener("message", this._onReceiveMessage);
 | 
					        window.removeEventListener("message", this.onReceiveMessage);
 | 
				
			||||||
        if (this._popupWindow) {
 | 
					        if (this.popupWindow) {
 | 
				
			||||||
            this._popupWindow.close();
 | 
					            this.popupWindow.close();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    focus = () => {
 | 
					    focus = () => {
 | 
				
			||||||
        if (this._fallbackButton.current) {
 | 
					        if (this.fallbackButton.current) {
 | 
				
			||||||
            this._fallbackButton.current.focus();
 | 
					            this.fallbackButton.current.focus();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onShowFallbackClick = e => {
 | 
					    private onShowFallbackClick = (e: MouseEvent) => {
 | 
				
			||||||
        e.preventDefault();
 | 
					        e.preventDefault();
 | 
				
			||||||
        e.stopPropagation();
 | 
					        e.stopPropagation();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -763,10 +788,10 @@ export class FallbackAuthEntry extends React.Component {
 | 
				
			|||||||
            this.props.loginType,
 | 
					            this.props.loginType,
 | 
				
			||||||
            this.props.authSessionId,
 | 
					            this.props.authSessionId,
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
        this._popupWindow = window.open(url, "_blank");
 | 
					        this.popupWindow = window.open(url, "_blank");
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _onReceiveMessage = event => {
 | 
					    private onReceiveMessage = (event: MessageEvent) => {
 | 
				
			||||||
        if (
 | 
					        if (
 | 
				
			||||||
            event.data === "authDone" &&
 | 
					            event.data === "authDone" &&
 | 
				
			||||||
            event.origin === this.props.matrixClient.getHomeserverUrl()
 | 
					            event.origin === this.props.matrixClient.getHomeserverUrl()
 | 
				
			||||||
@@ -786,7 +811,7 @@ export class FallbackAuthEntry extends React.Component {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        return (
 | 
					        return (
 | 
				
			||||||
            <div>
 | 
					            <div>
 | 
				
			||||||
                <a href="" ref={this._fallbackButton} onClick={this._onShowFallbackClick}>{
 | 
					                <a href="" ref={this.fallbackButton} onClick={this.onShowFallbackClick}>{
 | 
				
			||||||
                    _t("Start authentication")
 | 
					                    _t("Start authentication")
 | 
				
			||||||
                }</a>
 | 
					                }</a>
 | 
				
			||||||
                {errorSection}
 | 
					                {errorSection}
 | 
				
			||||||
@@ -795,20 +820,22 @@ export class FallbackAuthEntry extends React.Component {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const AuthEntryComponents = [
 | 
					export default function getEntryComponentForLoginType(loginType: AuthType): typeof React.Component {
 | 
				
			||||||
    PasswordAuthEntry,
 | 
					    switch (loginType) {
 | 
				
			||||||
    RecaptchaAuthEntry,
 | 
					        case AuthType.Password:
 | 
				
			||||||
    EmailIdentityAuthEntry,
 | 
					            return PasswordAuthEntry;
 | 
				
			||||||
    MsisdnAuthEntry,
 | 
					        case AuthType.Recaptcha:
 | 
				
			||||||
    TermsAuthEntry,
 | 
					            return RecaptchaAuthEntry;
 | 
				
			||||||
    SSOAuthEntry,
 | 
					        case AuthType.Email:
 | 
				
			||||||
];
 | 
					            return EmailIdentityAuthEntry;
 | 
				
			||||||
 | 
					        case AuthType.Msisdn:
 | 
				
			||||||
export default function getEntryComponentForLoginType(loginType) {
 | 
					            return MsisdnAuthEntry;
 | 
				
			||||||
    for (const c of AuthEntryComponents) {
 | 
					        case AuthType.Terms:
 | 
				
			||||||
        if (c.LOGIN_TYPE === loginType || c.UNSTABLE_LOGIN_TYPE === loginType) {
 | 
					            return TermsAuthEntry;
 | 
				
			||||||
            return c;
 | 
					        case AuthType.Sso:
 | 
				
			||||||
        }
 | 
					        case AuthType.SsoUnstable:
 | 
				
			||||||
 | 
					            return SSOAuthEntry;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            return FallbackAuthEntry;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return FallbackAuthEntry;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -105,12 +105,14 @@ function safeCounterpartTranslate(text: string, options?: object) {
 | 
				
			|||||||
    return translated;
 | 
					    return translated;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type SubstitutionValue = number | string | React.ReactNode | ((sub: string) => React.ReactNode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IVariables {
 | 
					export interface IVariables {
 | 
				
			||||||
    count?: number;
 | 
					    count?: number;
 | 
				
			||||||
    [key: string]: number | string;
 | 
					    [key: string]: SubstitutionValue;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Tags = Record<string, (sub: string) => React.ReactNode>;
 | 
					type Tags = Record<string, SubstitutionValue>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type TranslatedString = string | React.ReactNode;
 | 
					export type TranslatedString = string | React.ReactNode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -247,7 +249,7 @@ export function replaceByRegexes(text: string, mapping: IVariables | Tags): stri
 | 
				
			|||||||
                let replaced;
 | 
					                let replaced;
 | 
				
			||||||
                // If substitution is a function, call it
 | 
					                // If substitution is a function, call it
 | 
				
			||||||
                if (mapping[regexpString] instanceof Function) {
 | 
					                if (mapping[regexpString] instanceof Function) {
 | 
				
			||||||
                    replaced = (mapping as Tags)[regexpString].apply(null, capturedGroups);
 | 
					                    replaced = ((mapping as Tags)[regexpString] as Function)(...capturedGroups);
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    replaced = mapping[regexpString];
 | 
					                    replaced = mapping[regexpString];
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user