UNPKG

passbolt-styleguide

Version:

Passbolt styleguide contains common styling assets used by the different sites, plugin, etc.

266 lines (246 loc) 9.92 kB
import React from "react"; import PropTypes from "prop-types"; import {Trans, withTranslation} from "react-i18next"; import {Link, withRouter} from "react-router-dom"; import Tabs from "../../../react-extension/components/Common/Tab/Tabs"; import Tab from "../../../react-extension/components/Common/Tab/Tab"; import ConfigurePassphraseGenerator from "./ConfigurePassphraseGenerator"; import ConfigurePasswordGenerator from "./ConfigurePasswordGenerator"; import {SecretGenerator} from "../../../shared/lib/SecretGenerator/SecretGenerator"; import {withPrepareResourceContext} from "../../contexts/PrepareResourceContext"; import Transition from "react-transition-group/cjs/Transition"; import Icon from "../../../shared/components/Icons/Icon"; import Password from "../../../shared/components/Password/Password"; import PasswordComplexity from "../../../shared/components/PasswordComplexity/PasswordComplexity"; import ClipBoard from '../../../shared/lib/Browser/clipBoard'; class GeneratePasswordPage extends React.Component { constructor(props) { super(props); this.state = this.defaultState; this.initEventHandlers(); } get defaultState() { return { password: "", // The password isObfuscated: true, // True if the passphrase should not be visible generator: {}, // The current password generator copySecretState: "default", processing: false }; } /** * Whenever the component has been mounted */ async componentDidMount() { const type = this.props.prepareResourceContext.settings.default_generator; const initialGenerator = this.generators.find(generator => generator.type === type); await this.handleGeneratorChanged(initialGenerator); } /** * Initialize the event handlers */ initEventHandlers() { this.handleSubmit = this.handleSubmit.bind(this); this.handleInputChange = this.handleInputChange.bind(this); this.handleViewPasswordToggle = this.handleViewPasswordToggle.bind(this); this.handleGeneratePasswordButtonClick = this.handleGeneratePasswordButtonClick.bind(this); this.handleGeneratorChanged = this.handleGeneratorChanged.bind(this); this.handleCopyPassword = this.handleCopyPassword.bind(this); this.handleGoBackClick = this.handleGoBackClick.bind(this); } /** * Returns the possible generators */ get generators() { return this.props.prepareResourceContext.settings.generators; } /** * Handle when the generator configuration has changed * @param generatorConfiguration The generator configuration * @returns {Promise<void>} */ async handleGeneratorChanged(generatorConfiguration) { await this.setState({generator: generatorConfiguration}); this.generatePassword(); } /** * Handle when one wants to generate password */ handleGeneratePasswordButtonClick() { this.generatePassword(); } /** * Handle form input change. * @params {ReactEvent} The react event. */ handleInputChange(event) { const target = event.target; const value = target.value; const name = target.name; this.setState({ [name]: value }); } /** * Handle view password button click. */ handleViewPasswordToggle() { if (this.state.processing) { return; } this.setState({isObfuscated: !this.state.isObfuscated}); } /** * Handle the submission of the generated password. * @params {ReactEvent} The react event */ async handleSubmit(event) { event.preventDefault(); await this.setState({processing: true}); await this.props.prepareResourceContext.onPasswordGenerated(this.state.password, this.state.generator); this.props.history.goBack(); } /** * Whenever one wants to copy the password */ async handleCopyPassword() { this.setState({copySecretState: 'processing'}); await ClipBoard.copy(this.state.password, this.props.context.port); this.setState({copySecretState: 'done'}); setTimeout(() => { this.setState({copySecretState: 'default'}); }, 3000); } /** * Generate the password */ generatePassword() { const password = SecretGenerator.generate(this.state.generator); this.setState({password}); } handleGoBackClick(ev) { ev.preventDefault(); this.props.history.goBack(); } get translate() { return this.props.t; } isPasswordEmpty() { return this.state.password === ""; } hasGeneratorName() { return this.state.generator.name; } render() { const passwordEntropy = this.state.password ? SecretGenerator.entropy(this.state.password) : null; return ( <> {!this.state.loading && <div className="generate-password"> <div className="back-link"> <a href="#" className="primary-action" onClick={this.handleGoBackClick} title={this.translate("Cancel the operation")}> <Icon name="chevron-left"/> <span className="primary-action-title"><Trans>Generate password</Trans></span> </a> <Link to="/webAccessibleResources/quickaccess.html" className="secondary-action button-transparent button" title={this.translate("Cancel")}> <Icon name="close"/> <span className="visually-hidden"><Trans>Cancel</Trans></span> </Link> </div> <form onSubmit={this.handleSubmit} noValidate> <div className="form-container"> <div className="input-password-wrapper input"> <label htmlFor="generate-resource-password-form-password"><Trans>Password</Trans></label> <div className="password-button-inline"> <Password id="generate-resource-password-form-password" name="password" autoComplete="off" readOnly={true} placeholder={this.translate("Password")} preview={true} value={this.state.password} onChange={this.handleInputChange} disabled={this.state.processing}/> <a onClick={this.handleGeneratePasswordButtonClick} className="password-generate button button-icon"> <Icon name="dice"/> <span className="visually-hidden"><Trans>Generate</Trans></span> </a> <a onClick={this.handleCopyPassword} className="copy-to-clipboard button button-icon"> <Transition in={this.state.copySecretState === "default"} appear={false} timeout={500}> {status => ( <span className={`transition fade-${status} ${this.state.copySecretState !== "default" ? "visually-hidden" : ""}`}> <Icon name="copy-to-clipboard"/> </span> )} </Transition> <Transition in={this.state.copySecretState === "processing"} appear={true} timeout={500}> {status => ( <span className={`transition fade-${status} ${this.state.copySecretState !== "processing" ? "visually-hidden" : ""}`}> <Icon name="spinner"/> </span> )} </Transition> <Transition in={this.state.copySecretState === "done"} appear={true} timeout={500}> {status => ( <span className={`transition fade-${status} ${this.state.copySecretState !== "done" ? "visually-hidden" : ""}`}> <Icon name="check"/> </span> )} </Transition> <span className="visually-hidden"><Trans>Copy</Trans></span> </a> </div> <PasswordComplexity entropy={passwordEntropy}/> </div> {this.hasGeneratorName() && <Tabs activeTabName={this.state.generator.name}> {this.generators.map(generator => <Tab key={generator.name} name={generator.name} type={generator.type} onClick={() => this.handleGeneratorChanged(generator)}> {generator.type === "password" && <ConfigurePasswordGenerator configuration={this.state.generator} onChanged={this.handleGeneratorChanged}/> } {generator.type === "passphrase" && <ConfigurePassphraseGenerator configuration={this.state.generator} onChanged={this.handleGeneratorChanged}/> } </Tab> )} </Tabs> } </div> <div className="submit-wrapper input"> <button type="submit" className={`button primary big full-width ${this.state.processing ? 'processing' : ''}`} role="button" disabled={this.state.processing || this.isPasswordEmpty()}> <Trans>Apply</Trans> {this.state.processing && <Icon name="spinner"/> } </button> </div> </form> </div> } </> ); } } GeneratePasswordPage.propTypes = { context: PropTypes.any, // The application context prepareResourceContext: PropTypes.any, // The password generator context history: PropTypes.any, // The history router t: PropTypes.func, // The translation function }; export default withRouter(withPrepareResourceContext(withTranslation('common')(GeneratePasswordPage)));