passbolt-styleguide
Version:
Passbolt styleguide contains common styling assets used by the different sites, plugin, etc.
317 lines (287 loc) • 13 kB
JavaScript
import browser from "webextension-polyfill";
import React from "react";
import AppContext from "./contexts/AppContext";
import FilterResourcesByFavoritePage from "./components/FilterResourcesByFavoritePage/FilterResourcesByFavoritePage";
import FilterResourcesByItemsIOwnPage from "./components/FilterResourcesByItemsIOwnPage/FilterResourcesByItemsIOwnPage";
import FilterResourcesByGroupPage from "./components/FilterResourcesByGroupPage/FilterResourcesByGroupPage";
import FilterResourcesByRecentlyModifiedPage
from "./components/FilterResourcesByRecentlyModifiedPage/FilterResourcesByRecentlyModifiedPage";
import FilterResourcesBySharedWithMePage
from "./components/FilterResourcesBySharedWithMePage/FilterResourcesBySharedWithMePage";
import FilterResourcesByTagPage from "./components/FilterResourcesByTagPage/FilterResourcesByTagPage";
import Header from "./components/Header/Header";
import HomePage from "./components/HomePage/HomePage";
import LoginPage from "./components/LoginPage/LoginPage";
import MoreFiltersPage from "./components/MoreFiltersPage/MoreFiltersPage";
import ResourceCreatePage from "./components/ResourceCreatePage/ResourceCreatePage";
import ResourceViewPage from "./components/ResourceViewPage/ResourceViewPage";
import Search from "./components/Search/Search";
import {BrowserRouter as Router, Route} from "react-router-dom";
import AnimatedSwitch from "./components/AnimatedSwitch/AnimatedSwitch";
import PassphraseDialog from "./components/PassphraseDialog/PassphraseDialog";
import PropTypes from "prop-types";
import SiteSettings from "../shared/lib/Settings/SiteSettings";
import UserSettings from "../shared/lib/Settings/UserSettings";
import TranslationProvider from "../shared/components/Internationalisation/TranslationProvider";
import SetupExtensionInProgress from "./components/ExtensionSetup/SetupExtensionInProgress/SetupExtensionInProgress";
import ManageQuickAccessMode from "./components/ManageQuickAccessMode/ManageQuickAccessMode";
import PrivateRoute from "./components/PrivateRoute/PrivateRoute";
import SaveResource from "./components/ResourceAutoSave/SaveResource";
import GeneratePasswordPage from "./components/GeneratePasswordPage/GeneratePasswordPage";
import PrepareResourceContextProvider from "./contexts/PrepareResourceContext";
import Icon from "../shared/components/Icons/Icon";
import SsoContextProvider from "./contexts/SsoContext";
const SEARCH_VISIBLE_ROUTES = [
'/webAccessibleResources/quickaccess.html',
'/webAccessibleResources/quickaccess/resources/favorite',
'/webAccessibleResources/quickaccess/resources/group',
'/webAccessibleResources/quickaccess/resources/owned-by-me',
'/webAccessibleResources/quickaccess/resources/recently-modified',
'/webAccessibleResources/quickaccess/resources/shared-with-me',
'/webAccessibleResources/quickaccess/resources/tag'
];
const PASSBOLT_GETTING_STARTED_URL = "https://www.passbolt.com/start";
class ExtQuickAccess extends React.Component {
constructor(props) {
super(props);
this.searchRef = React.createRef();
this.bindCallbacks();
this.state = this.initState(props);
}
/**
* Can the user use the remember until I logout option
* @return {boolean}
*/
get canRememberMe() {
const options = this.state.siteSettings.getRememberMeOptions();
return options !== null && Object.keys(options).length > 0;
}
bindCallbacks() {
this.focusSearch = this.focusSearch.bind(this);
this.updateSearch = this.updateSearch.bind(this);
this.handlekeyDown = this.handleKeyDown.bind(this);
this.handleBackgroundPageRequiresPassphraseEvent = this.handleBackgroundPageRequiresPassphraseEvent.bind(this);
this.handlePassphraseDialogCompleted = this.handlePassphraseDialogCompleted.bind(this);
this.loginSuccessCallback = this.loginSuccessCallback.bind(this);
this.logoutSuccessCallback = this.logoutSuccessCallback.bind(this);
this.mfaRequiredCallback = this.mfaRequiredCallback.bind(this);
}
async componentDidMount() {
try {
this.state.port.on('passbolt.passphrase.request', this.handleBackgroundPageRequiresPassphraseEvent);
this.handlePassphraseRequest();
await this.checkPluginIsConfigured();
await this.getUser();
await this.checkAuthStatus();
await this.getSiteSettings();
this.getLocale();
} catch (e) {
this.setState({
hasError: true,
errorMessage: e.message
});
}
}
initState(props) {
return {
storage: props.storage,
port: props.port,
isAuthenticated: null,
userSettings: null,
siteSettings: null,
hasError: false,
errorMessage: "",
locale: "en-UK", // To avoid any weird blink, launch the quickaccess with a default english locale
// Search
search: "",
searchHistory: {},
updateSearch: this.updateSearch,
focusSearch: this.focusSearch,
// Passphrase
passphraseRequired: false,
passphraseRequestId: '',
// Tab id to refer to the good one if detached mode
tabId: this.getTabIdFromUrl(),
};
}
/**
* Get the tabId from URL
* @returns {string}
*/
getTabIdFromUrl() {
const queryParameters = new URLSearchParams(window.location.search);
return queryParameters.get('tabId');
}
updateSearch(search) {
this.setState({search});
}
focusSearch() {
if (this.searchRef.current) {
this.searchRef.current.focus();
}
}
async checkPluginIsConfigured() {
const isConfigured = await this.state.port.request('passbolt.addon.is-configured');
if (!isConfigured) {
browser.tabs.create({url: PASSBOLT_GETTING_STARTED_URL});
window.close();
}
}
async getUser() {
const storageData = await this.props.storage.local.get(["_passbolt_data"]);
const userSettings = new UserSettings(storageData._passbolt_data.config);
this.setState({userSettings});
}
async getSiteSettings() {
const siteSettingsDto = await this.state.port.request('passbolt.organization-settings.get');
const siteSettings = new SiteSettings(siteSettingsDto);
this.setState({siteSettings});
}
async getLocale() {
const {locale} = await this.state.port.request("passbolt.locale.get");
this.setState({locale});
}
/**
* Is feature is present
* @param feature {string}
* @returns {boolean}
*/
isInFeature(feature) {
const queryParameters = new URLSearchParams(window.location.search);
return queryParameters.get("feature") === feature;
}
/**
* Retrieve the authentication status.
*
* If the user is authenticated but the MFA challenge is required, close the quickaccess and redirect the user to
* the passbolt application.
*
* This function requires the user settings to be present in the component state.
* @returns {Promise<void>}
*/
async checkAuthStatus() {
const {isAuthenticated, isMfaRequired} = await this.state.port.request("passbolt.auth.check-status");
if (isMfaRequired) {
this.redirectToMfaAuthentication();
return;
}
this.setState({isAuthenticated});
}
redirectToMfaAuthentication() {
browser.tabs.create({url: this.state.userSettings.getTrustedDomain()});
window.close();
}
loginSuccessCallback() {
if (!this.isInFeature('login')) {
this.getSiteSettings();
this.setState({isAuthenticated: true});
} else {
window.close();
}
}
logoutSuccessCallback() {
this.setState({isAuthenticated: false});
}
mfaRequiredCallback(url) {
browser.tabs.create({url});
window.close();
}
handleKeyDown(event) {
// Close the quickaccess popup when the user presses the "ESC" key.
if (event.keyCode === 27) {
window.close();
}
}
handleBackgroundPageRequiresPassphraseEvent(requestId) {
this.setState({passphraseRequired: true, passphraseRequestId: requestId});
}
handlePassphraseDialogCompleted() {
if (this.isInFeature("request-passphrase")) {
window.close();
} else {
this.setState({passphraseRequired: false, passphraseRequestId: null});
}
}
handlePassphraseRequest() {
if (this.isInFeature("request-passphrase")) {
const queryParameters = new URLSearchParams(window.location.search);
this.handleBackgroundPageRequiresPassphraseEvent(queryParameters.get("requestId"));
}
}
isReady() {
return this.state.isAuthenticated !== null
&& this.state.userSettings !== null
&& this.state.siteSettings != null
&& this.state.locale !== null;
}
render() {
const isReady = this.isReady();
return (
<AppContext.Provider value={this.state}>
<TranslationProvider loadingPath="/webAccessibleResources/locales/{{lng}}/{{ns}}.json" locale={this.state?.locale}>
<Router>
<div className="container quickaccess" onKeyDown={this.handleKeyDown}>
<Header logoutSuccessCallback={this.logoutSuccessCallback}/>
{!isReady && !this.state.hasError &&
<div className="processing-wrapper">
<Icon name="spinner"/>
<p className="processing-text">Connecting your account</p>
</div>
}
{this.state.hasError &&
<div className="processing-wrapper">
<p className="processing-text">{this.state.errorMessage}</p>
</div>
}
{isReady &&
<React.Fragment>
<ManageQuickAccessMode/>
{this.state.passphraseRequired &&
<PassphraseDialog requestId={this.state.passphraseRequestId} onComplete={this.handlePassphraseDialogCompleted}/>
}
<div className={`${this.state.passphraseRequired ? "visually-hidden" : ""}`}>
<Route path={SEARCH_VISIBLE_ROUTES} render={() => (
<Search ref={el => this.searchRef = el}/>
)}/>
<PrepareResourceContextProvider>
<AnimatedSwitch>
<Route path="/webAccessibleResources/quickaccess/login" render={() => (
<SsoContextProvider>
<LoginPage
loginSuccessCallback={this.loginSuccessCallback}
mfaRequiredCallback={this.mfaRequiredCallback}
canRememberMe={this.canRememberMe}/>
</SsoContextProvider>
)}/>
<PrivateRoute exact path="/webAccessibleResources/quickaccess/resources/group" component={FilterResourcesByGroupPage}/>
<PrivateRoute path="/webAccessibleResources/quickaccess/resources/group/:id" component={FilterResourcesByGroupPage}/>
<PrivateRoute exact path="/webAccessibleResources/quickaccess/resources/tag" component={FilterResourcesByTagPage}/>
<PrivateRoute path="/webAccessibleResources/quickaccess/resources/tag/:id" component={FilterResourcesByTagPage}/>
<PrivateRoute exact path="/webAccessibleResources/quickaccess/resources/favorite" component={FilterResourcesByFavoritePage}/>
<PrivateRoute exact path="/webAccessibleResources/quickaccess/resources/owned-by-me" component={FilterResourcesByItemsIOwnPage}/>
<PrivateRoute exact path="/webAccessibleResources/quickaccess/resources/recently-modified" component={FilterResourcesByRecentlyModifiedPage}/>
<PrivateRoute exact path="/webAccessibleResources/quickaccess/resources/shared-with-me" component={FilterResourcesBySharedWithMePage}/>
<PrivateRoute path="/webAccessibleResources/quickaccess/resources/create" component={ResourceCreatePage}/>
<PrivateRoute exact path="/webAccessibleResources/quickaccess/resources/autosave" component={SaveResource}/>
<PrivateRoute path="/webAccessibleResources/quickaccess/resources/view/:id" component={ResourceViewPage}/>
<PrivateRoute exact path="/webAccessibleResources/quickaccess/more-filters" component={MoreFiltersPage}/>
<PrivateRoute exact path="/webAccessibleResources/quickaccess/setup-extension-in-progress" component={SetupExtensionInProgress}/>
<PrivateRoute path="/webAccessibleResources/quickaccess/resources/generate-password" component={GeneratePasswordPage}/>
<PrivateRoute exact path="/webAccessibleResources/quickaccess.html" component={HomePage}/>
</AnimatedSwitch>
</PrepareResourceContextProvider>
</div>
</React.Fragment>
}
</div>
</Router>
</TranslationProvider>
</AppContext.Provider>
);
}
}
ExtQuickAccess.propTypes = {
port: PropTypes.object,
storage: PropTypes.object,
};
export default ExtQuickAccess;