// Copyright 2021 The Casdoor Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import React, {Component} from "react"; import "./App.less"; import {Helmet} from "react-helmet"; import Dashboard from "./basic/Dashboard"; import ShortcutsPage from "./basic/ShortcutsPage"; import {MfaRuleRequired} from "./Setting"; import * as Setting from "./Setting"; import {StyleProvider, legacyLogicalPropertiesTransformer} from "@ant-design/cssinjs"; import {AppstoreTwoTone, BarsOutlined, DollarTwoTone, DownOutlined, HomeTwoTone, InfoCircleFilled, LockTwoTone, LogoutOutlined, SafetyCertificateTwoTone, SettingOutlined, SettingTwoTone, WalletTwoTone} from "@ant-design/icons"; import {Alert, Avatar, Button, Card, ConfigProvider, Drawer, Dropdown, FloatButton, Layout, Menu, Result} from "antd"; import {Link, Redirect, Route, Switch, withRouter} from "react-router-dom"; import OrganizationListPage from "./OrganizationListPage"; import OrganizationEditPage from "./OrganizationEditPage"; import UserListPage from "./UserListPage"; import UserEditPage from "./UserEditPage"; import RoleListPage from "./RoleListPage"; import RoleEditPage from "./RoleEditPage"; import PermissionListPage from "./PermissionListPage"; import PermissionEditPage from "./PermissionEditPage"; import EnforcerEditPage from "./EnforcerEditPage"; import EnforcerListPage from "./EnforcerListPage"; import GroupTreePage from "./GroupTreePage"; import GroupEditPage from "./GroupEdit"; import GroupListPage from "./GroupList"; import ProviderListPage from "./ProviderListPage"; import ProviderEditPage from "./ProviderEditPage"; import ApplicationListPage from "./ApplicationListPage"; import ApplicationEditPage from "./ApplicationEditPage"; import ResourceListPage from "./ResourceListPage"; import LdapEditPage from "./LdapEditPage"; import LdapSyncPage from "./LdapSyncPage"; import TokenListPage from "./TokenListPage"; import TokenEditPage from "./TokenEditPage"; import WebhookListPage from "./WebhookListPage"; import WebhookEditPage from "./WebhookEditPage"; import SyncerListPage from "./SyncerListPage"; import SyncerEditPage from "./SyncerEditPage"; import CertListPage from "./CertListPage"; import CertEditPage from "./CertEditPage"; import SubscriptionListPage from "./SubscriptionListPage"; import SubscriptionEditPage from "./SubscriptionEditPage"; import PricingListPage from "./PricingListPage"; import PricingEditPage from "./PricingEditPage"; import PlanListPage from "./PlanListPage"; import PlanEditPage from "./PlanEditPage"; import ProductListPage from "./ProductListPage"; import ProductEditPage from "./ProductEditPage"; import ProductBuyPage from "./ProductBuyPage"; import PaymentListPage from "./PaymentListPage"; import PaymentEditPage from "./PaymentEditPage"; import PaymentResultPage from "./PaymentResultPage"; import ModelListPage from "./ModelListPage"; import ModelEditPage from "./ModelEditPage"; import AdapterListPage from "./AdapterListPage"; import AdapterEditPage from "./AdapterEditPage"; import SessionListPage from "./SessionListPage"; import MfaSetupPage from "./auth/MfaSetupPage"; import SystemInfo from "./SystemInfo"; import AccountPage from "./account/AccountPage"; import AppListPage from "./basic/AppListPage"; import CustomGithubCorner from "./common/CustomGithubCorner"; import * as Conf from "./Conf"; import * as Auth from "./auth/Auth"; import EntryPage from "./EntryPage"; import * as AuthBackend from "./auth/AuthBackend"; import AuthCallback from "./auth/AuthCallback"; import OdicDiscoveryPage from "./auth/OidcDiscoveryPage"; import SamlCallback from "./auth/SamlCallback"; import i18next from "i18next"; import {withTranslation} from "react-i18next"; import EnableMfaNotification from "./common/notifaction/EnableMfaNotification"; import LanguageSelect from "./common/select/LanguageSelect"; import ThemeSelect from "./common/select/ThemeSelect"; import OrganizationSelect from "./common/select/OrganizationSelect"; import {clearWeb3AuthToken} from "./auth/Web3Auth"; import AccountAvatar from "./account/AccountAvatar"; import OpenTour from "./common/OpenTour"; const {Header, Footer, Content} = Layout; import {setTwoToneColor} from "@ant-design/icons"; setTwoToneColor("rgb(87,52,211)"); class App extends Component { constructor(props) { super(props); this.state = { classes: props, selectedMenuKey: 0, account: undefined, uri: null, menuVisible: false, themeAlgorithm: ["default"], themeData: Conf.ThemeDefault, logo: this.getLogo(Setting.getAlgorithmNames(Conf.ThemeDefault)), requiredEnableMfa: false, }; Setting.initServerUrl(); Auth.initAuthWithConfig({ serverUrl: Setting.ServerUrl, appName: Conf.DefaultApplication, // the application used in Casdoor root path: "/" }); } UNSAFE_componentWillMount() { this.updateMenuKey(); this.getAccount(); } componentDidUpdate(prevProps, prevState, snapshot) { const uri = location.pathname; if (this.state.uri !== uri) { this.updateMenuKey(); } if (this.state.account !== prevState.account) { const requiredEnableMfa = Setting.isRequiredEnableMfa(this.state.account, this.state.account?.organization); this.setState({ requiredEnableMfa: requiredEnableMfa, }); if (requiredEnableMfa === true) { const mfaType = Setting.getMfaItemsByRules(this.state.account, this.state.account?.organization, [MfaRuleRequired]) .find((item) => item.rule === MfaRuleRequired)?.name; if (mfaType !== undefined) { this.props.history.push(`/mfa/setup?mfaType=${mfaType}`, {from: "/login"}); } } } } updateMenuKey() { const uri = location.pathname; this.setState({ uri: uri, }); if (uri === "/" || uri.includes("/shortcuts") || uri.includes("/apps")) { this.setState({selectedMenuKey: "/home"}); } else if (uri.includes("/organizations") || uri.includes("/trees") || uri.includes("/users") || uri.includes("/groups")) { this.setState({selectedMenuKey: "/orgs"}); } else if (uri.includes("/applications") || uri.includes("/providers") || uri.includes("/resources") || uri.includes("/certs")) { this.setState({selectedMenuKey: "/identity"}); } else if (uri.includes("/roles") || uri.includes("/permissions") || uri.includes("/models") || uri.includes("/adapters") || uri.includes("/enforcers")) { this.setState({selectedMenuKey: "/auth"}); } else if (uri.includes("/records") || uri.includes("/tokens") || uri.includes("/sessions")) { this.setState({selectedMenuKey: "/logs"}); } else if (uri.includes("/products") || uri.includes("/payments") || uri.includes("/plans") || uri.includes("/pricings") || uri.includes("/subscriptions")) { this.setState({selectedMenuKey: "/business"}); } else if (uri.includes("/sysinfo") || uri.includes("/syncers") || uri.includes("/webhooks")) { this.setState({selectedMenuKey: "/admin"}); } else if (uri.includes("/signup")) { this.setState({selectedMenuKey: "/signup"}); } else if (uri.includes("/login")) { this.setState({selectedMenuKey: "/login"}); } else if (uri.includes("/result")) { this.setState({selectedMenuKey: "/result"}); } else { this.setState({selectedMenuKey: -1}); } } getAccessTokenParam(params) { // "/page?access_token=123" const accessToken = params.get("access_token"); return accessToken === null ? "" : `?accessToken=${accessToken}`; } getCredentialParams(params) { // "/page?username=abc&password=123" if (params.get("username") === null || params.get("password") === null) { return ""; } return `?username=${params.get("username")}&password=${params.get("password")}`; } getUrlWithoutQuery() { return window.location.toString().replace(window.location.search, ""); } getLanguageParam(params) { // "/page?language=en" const language = params.get("language"); if (language !== null) { Setting.setLanguage(language); return `language=${language}`; } return ""; } getLogo(themes) { if (themes.includes("dark")) { return `${Setting.StaticBaseUrl}/img/casdoor-logo_1185x256_dark.png`; } else { return `${Setting.StaticBaseUrl}/img/casdoor-logo_1185x256.png`; } } setLanguage(account) { const language = account?.language; if (language !== null && language !== "" && language !== i18next.language) { Setting.setLanguage(language); } } setTheme = (theme, initThemeAlgorithm) => { this.setState({ themeData: theme, }); if (initThemeAlgorithm) { this.setState({ logo: this.getLogo(Setting.getAlgorithmNames(theme)), themeAlgorithm: Setting.getAlgorithmNames(theme), }); } }; getAccount() { const params = new URLSearchParams(this.props.location.search); let query = this.getAccessTokenParam(params); if (query === "") { query = this.getCredentialParams(params); } const query2 = this.getLanguageParam(params); if (query2 !== "") { const url = window.location.toString().replace(new RegExp(`[?&]${query2}`), ""); window.history.replaceState({}, document.title, url); } if (query !== "") { window.history.replaceState({}, document.title, this.getUrlWithoutQuery()); } AuthBackend.getAccount(query) .then((res) => { let account = null; if (res.status === "ok") { account = res.data; account.organization = res.data2; this.setLanguage(account); this.setTheme(Setting.getThemeData(account.organization), Conf.InitThemeAlgorithm); } else { if (res.data !== "Please login first") { Setting.showMessage("error", `${i18next.t("application:Failed to sign in")}: ${res.msg}`); } } this.setState({ account: account, }); }); } logout() { this.setState({ expired: false, submitted: false, }); AuthBackend.logout() .then((res) => { if (res.status === "ok") { const owner = this.state.account.owner; this.setState({ account: null, themeAlgorithm: ["default"], }); clearWeb3AuthToken(); Setting.showMessage("success", i18next.t("application:Logged out successfully")); const redirectUri = res.data2; if (redirectUri !== null && redirectUri !== undefined && redirectUri !== "") { Setting.goToLink(redirectUri); } else if (owner !== "built-in") { Setting.goToLink(`${window.location.origin}/login/${owner}`); } else { Setting.goToLinkSoft(this, "/"); } } else { Setting.showMessage("error", `Failed to log out: ${res.msg}`); } }); } onUpdateAccount(account) { this.setState({ account: account, }); } renderAvatar() { if (this.state.account.avatar === "") { return ( {Setting.getShortName(this.state.account.name)} ); } else { return ( } > {Setting.getShortName(this.state.account.name)} ); } } renderRightDropdown() { const items = []; if (this.state.requiredEnableMfa === false) { items.push(Setting.getItem(<>  {i18next.t("account:My Account")}, "/account" )); } items.push(Setting.getItem(<>  {i18next.t("account:Logout")}, "/logout")); const onClick = (e) => { if (e.key === "/account") { this.props.history.push("/account"); } else if (e.key === "/subscription") { this.props.history.push("/subscription"); } else if (e.key === "/logout") { this.logout(); } }; return (
{ this.renderAvatar() }     {Setting.isMobile() ? null : Setting.getShortText(Setting.getNameAtLeast(this.state.account.displayName), 30)}        
); } renderAccountMenu() { if (this.state.account === undefined) { return null; } else if (this.state.account === null) { return null; } else { return ( {this.renderRightDropdown()} { this.setState({ themeAlgorithm: nextThemeAlgorithm, logo: this.getLogo(nextThemeAlgorithm), }); }} /> {Setting.isAdminUser(this.state.account) && !Setting.isMobile() && { Setting.setOrganization(value); }} className="select-box" /> } ); } } getMenuItems() { const res = []; if (this.state.account === null || this.state.account === undefined) { return []; } res.push(Setting.getItem({i18next.t("general:Home")}, "/home", , [ Setting.getItem({i18next.t("general:Dashboard")}, "/"), Setting.getItem({i18next.t("general:Shortcuts")}, "/shortcuts"), Setting.getItem({i18next.t("general:Apps")}, "/apps"), ].filter(item => { return Setting.isLocalAdminUser(this.state.account); }))); if (Setting.isLocalAdminUser(this.state.account)) { if (Conf.ShowGithubCorner) { res.push(Setting.getItem( 🚀 SaaS Hosting 🔥 , "#")); } res.push(Setting.getItem({i18next.t("general:User Management")}, "/orgs", , [ Setting.getItem({i18next.t("general:Organizations")}, "/organizations"), Setting.getItem({i18next.t("general:Groups")}, "/groups"), Setting.getItem({i18next.t("general:Users")}, "/users"), ])); res.push(Setting.getItem({i18next.t("general:Identity")}, "/identity", , [ Setting.getItem({i18next.t("general:Applications")}, "/applications"), Setting.getItem({i18next.t("general:Providers")}, "/providers"), Setting.getItem({i18next.t("general:Resources")}, "/resources"), Setting.getItem({i18next.t("general:Certs")}, "/certs"), ])); res.push(Setting.getItem({i18next.t("general:Authorization")}, "/auth", , [ Setting.getItem({i18next.t("general:Roles")}, "/roles"), Setting.getItem({i18next.t("general:Permissions")}, "/permissions"), Setting.getItem({i18next.t("general:Models")}, "/models"), Setting.getItem({i18next.t("general:Adapters")}, "/adapters"), Setting.getItem({i18next.t("general:Enforcers")}, "/enforcers"), ].filter(item => { if (!Setting.isLocalAdminUser(this.state.account) && ["/models", "/adapters", "/enforcers"].includes(item.key)) { return false; } else { return true; } }))); res.push(Setting.getItem({i18next.t("general:Logging & Auditing")}, "/logs", , [ Setting.getItem({i18next.t("general:Sessions")}, "/sessions"), Setting.getItem({i18next.t("general:Records")}, "/records"), Setting.getItem({i18next.t("general:Tokens")}, "/tokens"), ])); res.push(Setting.getItem({i18next.t("general:Business & Payments")}, "/business", , [ Setting.getItem({i18next.t("general:Products")}, "/products"), Setting.getItem({i18next.t("general:Payments")}, "/payments"), Setting.getItem({i18next.t("general:Plans")}, "/plans"), Setting.getItem({i18next.t("general:Pricings")}, "/pricings"), Setting.getItem({i18next.t("general:Subscriptions")}, "/subscriptions"), ])); if (Setting.isAdminUser(this.state.account)) { res.push(Setting.getItem({i18next.t("general:Admin")}, "/admin", , [ Setting.getItem({i18next.t("general:System Info")}, "/sysinfo"), Setting.getItem({i18next.t("general:Syncers")}, "/syncers"), Setting.getItem({i18next.t("general:Webhooks")}, "/webhooks"), Setting.getItem({i18next.t("general:Swagger")}, "/swagger")])); } else { res.push(Setting.getItem({i18next.t("general:Admin")}, "/admin", , [ Setting.getItem({i18next.t("general:Syncers")}, "/syncers"), Setting.getItem({i18next.t("general:Webhooks")}, "/webhooks")])); } } return res; } renderLoginIfNotLoggedIn(component) { if (this.state.account === null) { sessionStorage.setItem("from", window.location.pathname); return ; } else if (this.state.account === undefined) { return null; } else { return component; } } renderRouter() { return ( this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> } /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> {/* this.renderLoginIfNotLoggedIn()}/>*/} this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn()} /> this.renderLoginIfNotLoggedIn( this.setState({requiredEnableMfa: false})} {...props} />)} /> } /> this.renderLoginIfNotLoggedIn()} /> } />} /> ); } onClose = () => { this.setState({ menuVisible: false, }); }; showMenu = () => { this.setState({ menuVisible: true, }); }; isWithoutCard() { return Setting.isMobile() || window.location.pathname.startsWith("/trees"); } renderContent() { const onClick = ({key}) => { if (key !== "/swagger" && key !== "/records") { if (this.state.requiredEnableMfa) { Setting.showMessage("info", "Please enable MFA first!"); } else { this.props.history.push(key); } } }; const menuStyleRight = Setting.isAdminUser(this.state.account) && !Setting.isMobile() ? "calc(180px + 280px)" : "280px"; return (
{Setting.isMobile() ? null : (
)} {this.state.requiredEnableMfa || (Setting.isMobile() ? : )} { this.renderAccountMenu() }
{this.isWithoutCard() ? this.renderRouter() : {this.renderRouter()} } {this.renderFooter()}
); } renderFooter() { return ( {!this.state.account ? null :
}
{ Conf.CustomFooter !== null ? Conf.CustomFooter : ( Powered by {"Casdoor"} ) }
); } isDoorPages() { return this.isEntryPages() || window.location.pathname.startsWith("/callback"); } isEntryPages() { return window.location.pathname.startsWith("/signup") || window.location.pathname.startsWith("/login") || window.location.pathname.startsWith("/forget") || window.location.pathname.startsWith("/prompt") || window.location.pathname.startsWith("/result") || window.location.pathname.startsWith("/cas") || window.location.pathname.startsWith("/auto-signup") || window.location.pathname.startsWith("/select-plan") || window.location.pathname.startsWith("/buy-plan") || window.location.pathname.startsWith("/qrcode") ; } renderPage() { if (this.isDoorPages()) { return ( { this.isEntryPages() ? { localStorage.setItem("mfaRedirectUrl", redirectUrl); this.getAccount(); }} onUpdateAccount={(account) => this.onUpdateAccount(account)} updataThemeData={this.setTheme} /> : } />} /> } { this.renderFooter() } ); } return ( {/* { */} {/* this.renderBanner() */} {/* } */} { this.renderContent() } ); } renderBanner() { if (!Conf.IsDemoMode) { return null; } const language = Setting.getLanguage(); if (language === "en" || language === "zh") { return null; } return (    {i18next.t("general:Found some texts still not translated? Please help us translate at")}   Crowdin  ! 🙏
} /> ); } render() { return ( {(this.state.account === undefined || this.state.account === null) ? : {this.state.account.organization?.displayName} } { this.renderPage() } ); } } export default withRouter(withTranslation()(App));