You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			204 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			TypeScript
		
	
			
		
		
	
	
			204 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			TypeScript
		
	
| import React from 'react';
 | |
| 
 | |
| import { SessionModal } from './SessionModal';
 | |
| import { SessionButton, SessionButtonColor } from './SessionButton';
 | |
| 
 | |
| export enum PasswordAction {
 | |
|   Set = 'set',
 | |
|   Change = 'change',
 | |
|   Remove = 'remove',
 | |
| }
 | |
| 
 | |
| interface Props {
 | |
|   action: PasswordAction;
 | |
|   onOk: any;
 | |
|   onClose: any;
 | |
| }
 | |
| 
 | |
| interface State {
 | |
|   error: string | null;
 | |
| }
 | |
| 
 | |
| export class SessionPasswordModal extends React.Component<Props, State> {
 | |
|   constructor(props: any) {
 | |
|     super(props);
 | |
| 
 | |
|     this.state = {
 | |
|       error: null,
 | |
|     };
 | |
| 
 | |
|     this.showError = this.showError.bind(this);
 | |
| 
 | |
|     this.setPassword = this.setPassword.bind(this);
 | |
|     this.closeDialog = this.closeDialog.bind(this);
 | |
| 
 | |
|     this.onKeyUp = this.onKeyUp.bind(this);
 | |
|   }
 | |
| 
 | |
|   public componentDidMount() {
 | |
|     setTimeout(() => $('#password-modal-input').focus(), 100);
 | |
|   }
 | |
| 
 | |
|   public render() {
 | |
|     const { action, onOk } = this.props;
 | |
|     const placeholders =
 | |
|       this.props.action === PasswordAction.Change
 | |
|         ? [window.i18n('typeInOldPassword'), window.i18n('enterPassword')]
 | |
|         : [window.i18n('enterPassword'), window.i18n('confirmPassword')];
 | |
| 
 | |
|     const confirmButtonColor =
 | |
|       this.props.action === PasswordAction.Remove
 | |
|         ? SessionButtonColor.Danger
 | |
|         : SessionButtonColor.Primary;
 | |
| 
 | |
|     return (
 | |
|       <SessionModal
 | |
|         title={window.i18n(`${action}Password`)}
 | |
|         onOk={() => null}
 | |
|         onClose={this.closeDialog}
 | |
|       >
 | |
|         <div className="spacer-sm" />
 | |
| 
 | |
|         <div className="session-modal__input-group">
 | |
|           <input
 | |
|             type="password"
 | |
|             id="password-modal-input"
 | |
|             placeholder={placeholders[0]}
 | |
|             onKeyUp={this.onKeyUp}
 | |
|             maxLength={window.CONSTANTS.MAX_PASSWORD_LENGTH}
 | |
|           />
 | |
|           {action !== PasswordAction.Remove && (
 | |
|             <input
 | |
|               type="password"
 | |
|               id="password-modal-input-confirm"
 | |
|               placeholder={placeholders[1]}
 | |
|               onKeyUp={this.onKeyUp}
 | |
|               maxLength={window.CONSTANTS.MAX_PASSWORD_LENGTH}
 | |
|             />
 | |
|           )}
 | |
|         </div>
 | |
| 
 | |
|         <div className="spacer-sm" />
 | |
|         {this.showError()}
 | |
| 
 | |
|         <div className="session-modal__button-group">
 | |
|           <SessionButton
 | |
|             text={window.i18n('ok')}
 | |
|             buttonColor={confirmButtonColor}
 | |
|             onClick={async () => this.setPassword(onOk)}
 | |
|           />
 | |
| 
 | |
|           <SessionButton
 | |
|             text={window.i18n('cancel')}
 | |
|             onClick={this.closeDialog}
 | |
|           />
 | |
|         </div>
 | |
|       </SessionModal>
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   public async validatePasswordHash(password: string | null) {
 | |
|     // Check if the password matches the hash we have stored
 | |
|     const hash = await window.Signal.Data.getPasswordHash();
 | |
|     if (hash && !window.passwordUtil.matchesHash(password, hash)) {
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   private showError() {
 | |
|     const message = this.state.error;
 | |
| 
 | |
|     return (
 | |
|       <>
 | |
|         {message && (
 | |
|           <>
 | |
|             <div className="session-label warning">{message}</div>
 | |
|             <div className="spacer-lg" />
 | |
|           </>
 | |
|         )}
 | |
|       </>
 | |
|     );
 | |
|   }
 | |
| 
 | |
|   private async setPassword(onSuccess: any) {
 | |
|     const enteredPassword = String($('#password-modal-input').val());
 | |
|     const enteredPasswordConfirm = String(
 | |
|       $('#password-modal-input-confirm').val()
 | |
|     );
 | |
| 
 | |
|     if (enteredPassword.length === 0 || enteredPasswordConfirm.length === 0) {
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     // Check passwords enntered
 | |
|     if (
 | |
|       enteredPassword.length === 0 ||
 | |
|       (this.props.action === PasswordAction.Change &&
 | |
|         enteredPasswordConfirm.length === 0)
 | |
|     ) {
 | |
|       this.setState({
 | |
|         error: window.i18n('noGivenPassword'),
 | |
|       });
 | |
| 
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     // Passwords match or remove password successful
 | |
|     const newPassword =
 | |
|       this.props.action === PasswordAction.Remove
 | |
|         ? null
 | |
|         : enteredPasswordConfirm;
 | |
|     const oldPassword =
 | |
|       this.props.action === PasswordAction.Set ? null : enteredPassword;
 | |
| 
 | |
|     // Check if password match, when setting, changing or removing
 | |
|     const valid =
 | |
|       this.props.action !== PasswordAction.Set
 | |
|         ? !!await this.validatePasswordHash(oldPassword)
 | |
|         : enteredPassword === enteredPasswordConfirm;
 | |
| 
 | |
|     if (!valid) {
 | |
|       this.setState({
 | |
|         error: window.i18n(`${this.props.action}PasswordInvalid`),
 | |
|       });
 | |
| 
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     await window.setPassword(newPassword, oldPassword);
 | |
| 
 | |
|     const toastParams = {
 | |
|       title: window.i18n(`${this.props.action}PasswordTitle`),
 | |
|       description: window.i18n(`${this.props.action}PasswordToastDescription`),
 | |
|       type: this.props.action !== PasswordAction.Remove ? 'success' : 'warning',
 | |
|       icon: this.props.action !== PasswordAction.Remove ? 'lock' : undefined,
 | |
|     };
 | |
| 
 | |
|     window.pushToast({
 | |
|       id: 'set-password-success-toast',
 | |
|       ...toastParams,
 | |
|     });
 | |
| 
 | |
|     onSuccess(this.props.action);
 | |
|     this.closeDialog();
 | |
|   }
 | |
| 
 | |
|   private closeDialog() {
 | |
|     if (this.props.onClose) {
 | |
|       this.props.onClose();
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   private async onKeyUp(event: any) {
 | |
|     const { onOk } = this.props;
 | |
| 
 | |
|     if (event.key === 'Enter') {
 | |
|       await this.setPassword(onOk);
 | |
|     }
 | |
| 
 | |
|     event.preventDefault();
 | |
|   }
 | |
| }
 |