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 
			
		
		
		
	Convert inputs on Export/Import Room Key dialogs to be real Fields (#9350)
* Convert inputs on Export/Import Room Key dialogs to be real Fields Fixes https://github.com/vector-im/element-web/issues/18517 * Correctly label the second field * Appease the linter
This commit is contained in:
		@@ -49,3 +49,8 @@ export type KeysWithObjectShape<Input> = {
 | 
				
			|||||||
        ? (Input[P] extends Array<unknown> ? never : P)
 | 
					        ? (Input[P] extends Array<unknown> ? never : P)
 | 
				
			||||||
        : never;
 | 
					        : never;
 | 
				
			||||||
}[keyof Input];
 | 
					}[keyof Input];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export type KeysStartingWith<Input extends object, Str extends string> = {
 | 
				
			||||||
 | 
					    // eslint-disable-next-line @typescript-eslint/no-unused-vars
 | 
				
			||||||
 | 
					    [P in keyof Input]: P extends `${Str}${infer _X}` ? P : never; // we don't use _X
 | 
				
			||||||
 | 
					}[keyof Input];
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
Copyright 2017 Vector Creations Ltd
 | 
					Copyright 2017 Vector Creations Ltd
 | 
				
			||||||
 | 
					Copyright 2022 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.
 | 
				
			||||||
@@ -15,7 +16,7 @@ limitations under the License.
 | 
				
			|||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import FileSaver from 'file-saver';
 | 
					import FileSaver from 'file-saver';
 | 
				
			||||||
import React, { createRef } from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
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";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -23,6 +24,8 @@ import { _t } from '../../../../languageHandler';
 | 
				
			|||||||
import * as MegolmExportEncryption from '../../../../utils/MegolmExportEncryption';
 | 
					import * as MegolmExportEncryption from '../../../../utils/MegolmExportEncryption';
 | 
				
			||||||
import { IDialogProps } from "../../../../components/views/dialogs/IDialogProps";
 | 
					import { IDialogProps } from "../../../../components/views/dialogs/IDialogProps";
 | 
				
			||||||
