UNPKG

passbolt-styleguide

Version:

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

239 lines (214 loc) 8.37 kB
/** * Passbolt ~ Open source password manager for teams * Copyright (c) 2020 Passbolt SA (https://www.passbolt.com) * * Licensed under GNU Affero General Public License version 3 of the or any later version. * For full copyright and license information, please see the LICENSE.txt * Redistributions of files must retain the above copyright notice. * * @copyright Copyright (c) 2020 Passbolt SA (https://www.passbolt.com) * @license https://opensource.org/licenses/AGPL-3.0 AGPL License * @link https://www.passbolt.com Passbolt(tm) * @since 3.0.0 */ import React from "react"; import PropTypes from "prop-types"; import { withAppContext } from "../../shared/context/AppContext/AppContext"; import { ApiClient } from "../../shared/lib/apiClient/apiClient"; import { BROWSER_NAMES, detectBrowserName } from "../../shared/lib/Browser/detectBrowserName"; import PassboltApiFetchError from "../../shared/lib/Error/PassboltApiFetchError"; import PassboltServiceUnavailableError from "../../shared/lib/Error/PassboltServiceUnavailableError"; import AuthLogoutService from "../../shared/services/api/auth/AuthLogoutService"; /** * The Api setup context. * @type {React.Context<object>} */ export const ApiSetupContext = React.createContext({ userId: null, // The setup user id token: null, // The setup token state: null, // The current setup workflow state unexpectedError: null, // The unexpected error obejct if any // Whenever the initialization of the setup is requested. onInitializeSetupRequested: () => {}, // Callback to be used when a user is unexpectedly logged in. logoutUserAndRefresh: () => {}, }); /** * The related context provider */ class ApiSetupContextProvider extends React.Component { /** * Default constructor * @param props The component props */ constructor(props) { super(props); this.state = Object.assign(this.defaultState, props.value); this.authLogoutService = new AuthLogoutService(props.context.getApiClientOptions()); } /** * Returns the default component state */ get defaultState() { return { userId: null, // The account recovery user id token: null, // The recover token state: ApiSetupContextState.INITIAL_STATE, // The current recover workflow state unexpectedError: null, // The unexpected error obejct if any onInitializeSetupRequested: this.onInitializeSetupRequested.bind(this), // Whenever the initialization of the recover is requested. logoutUserAndRefresh: this.logoutUserAndRefresh.bind(this), // Callback to be used when a user is unexpectedly logged in. handleSafariExtensionDownloading: this.handleSafariExtensionDownloading.bind(this), // callback when user clicked on the Safari extension download button handleSafariExtensionNotDownloaded: this.handleSafariExtensionNotDownloaded.bind(this), // callback when user clicked on the "I didn't download the Safari extension" button handleExtensionAlreadyInstalled: this.handleExtensionAlreadyInstalled.bind(this), // callback when user clicked on "already installed extension" button }; } /** * Initialize the setup * @return {Promise<void>} */ async onInitializeSetupRequested() { if (!this.state.userId || !this.state.token) { return this.setState({ state: ApiSetupContextState.REQUEST_INVITATION_ERROR }); } if (!this.isBrowserSupported()) { return this.setState({ state: ApiSetupContextState.DOWNLOAD_SUPPORTED_BROWSER_STATE }); } await this.startSetup().then(this.handleStartSetupSuccess.bind(this)).catch(this.handleStartSetupError.bind(this)); } /** * When the setup start succeed. * @return {void} */ handleStartSetupSuccess() { const currentBrowser = detectBrowserName(); const state = currentBrowser === BROWSER_NAMES.SAFARI ? ApiSetupContextState.INSTALL_SAFARI_EXTENSION_STATE : ApiSetupContextState.INSTALL_EXTENSION_STATE; this.setState({ state }); } /** * When the user click on the Safari extension link for downloading. * @return {void} */ handleSafariExtensionDownloading() { const state = ApiSetupContextState.CONFIGURE_SAFARI_EXTENSION_STATE; this.setState({ state }); } /** * When the user click on "I didn't download the extension". * @return {void} */ handleSafariExtensionNotDownloaded() { const state = ApiSetupContextState.INSTALL_SAFARI_EXTENSION_STATE; this.setState({ state }); } /** * When the user click on "Already installed extension" button. * @return {void} */ handleExtensionAlreadyInstalled() { const state = ApiSetupContextState.CONFIGURE_SAFARI_EXTENSION_STATE; this.setState({ state }); } /** * When the user asks for logging out before going on with the desired process. * @returns {Promise<void>} */ async logoutUserAndRefresh() { try { await this.authLogoutService.logout(); } catch (e) { const error = new PassboltServiceUnavailableError(e.message); return this.setState({ unexpectedError: error, state: ApiSetupContextState.UNEXPECTED_ERROR_STATE }); } window.location.reload(); } /** * When the setup start failed. * @return {void} */ handleStartSetupError(error) { if (error instanceof PassboltApiFetchError) { const isUserLoggedIn = error.data.code === 403; if (isUserLoggedIn) { return this.setState({ state: ApiSetupContextState.ERROR_ALREADY_SIGNED_IN_STATE }); } const isTokenExpired = Boolean(error.data.body?.token?.expired); const isTokenConsumed = Boolean(error.data.body?.token?.isActive); if (isTokenExpired || isTokenConsumed) { return this.setState({ state: ApiSetupContextState.TOKEN_EXPIRED_STATE }); } if (error?.data?.code === 400) { return this.setState({ state: ApiSetupContextState.REQUEST_INVITATION_ERROR }); } } return this.setState({ state: ApiSetupContextState.UNEXPECTED_ERROR_STATE }); } /** * Check if the browser is supported. * @returns {boolean} */ isBrowserSupported() { const browserName = detectBrowserName(); const supportedBrowserNames = [BROWSER_NAMES.CHROME, BROWSER_NAMES.FIREFOX, BROWSER_NAMES.EDGE]; const isSafariEnabled = this.props.context.siteSettings.canIUse("safari"); if (isSafariEnabled) { supportedBrowserNames.push(BROWSER_NAMES.SAFARI); } return supportedBrowserNames.includes(browserName); } /** * Verify the setup information. * @returns {Promise<object>} */ async startSetup() { const apiClientOptions = this.props.context.getApiClientOptions(); apiClientOptions.setResourceName("setup"); const apiClient = new ApiClient(apiClientOptions); const { body } = await apiClient.get(`install/${this.state.userId}/${this.state.token}`); return body; } /** * Render the component * @returns {JSX} */ render() { return <ApiSetupContext.Provider value={this.state}>{this.props.children}</ApiSetupContext.Provider>; } } ApiSetupContextProvider.propTypes = { context: PropTypes.any, // The application context value: PropTypes.any, // The initial value of the context children: PropTypes.any, // The children components }; export default withAppContext(ApiSetupContextProvider); /** * API Setup Context Consumer HOC * @param WrappedComponent */ export function withApiSetupContext(WrappedComponent) { return class withApiSetupContext extends React.Component { render() { return ( <ApiSetupContext.Consumer> {(context) => <WrappedComponent apiSetupContext={context} {...this.props} />} </ApiSetupContext.Consumer> ); } }; } /** * The setup types of state */ export const ApiSetupContextState = { INITIAL_STATE: "Initial state", DOWNLOAD_SUPPORTED_BROWSER_STATE: "Download supported browser state", INSTALL_EXTENSION_STATE: "Install extension state", INSTALL_SAFARI_EXTENSION_STATE: "Install Safari extension state", CONFIGURE_SAFARI_EXTENSION_STATE: "Configure Safari extension state", TOKEN_EXPIRED_STATE: "Token expired state", ERROR_ALREADY_SIGNED_IN_STATE: "Error, already signed in state", REQUEST_INVITATION_ERROR: "Request inviration error state", UNEXPECTED_ERROR_STATE: "Unexpected error state", };