From e425b0794943e8d0605a7f5368f1d94acf8d9d71 Mon Sep 17 00:00:00 2001 From: PoeppingT Date: Wed, 30 Nov 2022 14:29:47 -0800 Subject: [PATCH] Fix signout in admin web app. (#439) This commit also includes a large-scale cleanup of unnecessary JS in the admin web app, deleting files that are unused in an effort to simplify the JS application. Fixes #432 Co-authored-by: PoeppingT Co-authored-by: brtrvn --- client/web/src/AppWithAuth.js | 4 +- .../blueprints/DefaultLayout/DefaultFooter.js | 49 ---- .../blueprints/DefaultLayout/DefaultHeader.js | 70 ----- .../blueprints/DefaultLayout/DefaultLayout.js | 192 ------------- .../web/src/blueprints/DefaultLayout/index.js | 19 -- .../web/src/blueprints/LeftSidebar/index.js | 72 ----- .../web/src/blueprints/MinimalLayout/index.js | 31 -- client/web/src/blueprints/index.js | 18 -- .../components/Auth/CurrentUserComponent.js | 39 --- .../components/Auth/CurrentUserContainer.js | 25 -- .../components/Auth/SaasBoostAuthComponent.js | 169 ----------- .../Auth/SaasBoostChangePassword1.js | 169 ----------- .../Auth/SaasBoostForgotPassword.js | 126 --------- .../src/components/Auth/SaasBoostLoading.js | 36 --- .../Auth/SaasBoostRequireNewPassword.js | 133 --------- .../components/Auth/SaasBoostResetPassword.js | 153 ---------- .../src/components/Auth/SaasBoostSignIn.js | 267 ------------------ .../src/components/Auth/SaasBoostSignOut.js | 30 -- .../components/Auth/SaasBoostVerifyContact.js | 166 ----------- .../src/components/Layout/Sidebar/index.js | 60 ---- client/web/src/index.js | 1 + client/web/src/layout/DefaultLayout.js | 10 +- 22 files changed, 12 insertions(+), 1827 deletions(-) delete mode 100644 client/web/src/blueprints/DefaultLayout/DefaultFooter.js delete mode 100644 client/web/src/blueprints/DefaultLayout/DefaultHeader.js delete mode 100644 client/web/src/blueprints/DefaultLayout/DefaultLayout.js delete mode 100644 client/web/src/blueprints/DefaultLayout/index.js delete mode 100644 client/web/src/blueprints/LeftSidebar/index.js delete mode 100644 client/web/src/blueprints/MinimalLayout/index.js delete mode 100644 client/web/src/blueprints/index.js delete mode 100644 client/web/src/components/Auth/CurrentUserComponent.js delete mode 100644 client/web/src/components/Auth/CurrentUserContainer.js delete mode 100644 client/web/src/components/Auth/SaasBoostAuthComponent.js delete mode 100644 client/web/src/components/Auth/SaasBoostChangePassword1.js delete mode 100644 client/web/src/components/Auth/SaasBoostForgotPassword.js delete mode 100644 client/web/src/components/Auth/SaasBoostLoading.js delete mode 100644 client/web/src/components/Auth/SaasBoostRequireNewPassword.js delete mode 100644 client/web/src/components/Auth/SaasBoostResetPassword.js delete mode 100644 client/web/src/components/Auth/SaasBoostSignIn.js delete mode 100644 client/web/src/components/Auth/SaasBoostSignOut.js delete mode 100644 client/web/src/components/Auth/SaasBoostVerifyContact.js delete mode 100644 client/web/src/components/Layout/Sidebar/index.js diff --git a/client/web/src/AppWithAuth.js b/client/web/src/AppWithAuth.js index 35ec00de..5dde586a 100644 --- a/client/web/src/AppWithAuth.js +++ b/client/web/src/AppWithAuth.js @@ -35,7 +35,9 @@ const AppWithAuth = () => { try { const signOutReason = `Session closed due to ${minutes} minutes of inactivity.` setSignOutReason(signOutReason) - return auth.removeUser() + await auth.signoutRedirect() + await auth.removeUser() + return removeUserInfo() } catch (e) { // do nothing } diff --git a/client/web/src/blueprints/DefaultLayout/DefaultFooter.js b/client/web/src/blueprints/DefaultLayout/DefaultFooter.js deleted file mode 100644 index 768164f5..00000000 --- a/client/web/src/blueprints/DefaultLayout/DefaultFooter.js +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. 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 PropTypes from "prop-types"; -import { useSelector } from "react-redux"; -import { selectSettingsById } from "../../settings/ducks"; -import * as SETTINGS from "../../settings/common"; - -const propTypes = { - children: PropTypes.node, -}; - -const DefaultFooter = (props) => { - // eslint-disable-next-line - const { children, ...attributes } = props; - const version = useSelector((state) => - selectSettingsById(state, SETTINGS.VERSION) - ); - const saasBoostEnvironment = useSelector((state) => - selectSettingsById(state, "SAAS_BOOST_ENVIRONMENT") - ); - - return ( - - - AWS © Amazon.com, Inc. - - - Version {version?.value} - {saasBoostEnvironment?.value} - - - ); -}; - -export default DefaultFooter; diff --git a/client/web/src/blueprints/DefaultLayout/DefaultHeader.js b/client/web/src/blueprints/DefaultLayout/DefaultHeader.js deleted file mode 100644 index 3e1645ab..00000000 --- a/client/web/src/blueprints/DefaultLayout/DefaultHeader.js +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. 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 { - UncontrolledDropdown, - DropdownItem, - DropdownMenu, - DropdownToggle, -} from 'reactstrap' -import PropTypes from 'prop-types' - -const propTypes = { - children: PropTypes.node, -} - -const defaultProps = {} - -class DefaultHeader extends Component { - render() { - // eslint-disable-next-line - const { handleProfileClick, handleChangePasswordClick, user } = this.props - return ( - <> - - -
- - {user?.username} - -
-
- - - Settings - - handleProfileClick()}> - Profile - - - handleChangePasswordClick()}> - Change Password - - this.props.onLogout(e)}> - Sign Out - - -
- - ) - } -} -DefaultHeader.propTypes = propTypes -DefaultHeader.defaultProps = defaultProps - -export default DefaultHeader diff --git a/client/web/src/blueprints/DefaultLayout/DefaultLayout.js b/client/web/src/blueprints/DefaultLayout/DefaultLayout.js deleted file mode 100644 index ea6d9b7d..00000000 --- a/client/web/src/blueprints/DefaultLayout/DefaultLayout.js +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. 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, Suspense } from "react"; -import { withRouter, Switch, Route, Redirect } from "react-router-dom"; -import * as router from "react-router-dom"; -import { Container } from "reactstrap"; -import { Auth } from "aws-amplify"; -import { connect } from "react-redux"; -import { fetchSettings, fetchConfig } from "../../settings/ducks"; - -import { - AppAside, - AppFooter, - AppHeader, - AppSidebar, - AppSidebarFooter, - AppSidebarForm, - AppSidebarHeader, - AppSidebarMinimizer, - AppBreadcrumb2 as AppBreadcrumb, - AppSidebarNav2 as AppSidebarNav, -} from "@coreui/react"; - -// sidebar nav config -import navigation from "../../_nav"; -// routes config -import routes from "../../routes/extras"; - -const DefaultHeader = React.lazy(() => import("./DefaultHeader")); -const DefaultFooter = React.lazy(() => import("./DefaultFooter")); -const SaasBoostChangePassword = React.lazy(() => - import("../../components/Auth/SaasBoostChangePassword1") -); - -const mapStateToProps = (state) => { - return { settings: state.settings, setup: state.settings.setup }; -}; - -class DefaultLayout extends Component { - constructor(props) { - super(props); - this.state = { - showChangePassword: false, - user: undefined, - }; - - this.handleSignOut = this.handleSignOut.bind(this); - this.handleProfileClick = this.handleProfileClick.bind(this); - this.showChangePassword = this.showChangePassword.bind(this); - this.closeChangePassword = this.closeChangePassword.bind(this); - } - - async componentDidMount() { - const user = await Auth.currentUserInfo(); - this.setState((state, props) => { - return { - user: user, - }; - }); - } - - handleSignOut = async () => { - await Auth.signOut(); - }; - - handleProfileClick = () => { - const { history } = this.props; - try { - const userInfo = this.state.user; - history.push(`/users/${userInfo.username}`); - } catch (err) { - console.error(err); - } - }; - - showChangePassword = () => { - this.setState((state) => { - return { - showChangePassword: true, - }; - }); - }; - - closeChangePassword = () => { - this.setState((state) => { - return { - showChangePassword: false, - }; - }); - }; - - loading = () => ( -
Loading...
- ); - - render() { - const { showChangePassword, user } = this.state; - const { setup, location } = this.props; - if (!setup) { - navigation.items.forEach((nav, index) => { - if (nav.name === "Application") { - navigation.items[index].badge = {}; - } - - if (nav.name === "Onboarding") { - navigation.items[index].attributes.disabled = false; - } - - if (nav.name === "Tenants") { - navigation.items[index].attributes.disabled = false; - } - }); - } - return ( -
- - - - - -
- - - - - - - - - -
- - - - - {routes.map((route, idx) => { - return route.component ? ( - } - /> - ) : null; - })} - - - - - -
-
- - - - - - -
- ); - } -} - -export default connect(mapStateToProps, null)(withRouter(DefaultLayout)); diff --git a/client/web/src/blueprints/DefaultLayout/index.js b/client/web/src/blueprints/DefaultLayout/index.js deleted file mode 100644 index ba75ebb3..00000000 --- a/client/web/src/blueprints/DefaultLayout/index.js +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. 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 DefaultLayout from "./DefaultLayout"; - -export default DefaultLayout; diff --git a/client/web/src/blueprints/LeftSidebar/index.js b/client/web/src/blueprints/LeftSidebar/index.js deleted file mode 100644 index e1c2e9f5..00000000 --- a/client/web/src/blueprints/LeftSidebar/index.js +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. 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 from "react"; - -import PropTypes from "prop-types"; -import { Navbar, Nav, Container } from "react-bootstrap"; - -import Sidebar from "../../components/Layout/Sidebar"; -import CurrentUserContainer from "../../components/Auth/CurrentUserContainer"; - -const LeftSidebar = (props) => { - const { children } = props; - - return ( -
- - - APN SaaS Factory - - - - - - - - - -
- - -
-
- ); -}; - -LeftSidebar.propTypes = { - children: PropTypes.node, -}; - -export default LeftSidebar; diff --git a/client/web/src/blueprints/MinimalLayout/index.js b/client/web/src/blueprints/MinimalLayout/index.js deleted file mode 100644 index fbf84e47..00000000 --- a/client/web/src/blueprints/MinimalLayout/index.js +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. 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, { Fragment } from "react"; - -import PropTypes from "prop-types"; - -const MinimalLayout = (props) => { - const { children } = props; - - return {children}; -}; - -MinimalLayout.propTypes = { - children: PropTypes.node, -}; - -export default MinimalLayout; diff --git a/client/web/src/blueprints/index.js b/client/web/src/blueprints/index.js deleted file mode 100644 index b2fb06d0..00000000 --- a/client/web/src/blueprints/index.js +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. 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. - */ - -export { default as MinimalLayout } from "./MinimalLayout"; -export { default as LeftSidebar } from "./LeftSidebar"; diff --git a/client/web/src/components/Auth/CurrentUserComponent.js b/client/web/src/components/Auth/CurrentUserComponent.js deleted file mode 100644 index 82d9b177..00000000 --- a/client/web/src/components/Auth/CurrentUserComponent.js +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. 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, { Fragment } from "react"; -import { Button } from "react-bootstrap"; - -export default function CurrentUserComponent(props) { - const { username, handleSignOut } = props; - - console.log(username); - - return ( - - - Signed in as: {username} - - - - ); -} diff --git a/client/web/src/components/Auth/CurrentUserContainer.js b/client/web/src/components/Auth/CurrentUserContainer.js deleted file mode 100644 index ab5c1ab0..00000000 --- a/client/web/src/components/Auth/CurrentUserContainer.js +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. 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 from 'react' - -import SaasBoostSignOut from './SaasBoostSignOut' - -function CurrentUserContainer() { - return -} - -export default CurrentUserContainer diff --git a/client/web/src/components/Auth/SaasBoostAuthComponent.js b/client/web/src/components/Auth/SaasBoostAuthComponent.js deleted file mode 100644 index e0642454..00000000 --- a/client/web/src/components/Auth/SaasBoostAuthComponent.js +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. 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 { PropTypes } from 'prop-types' -import React, { Component } from 'react' -import { SBInput } from './SaasBoostSignIn' -import { Alert } from 'reactstrap' -import { Auth } from '@aws-amplify/auth' -import { isEmpty } from '@aws-amplify/core' -import { cilEnvelopeClosed, cilUser } from '@coreui/icons' - -const UsernameAttributes = { - EMAIL: 'email', - PHONE_NUMBER: 'phone_number', - USERNAME: 'username', -} - -export class SaasBoostAuthComponent extends Component { - _validAuthStates = [] - constructor(props) { - super(props) - this.state = {} - - this._validAuthStates = [] - this.inputs = {} - this.changeState = this.changeState.bind(this) - this.error = this.error.bind(this) - this.handleInputChange = this.handleInputChange.bind(this) - this.renderUsernameField = this.renderUsernameField.bind(this) - this.getUsernameFromInput = this.getUsernameFromInput.bind(this) - this.dismiss = this.dismiss.bind(this) - this.checkContact = this.checkContact.bind(this) - } - - handleInputChange(e) { - const { name, value, type, checked } = e.target - const check_type = ['radio', 'checkbox'].includes(type) - this.inputs[name] = check_type ? checked : value - this.inputs['checkedValue'] = check_type ? value : null - } - - triggerAuthEvent(event) { - const state = this.props.authState - if (this.props.onAuthEvent) { - this.props.onAuthEvent(state, event, false) - } - } - - changeState(state, data) { - if (this.props.onStateChange) { - this.props.onStateChange(state, data) - } - - this.triggerAuthEvent({ - type: 'stateChange', - data: state, - }) - } - errorMessage(err) { - if (typeof err === 'string') { - return err - } - return err.message ? err.message : JSON.stringify(err) - } - - error(err) { - this.triggerAuthEvent({ - type: 'error', - data: this.errorMessage(err), - }) - } - - getUsernameFromInput() { - const { usernameAttributes = 'username' } = this.props - switch (usernameAttributes) { - case UsernameAttributes.EMAIL: - return this.inputs.email - case UsernameAttributes.PHONE_NUMBER: - return this.phone_number - default: - return this.inputs.username || this.state.username - } - } - renderUsernameField() { - const { usernameAttributes = [] } = this.props - if (usernameAttributes === UsernameAttributes.EMAIL) { - return ( - - ) - } else if (usernameAttributes === UsernameAttributes.PHONE_NUMBER) { - return
Phone Field
- } else { - return ( - - ) - } - } - - showError() { - const { error } = this.state - return ( - !!error && ( - - {error && error.message} - - ) - ) - } - - checkContact(user) { - if (!Auth || typeof Auth.verifiedContact !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported') - } - Auth.verifiedContact(user).then((data) => { - console.log(data) - if (!isEmpty(data.verified)) { - this.changeState('signedIn', user) - } else { - user = Object.assign(user, data) - this.changeState('verifyContact', user) - } - }) - } - - dismiss() { - this.setState({ error: null }) - } - - render() { - if (!this._validAuthStates.includes(this.props.authState)) { - return null - } - return this.showComponent() - } -} - -SaasBoostAuthComponent.propTypes = { - authState: PropTypes.string, - onAuthEvent: PropTypes.func, - onStateChange: PropTypes.func, - usernameAttributes: PropTypes.object, -} - -export default SaasBoostAuthComponent diff --git a/client/web/src/components/Auth/SaasBoostChangePassword1.js b/client/web/src/components/Auth/SaasBoostChangePassword1.js deleted file mode 100644 index 90e7e6cf..00000000 --- a/client/web/src/components/Auth/SaasBoostChangePassword1.js +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. 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 PropTypes from 'prop-types' -import React, { Component } from 'react' -import { Formik, Form } from 'formik' -import * as Yup from 'yup' -import { Auth } from 'aws-amplify' - -import { Modal, ModalHeader, ModalBody, ModalFooter, Button, Alert, Row, Col } from 'reactstrap' -import { SaasBoostInput } from '../FormComponents/SaasBoostInput' - -class SaasBoostChangePassword extends Component { - constructor(props) { - super(props) - this.state = { - isOpen: false, - error: undefined, - success: false, - } - this.handleCancel = this.handleCancel.bind(this) - this.handleSubmit = this.handleSubmit.bind(this) - this.showError = this.showError.bind(this) - this.handleError = this.handleError.bind(this) - } - - toggle() {} - - showError(error, handleError) { - return ( - handleError()}> -

Error

-

{error}

-
- ) - } - - handleCancel() { - const { handleClose } = this.props - // do clean up. - handleClose() - } - - handleError() { - this.setState({ error: undefined }) - } - - async handleSubmit(values, { resetForm, setSubmitting }) { - const { newPassword, oldPassword } = values - try { - const user = await Auth.currentAuthenticatedUser() - - await Auth.changePassword(user, oldPassword, newPassword) - setSubmitting(false) - this.setState((state, props) => { - return { success: true } - }) - } catch (err) { - this.setState({ error: err.message }) - setSubmitting(false) - resetForm({ values }) - } - } - - render() { - const { show } = this.props - const { error, success } = this.state - - const initialValue = { - oldPassword: '', - newPassword: '', - confirmNewPassword: '', - } - - const validationSchema = Yup.object({ - oldPassword: Yup.string().required('Required'), - newPassword: Yup.string() - .min(6, 'Password must have a minimum of 6 characters') - .required('Required'), - confirmNewPassword: Yup.string() - .min(6, 'Password must have a minimum of 6 characters') - .equals([Yup.ref('newPassword'), null], 'Password does not match') - .required('Required'), - }) - - return ( - <> - - - {(props) => ( -
- Change Password - - - {error && this.showError(error, this.handleError)} - - - - - - - - - - - - - -
- )} -
-
- - Success - -