import BaseDialog from "../../../../components/views/dialogs/BaseDialog";
 | 
					import BaseDialog from "../../../../components/views/dialogs/BaseDialog";
 | 
				
			||||||
 | 
					import Field from "../../../../components/views/elements/Field";
 | 
				
			||||||
 | 
					import { KeysStartingWith } from "../../../../@types/common";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum Phase {
 | 
					enum Phase {
 | 
				
			||||||
    Edit = "edit",
 | 
					    Edit = "edit",
 | 
				
			||||||
@@ -36,12 +39,14 @@ interface IProps extends IDialogProps {
 | 
				
			|||||||
interface IState {
 | 
					interface IState {
 | 
				
			||||||
    phase: Phase;
 | 
					    phase: Phase;
 | 
				
			||||||
    errStr: string;
 | 
					    errStr: string;
 | 
				
			||||||
 | 
					    passphrase1: string;
 | 
				
			||||||
 | 
					    passphrase2: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					type AnyPassphrase = KeysStartingWith<IState, "passphrase">;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class ExportE2eKeysDialog extends React.Component<IProps, IState> {
 | 
					export default class ExportE2eKeysDialog extends React.Component<IProps, IState> {
 | 
				
			||||||
    private unmounted = false;
 | 
					    private unmounted = false;
 | 
				
			||||||
    private passphrase1 = createRef<HTMLInputElement>();
 | 
					 | 
				
			||||||
    private passphrase2 = createRef<HTMLInputElement>();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(props: IProps) {
 | 
					    constructor(props: IProps) {
 | 
				
			||||||
        super(props);
 | 
					        super(props);
 | 
				
			||||||
@@ -49,6 +54,8 @@ export default class ExportE2eKeysDialog extends React.Component<IProps, IState>
 | 
				
			|||||||
        this.state = {
 | 
					        this.state = {
 | 
				
			||||||
            phase: Phase.Edit,
 | 
					            phase: Phase.Edit,
 | 
				
			||||||
            errStr: null,
 | 
					            errStr: null,
 | 
				
			||||||
 | 
					            passphrase1: "",
 | 
				
			||||||
 | 
					            passphrase2: "",
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -59,8 +66,8 @@ export default class ExportE2eKeysDialog extends React.Component<IProps, IState>
 | 
				
			|||||||
    private onPassphraseFormSubmit = (ev: React.FormEvent): boolean => {
 | 
					    private onPassphraseFormSubmit = (ev: React.FormEvent): boolean => {
 | 
				
			||||||
        ev.preventDefault();
 | 
					        ev.preventDefault();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const passphrase = this.passphrase1.current.value;
 | 
					        const passphrase = this.state.passphrase1;
 | 
				
			||||||
        if (passphrase !== this.passphrase2.current.value) {
 | 
					        if (passphrase !== this.state.passphrase2) {
 | 
				
			||||||
            this.setState({ errStr: _t('Passphrases must match') });
 | 
					            this.setState({ errStr: _t('Passphrases must match') });
 | 
				
			||||||
            return false;
 | 
					            return false;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -112,6 +119,12 @@ export default class ExportE2eKeysDialog extends React.Component<IProps, IState>
 | 
				
			|||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private onPassphraseChange = (ev: React.ChangeEvent<HTMLInputElement>, phrase: AnyPassphrase) => {
 | 
				
			||||||
 | 
					        this.setState({
 | 
				
			||||||
 | 
					            [phrase]: ev.target.value,
 | 
				
			||||||
 | 
					        } as Pick<IState, AnyPassphrase>);
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public render(): JSX.Element {
 | 
					    public render(): JSX.Element {
 | 
				
			||||||
        const disableForm = (this.state.phase === Phase.Exporting);
 | 
					        const disableForm = (this.state.phase === Phase.Exporting);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -146,39 +159,28 @@ export default class ExportE2eKeysDialog extends React.Component<IProps, IState>
 | 
				
			|||||||
                        </div>
 | 
					                        </div>
 | 
				
			||||||
                        <div className='mx_E2eKeysDialog_inputTable'>
 | 
					                        <div className='mx_E2eKeysDialog_inputTable'>
 | 
				
			||||||
                            <div className='mx_E2eKeysDialog_inputRow'>
 | 
					                            <div className='mx_E2eKeysDialog_inputRow'>
 | 
				
			||||||
                                <div className='mx_E2eKeysDialog_inputLabel'>
 | 
					                                <Field
 | 
				
			||||||
                                    <label htmlFor='passphrase1'>
 | 
					                                    label={_t("Enter passphrase")}
 | 
				
			||||||
                                        { _t("Enter passphrase") }
 | 
					                                    value={this.state.passphrase1}
 | 
				
			||||||
                                    </label>
 | 
					                                    onChange={e => this.onPassphraseChange(e, "passphrase1")}
 | 
				
			||||||
                                </div>
 | 
					 | 
				
			||||||
                                <div className='mx_E2eKeysDialog_inputCell'>
 | 
					 | 
				
			||||||
                                    <input
 | 
					 | 
				
			||||||
                                        ref={this.passphrase1}
 | 
					 | 
				
			||||||
                                        id='passphrase1'
 | 
					 | 
				
			||||||
                                    autoFocus={true}
 | 
					                                    autoFocus={true}
 | 
				
			||||||
                                    size={64}
 | 
					                                    size={64}
 | 
				
			||||||
                                        type='password'
 | 
					                                    type="password"
 | 
				
			||||||
                                    disabled={disableForm}
 | 
					                                    disabled={disableForm}
 | 
				
			||||||
                                />
 | 
					                                />
 | 
				
			||||||
                            </div>
 | 
					                            </div>
 | 
				
			||||||
                            </div>
 | 
					 | 
				
			||||||
                            <div className='mx_E2eKeysDialog_inputRow'>
 | 
					                            <div className='mx_E2eKeysDialog_inputRow'>
 | 
				
			||||||
                                <div className='mx_E2eKeysDialog_inputLabel'>
 | 
					                                <Field
 | 
				
			||||||
                                    <label htmlFor='passphrase2'>
 | 
					                                    label={_t("Confirm passphrase")}
 | 
				
			||||||
                                        { _t("Confirm passphrase") }
 | 
					                                    value={this.state.passphrase2}
 | 
				
			||||||
                                    </label>
 | 
					                                    onChange={e => this.onPassphraseChange(e, "passphrase2")}
 | 
				
			||||||
                                </div>
 | 
					 | 
				
			||||||
                                <div className='mx_E2eKeysDialog_inputCell'>
 | 
					 | 
				
			||||||
                                    <input ref={this.passphrase2}
 | 
					 | 
				
			||||||
                                        id='passphrase2'
 | 
					 | 
				
			||||||
                                    size={64}
 | 
					                                    size={64}
 | 
				
			||||||
                                        type='password'
 | 
					                                    type="password"
 | 
				
			||||||
                                    disabled={disableForm}
 | 
					                                    disabled={disableForm}
 | 
				
			||||||
                                />
 | 
					                                />
 | 
				
			||||||
                            </div>
 | 
					                            </div>
 | 
				
			||||||
                        </div>
 | 
					                        </div>
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                    </div>
 | 
					 | 
				
			||||||
                    <div className='mx_Dialog_buttons'>
 | 
					                    <div className='mx_Dialog_buttons'>
 | 
				
			||||||
                        <input
 | 
					                        <input
 | 
				
			||||||
                            className='mx_Dialog_primary'
 | 
					                            className='mx_Dialog_primary'
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
/*
 | 
					/*
 | 
				
			||||||
Copyright 2017 Vector Creations Ltd
 | 
					Copyright 2017 Vector Creations Ltd
 | 
				
			||||||
 | 
					Copyright 2022 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.
 | 
				
			||||||
@@ -22,6 +23,7 @@ import * as MegolmExportEncryption from '../../../../utils/MegolmExportEncryptio
 | 
				
			|||||||
import { _t } from '../../../../languageHandler';
 | 
					import { _t } from '../../../../languageHandler';
 | 
				
			||||||
import { IDialogProps } from "../../../../components/views/dialogs/IDialogProps";
 | 
					import { IDialogProps } from "../../../../components/views/dialogs/IDialogProps";
 | 
				
			||||||
import BaseDialog from "../../../../components/views/dialogs/BaseDialog";
 | 
					import BaseDialog from "../../../../components/views/dialogs/BaseDialog";
 | 
				
			||||||
 | 
					import Field from "../../../../components/views/elements/Field";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function readFileAsArrayBuffer(file: File): Promise<ArrayBuffer> {
 | 
					function readFileAsArrayBuffer(file: File): Promise<ArrayBuffer> {
 | 
				
			||||||
    return new Promise((resolve, reject) => {
 | 
					    return new Promise((resolve, reject) => {
 | 
				
			||||||
@@ -48,12 +50,12 @@ interface IState {
 | 
				
			|||||||
    enableSubmit: boolean;
 | 
					    enableSubmit: boolean;
 | 
				
			||||||
    phase: Phase;
 | 
					    phase: Phase;
 | 
				
			||||||
    errStr: string;
 | 
					    errStr: string;
 | 
				
			||||||
 | 
					    passphrase: string;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default class ImportE2eKeysDialog extends React.Component<IProps, IState> {
 | 
					export default class ImportE2eKeysDialog extends React.Component<IProps, IState> {
 | 
				
			||||||
    private unmounted = false;
 | 
					    private unmounted = false;
 | 
				
			||||||
    private file = createRef<HTMLInputElement>();
 | 
					    private file = createRef<HTMLInputElement>();
 | 
				
			||||||
    private passphrase = createRef<HTMLInputElement>();
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(props: IProps) {
 | 
					    constructor(props: IProps) {
 | 
				
			||||||
        super(props);
 | 
					        super(props);
 | 
				
			||||||
@@ -62,6 +64,7 @@ export default class ImportE2eKeysDialog extends React.Component<IProps, IState>
 | 
				
			|||||||
            enableSubmit: false,
 | 
					            enableSubmit: false,
 | 
				
			||||||
            phase: Phase.Edit,
 | 
					            phase: Phase.Edit,
 | 
				
			||||||
            errStr: null,
 | 
					            errStr: null,
 | 
				
			||||||
 | 
					            passphrase: "",
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -69,16 +72,22 @@ export default class ImportE2eKeysDialog extends React.Component<IProps, IState>
 | 
				
			|||||||
        this.unmounted = true;
 | 
					        this.unmounted = true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private onFormChange = (ev: React.FormEvent): void => {
 | 
					    private onFormChange = (): void => {
 | 
				
			||||||
        const files = this.file.current.files || [];
 | 
					        const files = this.file.current.files || [];
 | 
				
			||||||
        this.setState({
 | 
					        this.setState({
 | 
				
			||||||
            enableSubmit: (this.passphrase.current.value !== "" && files.length > 0),
 | 
					            enableSubmit: (this.state.passphrase !== "" && files.length > 0),
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private onPassphraseChange = (ev: React.ChangeEvent<HTMLInputElement>): void => {
 | 
				
			||||||
 | 
					        this.setState({ passphrase: ev.target.value });
 | 
				
			||||||
 | 
					        this.onFormChange(); // update general form state too
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private onFormSubmit = (ev: React.FormEvent): boolean => {
 | 
					    private onFormSubmit = (ev: React.FormEvent): boolean => {
 | 
				
			||||||
        ev.preventDefault();
 | 
					        ev.preventDefault();
 | 
				
			||||||
        this.startImport(this.file.current.files[0], this.passphrase.current.value);
 | 
					        // noinspection JSIgnoredPromiseFromCall
 | 
				
			||||||
 | 
					        this.startImport(this.file.current.files[0], this.state.passphrase);
 | 
				
			||||||
        return false;
 | 
					        return false;
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -161,20 +170,14 @@ export default class ImportE2eKeysDialog extends React.Component<IProps, IState>
 | 
				
			|||||||
                                </div>
 | 
					                                </div>
 | 
				
			||||||
                            </div>
 | 
					                            </div>
 | 
				
			||||||
                            <div className='mx_E2eKeysDialog_inputRow'>
 | 
					                            <div className='mx_E2eKeysDialog_inputRow'>
 | 
				
			||||||
                                <div className='mx_E2eKeysDialog_inputLabel'>
 | 
					                                <Field
 | 
				
			||||||
                                    <label htmlFor='passphrase'>
 | 
					                                    label={_t("Enter passphrase")}
 | 
				
			||||||
                                        { _t("Enter passphrase") }
 | 
					                                    value={this.state.passphrase}
 | 
				
			||||||
                                    </label>
 | 
					                                    onChange={this.onPassphraseChange}
 | 
				
			||||||
                                </div>
 | 
					 | 
				
			||||||
                                <div className='mx_E2eKeysDialog_inputCell'>
 | 
					 | 
				
			||||||
                                    <input
 | 
					 | 
				
			||||||
                                        ref={this.passphrase}
 | 
					 | 
				
			||||||
                                        id='passphrase'
 | 
					 | 
				
			||||||
                                    size={64}
 | 
					                                    size={64}
 | 
				
			||||||
                                        type='password'
 | 
					                                    type="password"
 | 
				
			||||||
                                        onChange={this.onFormChange}
 | 
					                                    disabled={disableForm}
 | 
				
			||||||
                                        disabled={disableForm} />
 | 
					                                />
 | 
				
			||||||
                                </div>
 | 
					 | 
				
			||||||
                            </div>
 | 
					                            </div>
 | 
				
			||||||
                        </div>
 | 
					                        </div>
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user