UNPKG

aws-amplify-react

Version:

AWS Amplify is a JavaScript library for Frontend and mobile developers building cloud-enabled applications.

235 lines (210 loc) • 8.94 kB
/* * Copyright 2017-2018 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. A copy of the License is located at * * http://aws.amazon.com/apache2.0/ * * or in the "license" file accompanying this file. This file 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 * as React from 'react'; import { Component } from 'react'; import Amplify, { I18n, ConsoleLogger as Logger, Hub } from '@aws-amplify/core'; import Auth from '@aws-amplify/auth'; import Greetings from './Greetings'; import SignIn from './SignIn'; import ConfirmSignIn from './ConfirmSignIn'; import RequireNewPassword from './RequireNewPassword'; import SignUp from './SignUp'; import Loading from './Loading'; import ConfirmSignUp from './ConfirmSignUp'; import VerifyContact from './VerifyContact'; import ForgotPassword from './ForgotPassword'; import TOTPSetup from './TOTPSetup'; import Constants from './common/constants'; import AmplifyTheme from '../Amplify-UI/Amplify-UI-Theme'; import AmplifyMessageMap from '../AmplifyMessageMap'; import { Container, Toast } from '../Amplify-UI/Amplify-UI-Components-React'; const logger = new Logger('Authenticator'); const AUTHENTICATOR_AUTHSTATE = 'amplify-authenticator-authState'; export default class Authenticator extends Component { constructor(props) { super(props); this.handleStateChange = this.handleStateChange.bind(this); this.handleAuthEvent = this.handleAuthEvent.bind(this); this.onHubCapsule = this.onHubCapsule.bind(this); this._initialAuthState = this.props.authState || 'signIn'; this.state = { authState: 'loading' }; Hub.listen('auth', this); } componentDidMount() { const config = this.props.amplifyConfig; if (config) { Amplify.configure(config); } this._isMounted = true; // the workaround for Cognito Hosted UI // don't check the user immediately if redirected back from Hosted UI // instead waiting for the hub event sent from Auth module // the item in the localStorage is a mark to indicate whether // the app is redirected back from Hosted UI or not const byHostedUI = localStorage.getItem(Constants.SIGN_IN_WITH_HOSTEDUI_KEY); localStorage.removeItem(Constants.SIGN_IN_WITH_HOSTEDUI_KEY); if (!byHostedUI) this.checkUser(); } componentWillUnmount() { this._isMounted = false; } checkUser() { if (!Auth || typeof Auth.currentAuthenticatedUser !== 'function') { throw new Error('No Auth module found, please ensure @aws-amplify/auth is imported'); } return Auth.currentAuthenticatedUser() .then(user => { if (!this._isMounted) { return; } this.handleStateChange('signedIn', user); }) .catch(err => { if (!this._isMounted) { return; } let cachedAuthState = null; try { cachedAuthState = localStorage.getItem(AUTHENTICATOR_AUTHSTATE); } catch (e) { logger.debug('Failed to get the auth state from local storage', e); } const promise = cachedAuthState === 'signedIn'? Auth.signOut() : Promise.resolve(); promise.then(() => this.handleStateChange(this._initialAuthState)) .catch((e) => { logger.debug('Failed to sign out', e); }); }); } onHubCapsule(capsule) { const { channel, payload, source } = capsule; if (channel === 'auth') { switch (payload.event) { case 'cognitoHostedUI': this.handleStateChange('signedIn', payload.data); break; case 'cognitoHostedUI_failure': this.handleStateChange('signIn', null); break; case 'parsingUrl_failure': this.handleStateChange('signIn', null); break; case 'signOut': this.handleStateChange('signIn', null); break; case 'customGreetingSignOut': this.handleStateChange('signIn', null); break; default: break; } } } handleStateChange(state, data) { logger.debug('authenticator state change ' + state, data); if (state === this.state.authState) { return; } if (state === 'signedOut') { state = 'signIn'; } try { localStorage.setItem(AUTHENTICATOR_AUTHSTATE, state); } catch (e) { logger.debug('Failed to set the auth state into local storage', e); } if (this._isMounted) { this.setState({ authState: state, authData: data, error: null, showToast: false }); } if (this.props.onStateChange) { this.props.onStateChange(state, data); } } handleAuthEvent(state, event, showToast = true) { if (event.type === 'error') { const map = this.props.errorMessage || AmplifyMessageMap; const message = (typeof map === 'string')? map : map(event.data); this.setState({ error: message, showToast }); } } render() { const { authState, authData } = this.state; const theme = this.props.theme || AmplifyTheme; const messageMap = this.props.errorMessage || AmplifyMessageMap; let { hideDefault, hide = [], federated, signUpConfig } = this.props; if (hideDefault) { hide = hide.concat([ Greetings, SignIn, ConfirmSignIn, RequireNewPassword, SignUp, ConfirmSignUp, VerifyContact, ForgotPassword, TOTPSetup, Loading ]); } let props_children = []; if (typeof this.props.children === 'object') { if (Array.isArray(this.props.children)){ props_children = this.props.children; } else { props_children.push(this.props.children); } } const default_children = [ <Greetings federated={federated}/>, <SignIn federated={federated}/>, <ConfirmSignIn/>, <RequireNewPassword/>, <SignUp signUpConfig={signUpConfig}/>, <ConfirmSignUp/>, <VerifyContact/>, <ForgotPassword/>, <TOTPSetup/>, <Loading/> ]; const props_children_override = React.Children.map(props_children, child => child.props.override); hide = hide.filter((component) => !props_children.find(child => child.type === component)); const render_props_children = React.Children.map(props_children, (child, index) => { return React.cloneElement(child, { key: 'aws-amplify-authenticator-props-children-' + index, theme, messageMap, authState, authData, onStateChange: this.handleStateChange, onAuthEvent: this.handleAuthEvent, hide, override: props_children_override }); }); const render_default_children = hideDefault ? [] : React.Children.map(default_children, (child, index) => { return React.cloneElement(child, { key: 'aws-amplify-authenticator-default-children-' + index, theme, messageMap, authState, authData, onStateChange: this.handleStateChange, onAuthEvent: this.handleAuthEvent, hide, override: props_children_override }); }); const render_children = render_default_children.concat(render_props_children); const error = this.state.error; return ( <Container theme={theme}> {this.state.showToast && <Toast theme={theme} onClose={() => this.setState({showToast: false})}> { I18n.get(error) } </Toast> } {render_children} </Container> ); } }