Your password has been changed successfully.

-
- - - -
- - ) - } -} - -SaasBoostChangePassword.propTypes = { - show: PropTypes.bool, - handleClose: PropTypes.func, -} - -export default SaasBoostChangePassword diff --git a/client/web/src/components/Auth/SaasBoostForgotPassword.js b/client/web/src/components/Auth/SaasBoostForgotPassword.js deleted file mode 100644 index cdfe3d6c..00000000 --- a/client/web/src/components/Auth/SaasBoostForgotPassword.js +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. 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 from 'react' -import SaasBoostAuthComponent from './SaasBoostAuthComponent' -import { Card, CardBody, Col, Container, Row, Button, CardFooter } from 'reactstrap' -import * as Yup from 'yup' -import { Formik, Form as FormikForm } from 'formik' -import { Auth } from 'aws-amplify' - -export class SaasBoostForgotPassword extends SaasBoostAuthComponent { - _initialState = { delivery: null, error: null, username: null } - constructor(props) { - super(props) - this._validAuthStates = ['forgotPassword'] - - this.state = this._initialState - this.submit = this.submit.bind(this) - } - - submit(values, { setSubmitting, resetForm }) { - const { username } = values || this.state.username - - this.setState({ error: null }) - if (!Auth || typeof Auth.forgotPassword !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported') - } - - Auth.forgotPassword(username) - .then((data) => { - this.setState({ delivery: data.CodeDeliveryDetails, username }) - }) - .catch((err) => { - this.setState({ error: err }) - resetForm() - this.error(err) - }) - .finally(() => { - setSubmitting(false) - this.changeState('resetPassword', { - message: 'Expect an email with a reset password code.', - }) - }) - } - - showComponent() { - const { authData = {} } = this.props - console.log(`authData: ${JSON.stringify(authData)}`) - const initialValues = { username: '', email: '', phoneNumber: '' } - - const validationSchema = Yup.object({ - username: Yup.string().trim().required('Required'), - }) - return ( -
- - - - - {(props) => ( - - - -

Reset your password

-
- {this.showError()} - {this.renderUsernameField()} -
-
- - - - - -
-
- )} -
- -
-
-
- ) - } -} - -export default SaasBoostForgotPassword diff --git a/client/web/src/components/Auth/SaasBoostLoading.js b/client/web/src/components/Auth/SaasBoostLoading.js deleted file mode 100644 index 549bc60d..00000000 --- a/client/web/src/components/Auth/SaasBoostLoading.js +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. 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, { Fragment } from 'react' -import { Loading } from 'aws-amplify-react' -import { RingLoader } from 'react-spinners' - -export default class SaasBoostLoading extends Loading { - showComponent() { - return ( - -
-
-

- -

-
-

Authenticating...

-
-
- ) - } -} diff --git a/client/web/src/components/Auth/SaasBoostRequireNewPassword.js b/client/web/src/components/Auth/SaasBoostRequireNewPassword.js deleted file mode 100644 index 7dbf1c9a..00000000 --- a/client/web/src/components/Auth/SaasBoostRequireNewPassword.js +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. 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 from 'react' -import SaasBoostAuthComponent from './SaasBoostAuthComponent' -import { Auth } from 'aws-amplify' -import { Button, Card, CardBody, Col, Container, Row, CardFooter } from 'reactstrap' -import { Formik, Form as FormikForm } from 'formik' - -import { SBInput } from './SaasBoostSignIn' -import * as Yup from 'yup' - -export class SaasBoostRequireNewPassword extends SaasBoostAuthComponent { - _initialState = {} - constructor(props) { - super(props) - this._validAuthStates = ['requireNewPassword'] - this.state = this._initialState - this.change = this.change.bind(this) - } - - change(values, { resetForm }) { - const user = this.props.authData - const attrs = {} - const { password } = values - - if (!Auth || typeof Auth.completeNewPassword !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported') - } - resetForm(values) - Auth.completeNewPassword(user, password, attrs) - .then((user) => { - if (user.challengeName === 'SMS_MFA') { - this.changeState('confirmSignIn', user) - } else if (user.challengeName === 'MFA_SETUP') { - this.changeState('TOTPSetup', user) - } else { - this.checkContact(user) - } - }) - .catch((err) => { - this.setState({ error: err }) - this.error(err) - }) - } - - showComponent() { - const validationSchema = Yup.object({ - password: Yup.string() - .required('Required') - .min(6, 'Password must have a minimum of 6 characters'), - confirmPassword: Yup.string() - .min(6, 'Password must have a minimum of 6 characters') - .equals([Yup.ref('password'), null], 'Password does not match') - .required('Required'), - }) - - return ( -
- - - - - {(props) => ( - - - -

Change Password

- {this.showError()} - - -
- - - - -
-
- )} -
- -
-
-
- ) - } -} - -export default SaasBoostRequireNewPassword diff --git a/client/web/src/components/Auth/SaasBoostResetPassword.js b/client/web/src/components/Auth/SaasBoostResetPassword.js deleted file mode 100644 index a79e10fd..00000000 --- a/client/web/src/components/Auth/SaasBoostResetPassword.js +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. 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 from 'react' -import SaasBoostAuthComponent from './SaasBoostAuthComponent' -import { SBInput } from './SaasBoostSignIn' -import { Card, CardBody, Col, Container, Row, Button, CardFooter, Alert } from 'reactstrap' -import * as Yup from 'yup' -import { Formik, Form as FormikForm } from 'formik' -import { Auth } from 'aws-amplify' - -export class SaasBoostResetPassword extends SaasBoostAuthComponent { - _initialState = { delivery: null, error: null, username: null } - constructor(props) { - super(props) - this._validAuthStates = ['resetPassword'] - - this.submit = this.submit.bind(this) - this.showMessage = this.showMessage.bind(this) - } - - submit({ username, code, password }, { setSubmitting, resetForm }) { - console.log('submit form') - if (!Auth || typeof Auth.forgotPasswordSubmit !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported') - } - - Auth.forgotPasswordSubmit(username, code, password) - .then((data) => { - this.changeState('signIn', { message: 'Password change successful.' }) - this.setState(this._initialState) - }) - .catch((err) => { - this.setState({ error: err }) - this.error(err) - }) - } - - showMessage() { - const { authData } = this.props - - return ( - !!authData && ( - - {authData.message} - - ) - ) - } - - showComponent() { - const initialValues = { username: '', code: '', password: '', passwordConfirmation: '' } - const validationSchema = Yup.object({ - username: Yup.string().required('Required'), - code: Yup.string().required('Required'), - password: Yup.string().required('Required'), - passwordConfirmation: Yup.string().oneOf([Yup.ref('password'), null], 'Passwords must match'), - }) - - return ( -
- - - - - {(props) => ( - - - -

Reset your password

-
- {this.showError()} - {this.showMessage()} - - - -
- -
- - - - -
-
- )} -
- -
-
-
- ) - } -} - -export default SaasBoostResetPassword diff --git a/client/web/src/components/Auth/SaasBoostSignIn.js b/client/web/src/components/Auth/SaasBoostSignIn.js deleted file mode 100644 index bbe34d63..00000000 --- a/client/web/src/components/Auth/SaasBoostSignIn.js +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. 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, { Fragment } from 'react' -import { Auth } from 'aws-amplify' -import { cilUser, cilLockLocked } from '@coreui/icons' -import CIcon from '@coreui/icons-react' -import { Formik, Form as FormikForm, useField } from 'formik' -import { - Button, - Card, - CardBody, - CardGroup, - Col, - Container, - Input, - InputGroup, - InputGroupText, - Row, - Label, - FormFeedback, - FormGroup, - Alert, -} from 'reactstrap' -import * as Yup from 'yup' -import SaasBoostAuthComponent from './SaasBoostAuthComponent' -import { PropTypes } from 'prop-types' - -const SBInput = ({ icon, label, ...props }) => { - const [field, meta] = useField(props) - return ( - - {label && } - - {icon && ( - - - - )} - - - {meta.error} - - - - ) -} - -SBInput.propTypes = { - icon: PropTypes.array, - label: PropTypes.string, -} - -export default class SaasBoostSignIn extends SaasBoostAuthComponent { - constructor(props) { - super(props) - this._validAuthStates = ['signIn', 'signedOut'] - - this.credentials = { username: '', password: '' } - - this.signIn = this.signIn.bind(this) - this.showMessage = this.showMessage.bind(this) - this.showSignOutReason = this.showSignOutReason.bind(this) - } - - async signIn(values, { resetForm }) { - const { dismissSignOutReason } = this.props - this.dismiss() //clear any existing errors - - const { username, password } = values - - if (!Auth || typeof Auth.signIn !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported') - } - - this.setState({ loading: true }) - dismissSignOutReason() - resetForm({ values }) // clear form validation, but leave values. - try { - const user = await Auth.signIn(username.trim(), password.trim()) - if (user.challengeName === 'NEW_PASSWORD_REQUIRED') { - this.changeState('requireNewPassword', user) - } else { - this.checkContact(user) - } - } catch (err) { - if (err.code === 'UserNotConfirmedException') { - this.changeState('confirmSignUp', { username }) - } else if (err.code === 'PasswordResetRequiredException') { - this.changeState('resetPassword', { username }) - } else if (err.code === 'UserNotFoundException') { - this.error({ - ...err, - message: 'Could not login, check username and password', - }) - } else { - this.error(err) - } - } finally { - this.setState({ loading: false }) - } - } - - errorMessage(err) { - if (typeof err === 'string') { - return err - } - return err.message ? err.message : JSON.stringify(err) - } - - error(err) { - this.setState({ error: err }) - this.triggerAuthEvent({ - type: 'error', - data: this.errorMessage(err), - }) - } - - /** - * To integrate with AWS Amplify Auth module, - * need to trigger when an Auth event happens. - * @param event - */ - triggerAuthEvent(event) { - const { authState } = this.props - if (this.props.onAuthEvent) { - this.props.onAuthEvent(authState, event, false) - } - } - - showMessage() { - const { authData } = this.props - - return ( - !!authData && ( - - {authData.message} - - ) - ) - } - - showSignOutReason() { - const { signOutReason } = this.props - - return ( - !!signOutReason && ( - - {signOutReason} - - ) - ) - } - - render() { - const { authData, authState } = this.props - if (!this._validAuthStates.includes(authState)) { - return null - } - return ( - -
- - - - - - - - {(props) => ( - -

Login

-

Sign In to your account

- {this.showError()} - {this.showMessage()} - {this.showSignOutReason()} - - - - - - - - - - -
- )} -
-
-
- - -
-

AWS SaaS Boost

-
- SaasFactory -
-
-
-
-
- -
-
-
-
- ) - } -} - -export { SBInput } diff --git a/client/web/src/components/Auth/SaasBoostSignOut.js b/client/web/src/components/Auth/SaasBoostSignOut.js deleted file mode 100644 index fb5c0e48..00000000 --- a/client/web/src/components/Auth/SaasBoostSignOut.js +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. 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 from 'react' - -import { Auth } from 'aws-amplify' -import { Button } from 'reactstrap' - -const SaasBoostSignOut = () => { - const handleSignOut = async (e) => { - await Auth.signOut() - } - - return -} - -export default SaasBoostSignOut diff --git a/client/web/src/components/Auth/SaasBoostVerifyContact.js b/client/web/src/components/Auth/SaasBoostVerifyContact.js deleted file mode 100644 index eda1f517..00000000 --- a/client/web/src/components/Auth/SaasBoostVerifyContact.js +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. 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 from 'react' -import SaasBoostAuthComponent from './SaasBoostAuthComponent' -import CIcon from '@coreui/icons-react' -import { cilCheckAlt, cilX } from '@coreui/icons' -import { - Container, - Row, - Col, - Card, - CardBody, - FormGroup, - Input, - Label, - Button, - CardFooter, -} from 'reactstrap' -import { Auth } from '@aws-amplify/auth' - -class SaasBoostVerifyContact extends SaasBoostAuthComponent { - constructor(props) { - super(props) - - this._validAuthStates = ['verifyContact'] - this.state = { verifyAttr: null } - this.handleInputChange = this.handleInputChange.bind(this) - this.verify = this.verify.bind(this) - this.submit = this.submit.bind(this) - } - - verify() { - const { contact, checkedValue } = this.inputs - if (!contact) { - this.error('Neither Email nor Phone Number selected') - return - } - - if (!Auth || typeof Auth.verifyCurrentUserAttribute !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported') - } - - Auth.verifyCurrentUserAttribute(checkedValue) - .then((data) => { - this.setState({ verifyAttr: checkedValue }) - }) - .catch((err) => this.error(err)) - } - - submit() { - const attr = this.state.verifyAttr - const { code } = this.inputs - if (!Auth || typeof Auth.verifyCurrentUserAttributeSubmit !== 'function') { - throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported') - } - Auth.verifyCurrentUserAttributeSubmit(attr, code) - .then((data) => { - this.changeState('signedIn', this.props.authData) - this.setState({ verifyAttr: null }) - }) - .catch((err) => this.error(err)) - } - verifyView() { - const user = this.props.authData - if (!user) { - console.error('No user to verify') - return null - } - const { unverified } = user - if (!unverified) { - console.error('no unverified on user') - return null - } - const { email } = unverified - - return ( -
- {email ? ( - - - - - ) : null} -
- ) - } - - submitView() { - return ( -
- -
- ) - } - showComponent() { - const { authData } = this.props - return ( -
- - - - - -

Verify Contact Information

-
Account recovery requires contact information verification.
-
{this.state.verifyAttr ? this.submitView() : this.verifyView()}
-
- - {this.state.verifyAttr ? ( - - ) : ( - - )} - - - -
- -
-
-
- ) - } -} - -export default SaasBoostVerifyContact diff --git a/client/web/src/components/Layout/Sidebar/index.js b/client/web/src/components/Layout/Sidebar/index.js deleted file mode 100644 index 7763b3fb..00000000 --- a/client/web/src/components/Layout/Sidebar/index.js +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. 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, { Fragment, Component } from "react"; - -import { Nav, Container, Row, Col } from "react-bootstrap"; -import { NavLink } from "react-router-dom"; - -class Sidebar extends Component { - render() { - return ( - - - - -
AWS SaaS Boost
- -
- - -
-
- ); - } -} - -export default Sidebar; diff --git a/client/web/src/index.js b/client/web/src/index.js index ee6bacf7..377b2df4 100644 --- a/client/web/src/index.js +++ b/client/web/src/index.js @@ -25,6 +25,7 @@ const oidcConfig = { authority: appConfig.issuer, client_id: appConfig.clientId, redirect_uri: window.location.origin, + post_logout_redirect_uri: window.location.origin, } ReactDOM.render( diff --git a/client/web/src/layout/DefaultLayout.js b/client/web/src/layout/DefaultLayout.js index d55d6747..013b178c 100644 --- a/client/web/src/layout/DefaultLayout.js +++ b/client/web/src/layout/DefaultLayout.js @@ -23,6 +23,7 @@ import PropTypes from 'prop-types' import { connect } from 'react-redux' // sidebar nav config import navigation from '../_nav' +import { removeUserInfo } from '../api/common' const mapStateToProps = (state) => { return { settings: state.settings, setup: state.settings.setup } @@ -41,7 +42,13 @@ class DefaultLayout extends Component { } handleSignOut = async () => { - await this.oidcAuth.removeUser() + try { + await this.oidcAuth.signoutRedirect() + await this.oidcAuth.removeUser() + removeUserInfo() + } catch (e) { + // do nothing + } } handleProfileClick = () => { @@ -107,5 +114,4 @@ DefaultLayout.propTypes = { location: PropTypes.object, } -// export default connect(mapStateToProps, null)(withRouter(DefaultLayout)) export default connect(mapStateToProps, null)(withRouter(DefaultLayout)) \ No newline at end of file