From 2b70ccfc25a706c549bc4e8bc2a0aab4dddb9167 Mon Sep 17 00:00:00 2001 From: Ionatan Wiznia Date: Tue, 21 Sep 2021 15:52:46 +0200 Subject: [PATCH 01/14] Support validated links coming from e.com --- src/ROUTES.js | 1 + .../Navigation/AppNavigator/PublicScreens.js | 6 +++ src/libs/Navigation/linkingConfig.js | 1 + src/libs/actions/Session.js | 29 +++++++++- src/pages/LogInWithShortLivedTokenPage.js | 54 +++++++++++++++++++ 5 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 src/pages/LogInWithShortLivedTokenPage.js diff --git a/src/ROUTES.js b/src/ROUTES.js index 520f6f064171..00ea249f5032 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -67,6 +67,7 @@ export default { getReportDetailsRoute: reportID => `r/${reportID}/details`, VALIDATE_LOGIN: 'v', VALIDATE_LOGIN_WITH_VALIDATE_CODE: 'v/:accountID/:validateCode', + LOGIN_WITH_SHORTLIVED_AUTHTOKEN: 'something/:accountID/:email/:shortLivedToken/:encryptedAuthToken/:exitTo', // This is a special validation URL that will take the user to /workspace/new after validation. This is used // when linking users from e.com in order to share a session in this app. diff --git a/src/libs/Navigation/AppNavigator/PublicScreens.js b/src/libs/Navigation/AppNavigator/PublicScreens.js index 2ea797d0ddbc..8031fe774703 100644 --- a/src/libs/Navigation/AppNavigator/PublicScreens.js +++ b/src/libs/Navigation/AppNavigator/PublicScreens.js @@ -3,6 +3,7 @@ import {createStackNavigator} from '@react-navigation/stack'; import SignInPage from '../../../pages/signin/SignInPage'; import SetPasswordPage from '../../../pages/SetPasswordPage'; import ValidateLoginPage from '../../../pages/ValidateLoginPage'; +import LogInWithShortLivedTokenPage from '../../../pages/LogInWithShortLivedTokenPage'; import SCREENS from '../../../SCREENS'; import LoginWithValidateCodePage from '../../../pages/LoginWithValidateCodePage'; import LoginWithValidateCode2FAPage from '../../../pages/LoginWithValidateCode2FAPage'; @@ -17,6 +18,11 @@ export default () => ( options={defaultScreenOptions} component={SignInPage} /> + { + Onyx.merge(ONYXKEYS.SESSION, { + authToken: shortLivedToken, + accountID, + email, + encryptedAuthToken, + }); + if (response.jsonCode === 200) { + getUserDetails(); + Onyx.merge(ONYXKEYS.ACCOUNT, {success: true}); + } else { + const error = lodashGet(response, 'message', 'Unable to login.'); + Onyx.merge(ONYXKEYS.ACCOUNT, {error}); + } + }).finally(() => { + Onyx.merge(ONYXKEYS.ACCOUNT, {loading: false}); + Navigation.navigate(exitTo); + }); +} + /** * User forgot the password so let's send them the link to reset their password */ @@ -306,6 +332,7 @@ export { fetchAccountDetails, setPassword, signIn, + signInWithShortLivedToken, signOut, reopenAccount, resendValidationLink, diff --git a/src/pages/LogInWithShortLivedTokenPage.js b/src/pages/LogInWithShortLivedTokenPage.js new file mode 100644 index 000000000000..5e5070a35338 --- /dev/null +++ b/src/pages/LogInWithShortLivedTokenPage.js @@ -0,0 +1,54 @@ +import {Component} from 'react'; +import lodashGet from 'lodash/get'; +import PropTypes from 'prop-types'; +import {signInWithShortLivedToken} from '../libs/actions/Session'; + +const propTypes = { + /** The accountID and validateCode are passed via the URL */ + route: PropTypes.shape({ + // The name of the route + name: PropTypes.string, + + // Unique key associated with the route + key: PropTypes.string, + + // Each parameter passed via the URL + params: PropTypes.shape({ + // AccountID associated with the validation link + accountID: PropTypes.string, + + // Short lived token + shortLivedToken: PropTypes.string, + + // URL to exit to + exitTo: PropTypes.string, + }), + }), +}; + +const defaultProps = { + route: { + params: {}, + }, +}; +class LogInWithShortLivedTokenPage extends Component { + componentDidMount() { + const accountID = parseInt(lodashGet(this.props.route.params, 'accountID', ''), 10); + const email = lodashGet(this.props.route.params, 'email', ''); + const shortLivedToken = lodashGet(this.props.route.params, 'shortLivedToken', ''); + const encryptedAuthToken = lodashGet(this.props.route.params, 'encryptedAuthToken', ''); + const exitTo = lodashGet(this.props.route.params, 'exitTo', ''); + + signInWithShortLivedToken(accountID, email, shortLivedToken, encryptedAuthToken, exitTo); + } + + render() { + // Don't render anything here since we will redirect the user once we've attempted to validate their login + return null; + } +} + +LogInWithShortLivedTokenPage.propTypes = propTypes; +LogInWithShortLivedTokenPage.defaultProps = defaultProps; + +export default LogInWithShortLivedTokenPage; From d942fe6319f5b96190ce9851e731bf419c65ab1f Mon Sep 17 00:00:00 2001 From: Ionatan Wiznia Date: Tue, 21 Sep 2021 19:06:31 +0200 Subject: [PATCH 02/14] Pass authToken and do not fail on non exiting credentials --- src/libs/API.js | 1 + src/libs/actions/Session.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libs/API.js b/src/libs/API.js index 3f35f9f6caa0..aec23c17f5ac 100644 --- a/src/libs/API.js +++ b/src/libs/API.js @@ -263,6 +263,7 @@ function reauthenticate(command = '') { partnerPassword: CONFIG.EXPENSIFY.PARTNER_PASSWORD, partnerUserID: credentials.autoGeneratedLogin, partnerUserSecret: credentials.autoGeneratedPassword, + authToken, }) .then((response) => { // If authentication fails throw so that we hit diff --git a/src/libs/actions/Session.js b/src/libs/actions/Session.js index 2f33f657bf0f..0823d5845a07 100644 --- a/src/libs/actions/Session.js +++ b/src/libs/actions/Session.js @@ -184,7 +184,7 @@ function createTemporaryLogin(authToken, encryptedAuthToken, email) { // If we have an old generated login for some reason // we should delete it before storing the new details - if (credentials.autoGeneratedLogin) { + if (credentials && credentials.autoGeneratedLogin) { API.DeleteLogin({ partnerUserID: credentials.autoGeneratedLogin, partnerName: CONFIG.EXPENSIFY.PARTNER_NAME, From 3e4543214f9b2f314c0bb93518090ea48dfafc5b Mon Sep 17 00:00:00 2001 From: Ionatan Wiznia Date: Tue, 21 Sep 2021 19:49:28 +0200 Subject: [PATCH 03/14] Pass authToken in authenticate --- src/libs/API.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/API.js b/src/libs/API.js index aec23c17f5ac..d6b9158532d6 100644 --- a/src/libs/API.js +++ b/src/libs/API.js @@ -211,6 +211,7 @@ function Authenticate(parameters) { partnerUserID: parameters.partnerUserID, partnerUserSecret: parameters.partnerUserSecret, twoFactorAuthCode: parameters.twoFactorAuthCode, + authToken: parameters.authToken, doNotRetry: true, // Force this request to be made because the network queue is paused when re-authentication is happening From 8bf40dda4719f7021dfa03531bae491a222b23eb Mon Sep 17 00:00:00 2001 From: Amal Nazeem Date: Tue, 21 Sep 2021 15:06:39 -0400 Subject: [PATCH 04/14] Reintroduce workspace new without a modal, just the url --- src/ROUTES.js | 1 + src/libs/Navigation/AppNavigator/AuthScreens.js | 6 ++++++ src/libs/Navigation/linkingConfig.js | 5 +++++ src/pages/workspace/WorkspaceNew.js | 17 +++++++++++++++++ 4 files changed, 29 insertions(+) create mode 100644 src/pages/workspace/WorkspaceNew.js diff --git a/src/ROUTES.js b/src/ROUTES.js index 00ea249f5032..11d1642f5245 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -79,6 +79,7 @@ export default { WORKSPACE: 'workspace', WORKSPACE_CARD: ':policyID/card', WORKSPACE_PEOPLE: ':policyID/people', + WORKSPACE_NEW: 'workspace/new', getWorkspaceCardRoute: policyID => `workspace/${policyID}/card`, getWorkspacePeopleRoute: policyID => `workspace/${policyID}/people`, getWorkspaceInviteRoute: policyID => `workspace/${policyID}/invite`, diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js index 5338f4cb283d..37d84263c30b 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.js +++ b/src/libs/Navigation/AppNavigator/AuthScreens.js @@ -70,6 +70,7 @@ import CardOverlay from '../../../components/CardOverlay'; import defaultScreenOptions from './defaultScreenOptions'; import * as API from '../../API'; import {setLocale} from '../../actions/App'; +import WorkspaceNew from '../../../pages/workspace/WorkspaceNew'; Onyx.connect({ key: ONYXKEYS.MY_PERSONAL_DETAILS, @@ -340,6 +341,11 @@ class AuthScreens extends React.Component { options={defaultScreenOptions} component={LoginWithValidateCode2FAPage} /> + {/* These are the various modal routes */} {/* Note: Each modal must have it's own stack navigator since we want to be able to navigate to any diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index aa2900e16952..6ede15715b19 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -147,6 +147,11 @@ export default { WorkspaceInvite_Root: ROUTES.WORKSPACE_INVITE, }, }, + WorkspaceNew: { + screens: { + WorkspaceNew_Root: ROUTES.WORKSPACE_NEW, + } + }, WorkspaceSettings: { path: ROUTES.WORKSPACE, diff --git a/src/pages/workspace/WorkspaceNew.js b/src/pages/workspace/WorkspaceNew.js new file mode 100644 index 000000000000..b49651c1f2ee --- /dev/null +++ b/src/pages/workspace/WorkspaceNew.js @@ -0,0 +1,17 @@ +import React, {Component} from 'react'; +import * as Policy from '../../libs/actions/Policy'; +import FullScreenLoadingIndicator from '../../components/FullscreenLoadingIndicator'; + +class WorkspaceNew extends Component { + componentDidMount() { + // After the workspace is created, the user will automatically be directed to its settings page + Policy.create(); + } + + render() { + return ; + } +} + +export default WorkspaceNew; + From 9c8e5b94fbd7fa7d9aa108c22dfbac3c7bdc0c75 Mon Sep 17 00:00:00 2001 From: Amal Nazeem Date: Tue, 21 Sep 2021 15:28:55 -0400 Subject: [PATCH 05/14] minor style/spacing fixes --- src/libs/Navigation/linkingConfig.js | 2 +- src/pages/workspace/WorkspaceNew.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index 6ede15715b19..922f0ccdf07f 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -150,7 +150,7 @@ export default { WorkspaceNew: { screens: { WorkspaceNew_Root: ROUTES.WORKSPACE_NEW, - } + }, }, WorkspaceSettings: { diff --git a/src/pages/workspace/WorkspaceNew.js b/src/pages/workspace/WorkspaceNew.js index b49651c1f2ee..cbd987d4999b 100644 --- a/src/pages/workspace/WorkspaceNew.js +++ b/src/pages/workspace/WorkspaceNew.js @@ -14,4 +14,3 @@ class WorkspaceNew extends Component { } export default WorkspaceNew; - From 18afdf01628f031b3eb84d403e00618a01c61302 Mon Sep 17 00:00:00 2001 From: Amal Nazeem Date: Tue, 21 Sep 2021 18:20:55 -0400 Subject: [PATCH 06/14] Update linking from OldDot to incorporate route correctly --- src/ROUTES.js | 2 +- src/pages/LogInWithShortLivedTokenPage.js | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ROUTES.js b/src/ROUTES.js index 00ea249f5032..abec400aa3e2 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -67,7 +67,7 @@ export default { getReportDetailsRoute: reportID => `r/${reportID}/details`, VALIDATE_LOGIN: 'v', VALIDATE_LOGIN_WITH_VALIDATE_CODE: 'v/:accountID/:validateCode', - LOGIN_WITH_SHORTLIVED_AUTHTOKEN: 'something/:accountID/:email/:shortLivedToken/:encryptedAuthToken/:exitTo', + LOGIN_WITH_SHORTLIVED_AUTHTOKEN: 'transition/:accountID/:email/:shortLivedToken/:exitTo', // This is a special validation URL that will take the user to /workspace/new after validation. This is used // when linking users from e.com in order to share a session in this app. diff --git a/src/pages/LogInWithShortLivedTokenPage.js b/src/pages/LogInWithShortLivedTokenPage.js index 5e5070a35338..3e811a953e7b 100644 --- a/src/pages/LogInWithShortLivedTokenPage.js +++ b/src/pages/LogInWithShortLivedTokenPage.js @@ -37,7 +37,9 @@ class LogInWithShortLivedTokenPage extends Component { const email = lodashGet(this.props.route.params, 'email', ''); const shortLivedToken = lodashGet(this.props.route.params, 'shortLivedToken', ''); const encryptedAuthToken = lodashGet(this.props.route.params, 'encryptedAuthToken', ''); - const exitTo = lodashGet(this.props.route.params, 'exitTo', ''); + + // exitTo is URI encoded because it could contain slashes (i.e. "workspace/new") + const exitTo = decodeURIComponent(lodashGet(this.props.route.params, 'exitTo', '')); signInWithShortLivedToken(accountID, email, shortLivedToken, encryptedAuthToken, exitTo); } From 85f20dc9eec8f33a6f5ac9ac77ada8ff3a76bfd8 Mon Sep 17 00:00:00 2001 From: Amal Nazeem Date: Tue, 21 Sep 2021 19:34:19 -0400 Subject: [PATCH 07/14] Use AuthScreen rerouting method and remove encryptedAuthToken which isn't being set --- .../Navigation/AppNavigator/AuthScreens.js | 22 ++--------- src/libs/actions/Session.js | 6 +-- src/pages/LogInWithShortLivedTokenPage.js | 38 +++++++++++++++---- 3 files changed, 36 insertions(+), 30 deletions(-) diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js index 5338f4cb283d..132ce4483d28 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.js +++ b/src/libs/Navigation/AppNavigator/AuthScreens.js @@ -62,8 +62,7 @@ import { } from './ModalStackNavigators'; import SCREENS from '../../../SCREENS'; import Timers from '../../Timers'; -import LoginWithValidateCodePage from '../../../pages/LoginWithValidateCodePage'; -import LoginWithValidateCode2FAPage from '../../../pages/LoginWithValidateCode2FAPage'; +import LogInWithShortLivedTokenPage from '../../../pages/LogInWithShortLivedTokenPage'; import WorkspaceSettingsDrawerNavigator from './WorkspaceSettingsDrawerNavigator'; import spacing from '../../../styles/utilities/spacing'; import CardOverlay from '../../../components/CardOverlay'; @@ -321,24 +320,9 @@ class AuthScreens extends React.Component { component={ValidateLoginPage} /> - - - {/* These are the various modal routes */} diff --git a/src/libs/actions/Session.js b/src/libs/actions/Session.js index 0823d5845a07..a8a681f846d4 100644 --- a/src/libs/actions/Session.js +++ b/src/libs/actions/Session.js @@ -237,15 +237,14 @@ function signIn(password, twoFactorAuthCode) { }); } -function signInWithShortLivedToken(accountID, email, shortLivedToken, encryptedAuthToken, exitTo) { +function signInWithShortLivedToken(accountID, email, shortLivedToken) { Onyx.merge(ONYXKEYS.ACCOUNT, {...CONST.DEFAULT_ACCOUNT_DATA, loading: true}); - createTemporaryLogin(shortLivedToken, encryptedAuthToken).then((response) => { + createTemporaryLogin(shortLivedToken).then((response) => { Onyx.merge(ONYXKEYS.SESSION, { authToken: shortLivedToken, accountID, email, - encryptedAuthToken, }); if (response.jsonCode === 200) { getUserDetails(); @@ -256,7 +255,6 @@ function signInWithShortLivedToken(accountID, email, shortLivedToken, encryptedA } }).finally(() => { Onyx.merge(ONYXKEYS.ACCOUNT, {loading: false}); - Navigation.navigate(exitTo); }); } diff --git a/src/pages/LogInWithShortLivedTokenPage.js b/src/pages/LogInWithShortLivedTokenPage.js index 3e811a953e7b..5d19115ff744 100644 --- a/src/pages/LogInWithShortLivedTokenPage.js +++ b/src/pages/LogInWithShortLivedTokenPage.js @@ -1,7 +1,12 @@ -import {Component} from 'react'; +import React, {Component} from 'react'; import lodashGet from 'lodash/get'; import PropTypes from 'prop-types'; +import {withOnyx} from 'react-native-onyx'; +import compose from '../libs/compose'; +import ONYXKEYS from '../ONYXKEYS'; import {signInWithShortLivedToken} from '../libs/actions/Session'; +import FullScreenLoadingIndicator from '../components/FullscreenLoadingIndicator'; +import Navigation from '../libs/Navigation/Navigation'; const propTypes = { /** The accountID and validateCode are passed via the URL */ @@ -24,33 +29,52 @@ const propTypes = { exitTo: PropTypes.string, }), }), + + /** The data about the current session */ + session: PropTypes.shape({ + /** The authToken for the current session */ + authToken: PropTypes.string, + + /** The authToken for the current session */ + email: PropTypes.string, + }), }; const defaultProps = { route: { params: {}, }, + session: {}, }; class LogInWithShortLivedTokenPage extends Component { componentDidMount() { const accountID = parseInt(lodashGet(this.props.route.params, 'accountID', ''), 10); const email = lodashGet(this.props.route.params, 'email', ''); const shortLivedToken = lodashGet(this.props.route.params, 'shortLivedToken', ''); - const encryptedAuthToken = lodashGet(this.props.route.params, 'encryptedAuthToken', ''); - // exitTo is URI encoded because it could contain slashes (i.e. "workspace/new") + // exitTo is URI encoded because it could contain a variable number of slashes (i.e. "workspace/new" vs "workspace//card") const exitTo = decodeURIComponent(lodashGet(this.props.route.params, 'exitTo', '')); - signInWithShortLivedToken(accountID, email, shortLivedToken, encryptedAuthToken, exitTo); + // If the user is revisiting the component authenticated or they were already logged into the right account, we simply redirect them to the exitTo + if (this.props.session.authToken && email === this.props.session.email) { + Navigation.navigate(exitTo); + } + + signInWithShortLivedToken(accountID, email, shortLivedToken); } render() { - // Don't render anything here since we will redirect the user once we've attempted to validate their login - return null; + return ; } } LogInWithShortLivedTokenPage.propTypes = propTypes; LogInWithShortLivedTokenPage.defaultProps = defaultProps; -export default LogInWithShortLivedTokenPage; +export default compose( + withOnyx({ + session: { + key: ONYXKEYS.SESSION, + }, + }), +)(LogInWithShortLivedTokenPage); From 8ea5a2e6ac5cdc7cbcc00ac963633de8f8c025a3 Mon Sep 17 00:00:00 2001 From: Amal Nazeem Date: Tue, 21 Sep 2021 19:53:10 -0400 Subject: [PATCH 08/14] Use Screens Const --- src/SCREENS.js | 1 + src/libs/Navigation/AppNavigator/AuthScreens.js | 2 +- src/libs/Navigation/AppNavigator/PublicScreens.js | 2 +- src/libs/Navigation/linkingConfig.js | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/SCREENS.js b/src/SCREENS.js index 764965e7335c..3a9754a1ee76 100644 --- a/src/SCREENS.js +++ b/src/SCREENS.js @@ -6,6 +6,7 @@ export default { HOME: 'Home', LOADING: 'Loading', REPORT: 'Report', + LOG_IN_WITH_SHORT_LIVED_TOKEN: 'LogInWithShortLivedToken', LOGIN_WITH_VALIDATE_CODE_NEW_WORKSPACE: 'LoginWithValidateCodeNewWorkspace', LOGIN_WITH_VALIDATE_CODE_2FA_NEW_WORKSPACE: 'LoginWithValidateCode2FANewWorkspace', LOGIN_WITH_VALIDATE_CODE_WORKSPACE_CARD: 'LoginWithValidateCodeWorkspaceCard', diff --git a/src/libs/Navigation/AppNavigator/AuthScreens.js b/src/libs/Navigation/AppNavigator/AuthScreens.js index 132ce4483d28..b66199cec24b 100644 --- a/src/libs/Navigation/AppNavigator/AuthScreens.js +++ b/src/libs/Navigation/AppNavigator/AuthScreens.js @@ -320,7 +320,7 @@ class AuthScreens extends React.Component { component={ValidateLoginPage} /> diff --git a/src/libs/Navigation/AppNavigator/PublicScreens.js b/src/libs/Navigation/AppNavigator/PublicScreens.js index 8031fe774703..f95fe6b2dd5b 100644 --- a/src/libs/Navigation/AppNavigator/PublicScreens.js +++ b/src/libs/Navigation/AppNavigator/PublicScreens.js @@ -19,7 +19,7 @@ export default () => ( component={SignInPage} /> diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index aa2900e16952..c46cd4720a98 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -32,7 +32,7 @@ export default { [SCREENS.LOGIN_WITH_VALIDATE_CODE_2FA_NEW_WORKSPACE]: ROUTES.LOGIN_WITH_VALIDATE_CODE_2FA_NEW_WORKSPACE, [SCREENS.LOGIN_WITH_VALIDATE_CODE_WORKSPACE_CARD]: ROUTES.LOGIN_WITH_VALIDATE_CODE_WORKSPACE_CARD, [SCREENS.LOGIN_WITH_VALIDATE_CODE_2FA_WORKSPACE_CARD]: ROUTES.LOGIN_WITH_VALIDATE_CODE_2FA_WORKSPACE_CARD, - LogInWithShortLivedToken: ROUTES.LOGIN_WITH_SHORTLIVED_AUTHTOKEN, + [SCREENS.LOG_IN_WITH_SHORT_LIVED_TOKEN]: ROUTES.LOGIN_WITH_SHORTLIVED_AUTHTOKEN, // Modal Screens Settings: { From 579a6cb709082e873c36a49d4f0b23f5898fc302 Mon Sep 17 00:00:00 2001 From: Amal Nazeem Date: Tue, 21 Sep 2021 19:53:44 -0400 Subject: [PATCH 09/14] Incorporate Navigation.dismissModal to fix logic when closing a modal --- src/pages/LogInWithShortLivedTokenPage.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/pages/LogInWithShortLivedTokenPage.js b/src/pages/LogInWithShortLivedTokenPage.js index 5d19115ff744..bc64ba8c2406 100644 --- a/src/pages/LogInWithShortLivedTokenPage.js +++ b/src/pages/LogInWithShortLivedTokenPage.js @@ -57,6 +57,13 @@ class LogInWithShortLivedTokenPage extends Component { // If the user is revisiting the component authenticated or they were already logged into the right account, we simply redirect them to the exitTo if (this.props.session.authToken && email === this.props.session.email) { + // In order to navigate to a modal, we first have to dismiss the current modal. But there is no current + // modal you say? I know, it confuses me too. Without dismissing the current modal, if the user cancels out + // of the workspace modal, then they will be routed back to + // /transition////workspace//card and we don't want that. We want them to go back to `/` + // and by calling dismissModal(), the /transition/... route is removed from history so the user will get taken to `/` + // if they cancel out of the new workspace modal. + Navigation.dismissModal(); Navigation.navigate(exitTo); } From 31436b1537c9e011495bf74c038365f3b7e9df41 Mon Sep 17 00:00:00 2001 From: Amal Nazeem Date: Wed, 22 Sep 2021 00:54:52 -0400 Subject: [PATCH 10/14] Add/fix doc for functions --- src/libs/API.js | 1 + src/libs/actions/Session.js | 11 +++++++++-- src/pages/LogInWithShortLivedTokenPage.js | 16 ++++++++-------- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/libs/API.js b/src/libs/API.js index d6b9158532d6..9e397c39c4b1 100644 --- a/src/libs/API.js +++ b/src/libs/API.js @@ -189,6 +189,7 @@ Network.registerErrorHandler((queuedRequest, error) => { * @param {String} parameters.partnerUserSecret * @param {String} [parameters.twoFactorAuthCode] * @param {String} [parameters.email] + * @param {String} [parameters.authToken] * @returns {Promise} */ function Authenticate(parameters) { diff --git a/src/libs/actions/Session.js b/src/libs/actions/Session.js index a8a681f846d4..82a5ddf41931 100644 --- a/src/libs/actions/Session.js +++ b/src/libs/actions/Session.js @@ -157,8 +157,8 @@ function fetchAccountDetails(login) { * re-authenticating after an authToken expires. * * @param {String} authToken - * @param {String} encryptedAuthToken – Not required for the CreateLogin API call, but passed to setSuccessfulSignInData - * @param {String} email + * @param {String} [encryptedAuthToken] – Not required for the CreateLogin API call, but passed to setSuccessfulSignInData + * @param {String} [email] * @return {Promise} */ function createTemporaryLogin(authToken, encryptedAuthToken, email) { @@ -237,6 +237,13 @@ function signIn(password, twoFactorAuthCode) { }); } +/** + * Uses a short lived authToken to continue a user's session from OldDot + * + * @param {String} accountID + * @param {String} email + * @param {String} shortLivedToken + */ function signInWithShortLivedToken(accountID, email, shortLivedToken) { Onyx.merge(ONYXKEYS.ACCOUNT, {...CONST.DEFAULT_ACCOUNT_DATA, loading: true}); diff --git a/src/pages/LogInWithShortLivedTokenPage.js b/src/pages/LogInWithShortLivedTokenPage.js index bc64ba8c2406..c163af031705 100644 --- a/src/pages/LogInWithShortLivedTokenPage.js +++ b/src/pages/LogInWithShortLivedTokenPage.js @@ -9,28 +9,28 @@ import FullScreenLoadingIndicator from '../components/FullscreenLoadingIndicator import Navigation from '../libs/Navigation/Navigation'; const propTypes = { - /** The accountID and validateCode are passed via the URL */ + /** The parameters needed to authenticate with a short lived token are in the URL */ route: PropTypes.shape({ - // The name of the route + /** The name of the route */ name: PropTypes.string, - // Unique key associated with the route + /** Unique key associated with the route */ key: PropTypes.string, - // Each parameter passed via the URL + /** Each parameter passed via the URL */ params: PropTypes.shape({ - // AccountID associated with the validation link + /** AccountID associated with the validation link */ accountID: PropTypes.string, - // Short lived token + /** Short lived token */ shortLivedToken: PropTypes.string, - // URL to exit to + /** URL to exit to */ exitTo: PropTypes.string, }), }), - /** The data about the current session */ + /** The data about the current session which will be set once the user is authenticated and we return to this component as an AuthScreen */ session: PropTypes.shape({ /** The authToken for the current session */ authToken: PropTypes.string, From 60ebb4cb82931511c15effa338fc220e14cc233b Mon Sep 17 00:00:00 2001 From: Ionatan Wiznia Date: Wed, 22 Sep 2021 16:08:35 +0200 Subject: [PATCH 11/14] Return the response of createTemporaryLogin --- src/libs/actions/Session.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libs/actions/Session.js b/src/libs/actions/Session.js index 82a5ddf41931..d37d51675efd 100644 --- a/src/libs/actions/Session.js +++ b/src/libs/actions/Session.js @@ -199,6 +199,7 @@ function createTemporaryLogin(authToken, encryptedAuthToken, email) { autoGeneratedPassword, }); Network.unpauseRequestQueue(); + return createLoginResponse; }) .catch((error) => { Onyx.merge(ONYXKEYS.ACCOUNT, {error: error.message}); From 269697b67f504243137637c72b5b8102ae01335a Mon Sep 17 00:00:00 2001 From: Amal Nazeem Date: Wed, 22 Sep 2021 10:27:34 -0400 Subject: [PATCH 12/14] reintroduce encrypted authToken --- src/ROUTES.js | 2 +- src/libs/actions/Session.js | 8 ++++---- src/pages/LogInWithShortLivedTokenPage.js | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/ROUTES.js b/src/ROUTES.js index abec400aa3e2..89572e2ac601 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -67,7 +67,7 @@ export default { getReportDetailsRoute: reportID => `r/${reportID}/details`, VALIDATE_LOGIN: 'v', VALIDATE_LOGIN_WITH_VALIDATE_CODE: 'v/:accountID/:validateCode', - LOGIN_WITH_SHORTLIVED_AUTHTOKEN: 'transition/:accountID/:email/:shortLivedToken/:exitTo', + LOGIN_WITH_SHORTLIVED_AUTHTOKEN: 'transition/:accountID/:email/:shortLivedToken/:encryptedAuthToken/:exitTo', // This is a special validation URL that will take the user to /workspace/new after validation. This is used // when linking users from e.com in order to share a session in this app. diff --git a/src/libs/actions/Session.js b/src/libs/actions/Session.js index 82a5ddf41931..e6fbe64c9cce 100644 --- a/src/libs/actions/Session.js +++ b/src/libs/actions/Session.js @@ -157,8 +157,8 @@ function fetchAccountDetails(login) { * re-authenticating after an authToken expires. * * @param {String} authToken - * @param {String} [encryptedAuthToken] – Not required for the CreateLogin API call, but passed to setSuccessfulSignInData - * @param {String} [email] + * @param {String} encryptedAuthToken – Not required for the CreateLogin API call, but passed to setSuccessfulSignInData + * @param {String} email * @return {Promise} */ function createTemporaryLogin(authToken, encryptedAuthToken, email) { @@ -244,10 +244,10 @@ function signIn(password, twoFactorAuthCode) { * @param {String} email * @param {String} shortLivedToken */ -function signInWithShortLivedToken(accountID, email, shortLivedToken) { +function signInWithShortLivedToken(accountID, email, shortLivedToken, encryptedAuthToken) { Onyx.merge(ONYXKEYS.ACCOUNT, {...CONST.DEFAULT_ACCOUNT_DATA, loading: true}); - createTemporaryLogin(shortLivedToken).then((response) => { + createTemporaryLogin(shortLivedToken, encryptedAuthToken, email).then((response) => { Onyx.merge(ONYXKEYS.SESSION, { authToken: shortLivedToken, accountID, diff --git a/src/pages/LogInWithShortLivedTokenPage.js b/src/pages/LogInWithShortLivedTokenPage.js index c163af031705..e409b76217ac 100644 --- a/src/pages/LogInWithShortLivedTokenPage.js +++ b/src/pages/LogInWithShortLivedTokenPage.js @@ -51,6 +51,7 @@ class LogInWithShortLivedTokenPage extends Component { const accountID = parseInt(lodashGet(this.props.route.params, 'accountID', ''), 10); const email = lodashGet(this.props.route.params, 'email', ''); const shortLivedToken = lodashGet(this.props.route.params, 'shortLivedToken', ''); + const encryptedAuthToken = lodashGet(this.props.route.params, 'encryptedAuthToken', ''); // exitTo is URI encoded because it could contain a variable number of slashes (i.e. "workspace/new" vs "workspace//card") const exitTo = decodeURIComponent(lodashGet(this.props.route.params, 'exitTo', '')); @@ -67,7 +68,7 @@ class LogInWithShortLivedTokenPage extends Component { Navigation.navigate(exitTo); } - signInWithShortLivedToken(accountID, email, shortLivedToken); + signInWithShortLivedToken(accountID, email, shortLivedToken, encryptedAuthToken); } render() { From 327785fc1af8a6efb00dabe6b5d3e3bfbb9caa5e Mon Sep 17 00:00:00 2001 From: Ionatan Wiznia Date: Wed, 22 Sep 2021 17:34:56 +0200 Subject: [PATCH 13/14] Consistentyl use SHORT_LIVED --- src/ROUTES.js | 2 +- src/libs/Navigation/linkingConfig.js | 2 +- src/libs/actions/Session.js | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ROUTES.js b/src/ROUTES.js index 9870abbc2a04..93be942a6e09 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -67,7 +67,7 @@ export default { getReportDetailsRoute: reportID => `r/${reportID}/details`, VALIDATE_LOGIN: 'v', VALIDATE_LOGIN_WITH_VALIDATE_CODE: 'v/:accountID/:validateCode', - LOGIN_WITH_SHORTLIVED_AUTHTOKEN: 'transition/:accountID/:email/:shortLivedToken/:encryptedAuthToken/:exitTo', + LOGIN_WITH_SHORT_LIVED_AUTHTOKEN: 'transition/:accountID/:email/:shortLivedToken/:encryptedAuthToken/:exitTo', // This is a special validation URL that will take the user to /workspace/new after validation. This is used // when linking users from e.com in order to share a session in this app. diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index 52fb3a37b50f..7b67a78f91b7 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -32,7 +32,7 @@ export default { [SCREENS.LOGIN_WITH_VALIDATE_CODE_2FA_NEW_WORKSPACE]: ROUTES.LOGIN_WITH_VALIDATE_CODE_2FA_NEW_WORKSPACE, [SCREENS.LOGIN_WITH_VALIDATE_CODE_WORKSPACE_CARD]: ROUTES.LOGIN_WITH_VALIDATE_CODE_WORKSPACE_CARD, [SCREENS.LOGIN_WITH_VALIDATE_CODE_2FA_WORKSPACE_CARD]: ROUTES.LOGIN_WITH_VALIDATE_CODE_2FA_WORKSPACE_CARD, - [SCREENS.LOG_IN_WITH_SHORT_LIVED_TOKEN]: ROUTES.LOGIN_WITH_SHORTLIVED_AUTHTOKEN, + [SCREENS.LOG_IN_WITH_SHORT_LIVED_TOKEN]: ROUTES.LOGIN_WITH_SHORT_LIVED_AUTHTOKEN, // Modal Screens Settings: { diff --git a/src/libs/actions/Session.js b/src/libs/actions/Session.js index 99a7d20e9f42..a6931eee2362 100644 --- a/src/libs/actions/Session.js +++ b/src/libs/actions/Session.js @@ -244,6 +244,7 @@ function signIn(password, twoFactorAuthCode) { * @param {String} accountID * @param {String} email * @param {String} shortLivedToken + * @param {string} encryptedAuthToken */ function signInWithShortLivedToken(accountID, email, shortLivedToken, encryptedAuthToken) { Onyx.merge(ONYXKEYS.ACCOUNT, {...CONST.DEFAULT_ACCOUNT_DATA, loading: true}); From 702b89e67699c35e5ef39148965add704ef18c38 Mon Sep 17 00:00:00 2001 From: Amal Nazeem Date: Wed, 22 Sep 2021 11:37:39 -0400 Subject: [PATCH 14/14] Unify names by getting rid of auth --- src/ROUTES.js | 2 +- src/libs/Navigation/linkingConfig.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ROUTES.js b/src/ROUTES.js index 93be942a6e09..e09bb4e84986 100644 --- a/src/ROUTES.js +++ b/src/ROUTES.js @@ -67,7 +67,7 @@ export default { getReportDetailsRoute: reportID => `r/${reportID}/details`, VALIDATE_LOGIN: 'v', VALIDATE_LOGIN_WITH_VALIDATE_CODE: 'v/:accountID/:validateCode', - LOGIN_WITH_SHORT_LIVED_AUTHTOKEN: 'transition/:accountID/:email/:shortLivedToken/:encryptedAuthToken/:exitTo', + LOGIN_WITH_SHORT_LIVED_TOKEN: 'transition/:accountID/:email/:shortLivedToken/:encryptedAuthToken/:exitTo', // This is a special validation URL that will take the user to /workspace/new after validation. This is used // when linking users from e.com in order to share a session in this app. diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js index 7b67a78f91b7..c0b947db8998 100644 --- a/src/libs/Navigation/linkingConfig.js +++ b/src/libs/Navigation/linkingConfig.js @@ -32,7 +32,7 @@ export default { [SCREENS.LOGIN_WITH_VALIDATE_CODE_2FA_NEW_WORKSPACE]: ROUTES.LOGIN_WITH_VALIDATE_CODE_2FA_NEW_WORKSPACE, [SCREENS.LOGIN_WITH_VALIDATE_CODE_WORKSPACE_CARD]: ROUTES.LOGIN_WITH_VALIDATE_CODE_WORKSPACE_CARD, [SCREENS.LOGIN_WITH_VALIDATE_CODE_2FA_WORKSPACE_CARD]: ROUTES.LOGIN_WITH_VALIDATE_CODE_2FA_WORKSPACE_CARD, - [SCREENS.LOG_IN_WITH_SHORT_LIVED_TOKEN]: ROUTES.LOGIN_WITH_SHORT_LIVED_AUTHTOKEN, + [SCREENS.LOG_IN_WITH_SHORT_LIVED_TOKEN]: ROUTES.LOGIN_WITH_SHORT_LIVED_TOKEN, // Modal Screens Settings: {