UNPKG

passbolt-styleguide

Version:

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

336 lines (305 loc) 11.6 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 SelfRegistrationService from "../../shared/services/api/selfRegistration/selfRegistrationService"; import { SelfRegistrationProviderTypes } from "../../shared/models/selfRegistration/SelfRegistrationEnumeration"; import PassboltServiceUnavailableError from "../../shared/lib/Error/PassboltServiceUnavailableError"; import SsoProviders from "../components/Administration/ManageSsoSettings/SsoProviders.data"; /** * The Api triage context. * @type {React.Context<object>} */ export const ApiTriageContext = React.createContext({ unexpectedError: null, // The unexpected error obejct if any state: null, // The current triage workflow state isSsoRecoverEnabled: false, // Is the organization feature flag sso_recover enabled getSsoProviderId: () => {}, // Returns the current SSO provider configured for the organisation onInitializeTriageRequested: () => {}, // Whenever the initialization of the triage is requested. onTriageRequested: () => {}, // Whenever the user wants to submit their username for triage onRegistrationRequested: () => {}, // Whenever the user wants to register handleSwitchToSsoSignInState: () => {}, // Whenever the user switches to SSO_SIGN_IN_STATE state handleSwitchToUsernameState: () => {}, // Whenever the user switches to USERNAME_STATE state handleSwitchToEnterNameState: () => {}, // Whenever the user needs to register after SSO sign in }); /** * The related context provider */ export class ApiTriageContextProvider extends React.Component { /** * Default constructor * @param props The component props */ constructor(props) { super(props); this.state = Object.assign(this.defaultState, props.value); } /** * Returns the default component state */ get defaultState() { this.findSsoProviderId = this.findSsoProviderId.bind(this); return { unexpectedError: null, // The unexpected error obejct if any state: ApiTriageContextState.INITIAL_STATE, isSsoRecoverEnabled: false, ssoProviderId: null, getSsoProviderId: this.getSsoProviderId.bind(this), onInitializeTriageRequested: this.onInitializeTriageRequested.bind(this), onTriageRequested: this.onTriageRequested.bind(this), onRegistrationRequested: this.onRegistrationRequested.bind(this), handleSwitchToSsoSignInState: this.handleSwitchToSsoSignInState.bind(this), handleSwitchToUsernameState: this.handleSwitchToUsernameState.bind(this), handleSwitchToEnterNameState: this.handleSwitchToEnterNameState.bind(this), }; } /** * Initialize the triage */ async onInitializeTriageRequested() { const isSsoRecoverFeatureFlagEnabled = this.isSsoAvailable(); const ssoProviderId = isSsoRecoverFeatureFlagEnabled ? await this.findSsoProviderId() : null; const isSsoRecoverEnabled = isSsoRecoverFeatureFlagEnabled && Boolean(ssoProviderId); this.setState({ ssoProviderId, isSsoRecoverEnabled, state: isSsoRecoverEnabled ? ApiTriageContextState.SSO_SIGN_IN_STATE : ApiTriageContextState.USERNAME_STATE, }); } /** * Returns true if both SSO and SSO recover are enabled. * Both needs to be enabled to find the current settings. * @returns {boolean} */ isSsoAvailable() { return this.props.context.siteSettings.canIUse("ssoRecover") && this.props.context.siteSettings.canIUse("sso"); } /** * Returns the current SSO provider configured for the organisation * @returns {string|null} */ getSsoProviderId() { return this.state.ssoProviderId; } /** * Finds the current SSO provider configuration * @returns {Promise<string|null>} the provider id */ async findSsoProviderId() { const apiClientOptions = this.props.context.getApiClientOptions(); apiClientOptions.setResourceName("sso/settings/current"); const apiClient = new ApiClient(apiClientOptions); let response = null; try { // The feature is enabled, let's check if there's a configuration valid response = await apiClient.findAll(); } catch (e) { // if the feature is disabled, the server should still answer with a 200, something wrong happened here console.error(e); return null; } const providerId = response.body.provider; if (!providerId) { //The feature flag is set but there's no configuration yet return null; } const knownProvider = SsoProviders.find((provider) => provider.id === providerId); if (!knownProvider) { // The provider ID from the API is unknown to the Styleguide const error = new Error("The given SSO provider id is not valid"); console.error(error); return null; } if (knownProvider.disabledForRecover) { // The provider ID from the API is known but is not supported for ssoRecover console.log("Recover processes with this SSO provider is not supported"); return null; } // Everything is fine return providerId; } /** * When the user want to submit their username for triage * @param {string} username The username * @returns {Promise<void>} */ async onTriageRequested(username) { const triageDto = { username }; const apiClientOptions = this.props.context.getApiClientOptions(); apiClientOptions.setResourceName("users/recover"); const apiClient = new ApiClient(apiClientOptions); await apiClient .create(triageDto) .then(this.handleTriageSuccess.bind(this)) .catch((error) => this.handleTriageError(error, username)); } /** * Handle send username success. */ async handleTriageSuccess() { return this.setState({ state: ApiTriageContextState.CHECK_MAILBOX_STATE }); } /** * Handle send username error. */ async handleTriageError(error, username) { const userNotFound = error.data && error.data.code === 404; let nextState = ApiTriageContextState.USERNAME_NOT_FOUND_ERROR; if (userNotFound && this.canIUseSelfRegistrationSettings) { try { await this.isDomainAllowedToSelfRegister(username); nextState = ApiTriageContextState.NAME_STATE; } catch (exception) { const notAllowedErrorResponse = exception.data && (exception.data.code === 400 || exception.data.code === 403); if (!notAllowedErrorResponse) { this.setState({ unexpectedError: new PassboltServiceUnavailableError(exception.message) }); nextState = ApiTriageContextState.UNEXPECTED_ERROR_STATE; } } } this.setState({ username, state: nextState }); /* * @todo handle unexpected error. * else { * console.log(error); * await this.props.actionFeedbackContext.displayError("There was an unexpected error, please retry later..."); * await this.toggleProcessing(); * } */ } /** * When the user wants to register * @param {string} firstName The user first name * @param {string} lastName The user last name * @returns {Promise<Object>} */ async onRegistrationRequested(firstName, lastName) { const registrationDto = { username: this.state.username, profile: { first_name: firstName, last_name: lastName, }, }; this.register(registrationDto); } /** * Handle registration success */ async handleRegistrationSuccess() { return this.setState({ state: ApiTriageContextState.CHECK_MAILBOX_STATE }); } /** * Handle registration error * @returns {Promise<void>} */ async handleRegistrationError() { this.setState({ state: ApiTriageContextState.UNEXPECTED_ERROR_STATE }); } /** * Handle switch to SSO_SIGN_IN_STATE state */ handleSwitchToSsoSignInState() { this.setState({ state: ApiTriageContextState.SSO_SIGN_IN_STATE }); } /** * Handle switch to USERNAME_STATE state */ handleSwitchToUsernameState() { this.setState({ state: ApiTriageContextState.USERNAME_STATE }); } /** * Handle switch to NAME_STATE state * @param {string} username the username to be used for the user registration */ handleSwitchToEnterNameState(username) { this.setState({ username, state: ApiTriageContextState.NAME_STATE, }); } /** * Can I use the self registration settings plugin * @returns {boolean} */ get canIUseSelfRegistrationSettings() { return this.props.context.siteSettings.canIUse("selfRegistration"); } /** * Check if a domain is allowed to self-register * @param {string} username - The email address to check * @returns {Promise<void>} - Resolves if the domain is allowed, rejects otherwise */ async isDomainAllowedToSelfRegister(username) { const apiClientOptions = this.props.context.getApiClientOptions(); const selfRegistrationService = new SelfRegistrationService(apiClientOptions); const payload = { email: username, provider: SelfRegistrationProviderTypes.EMAILDOMAINS }; await selfRegistrationService.checkDomainAllowed(payload); } /** * Register a new user * @param {Object} registrationDto - The registration data * @returns {Promise<void>} - Resolves if the registration is successful, rejects otherwise */ async register(registrationDto) { const apiClientOptions = this.props.context.getApiClientOptions().setResourceName("users/register"); const apiClient = new ApiClient(apiClientOptions); await apiClient .create(registrationDto) .then(this.handleRegistrationSuccess.bind(this)) .catch(this.handleRegistrationError.bind(this)); } /** * Render the component * @returns {JSX} */ render() { return <ApiTriageContext.Provider value={this.state}>{this.props.children}</ApiTriageContext.Provider>; } } ApiTriageContextProvider.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(ApiTriageContextProvider); /** * API Triage Context Consumer HOC * @param WrappedComponent */ export function withApiTriageContext(WrappedComponent) { return class withApiTriageContext extends React.Component { render() { return ( <ApiTriageContext.Consumer> {(context) => <WrappedComponent apiTriageContext={context} {...this.props} />} </ApiTriageContext.Consumer> ); } }; } /** * The triage types of state */ export const ApiTriageContextState = { INITIAL_STATE: "Initial State", USERNAME_STATE: "Enter username state", SSO_SIGN_IN_STATE: "SSO Sign in state", CHECK_MAILBOX_STATE: "Check mailbox state", NAME_STATE: "Enter name state", USERNAME_NOT_FOUND_ERROR: "Username not found error state", UNEXPECTED_ERROR_STATE: "Unexpected error state", };