passbolt-styleguide
Version:
Passbolt styleguide contains common styling assets used by the different sites, plugin, etc.
313 lines (287 loc) • 10.3 kB
JavaScript
/**
* 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 "./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
});
/**
* 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),
};
}
/**
* Initialize the triage
*/
async onInitializeTriageRequested() {
const isSsoRecoverFeatureFlagEnabled = this.props.context.siteSettings.canIUse("ssoRecover");
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 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 {
response = await apiClient.findAll();
} catch (e) {
console.log(e);
this.handleTriageError(e);
return;
}
const providerId = response.body.provider;
const isProviderValid = SsoProviders.some(provider => provider.id === providerId);
if (!isProviderValid) {
const error = new Error("The given SSO provider id is not valid");
console.error(error);
this.handleTriageError(error);
return;
}
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.ERROR_STATE;
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.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});
}
/**
* 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',
NAME_ERROR: 'Error state',
UNEXPECTED_ERROR_STATE: 'Unexpected error state',
};