-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow e.com to link straight to e.cash and share sessions #3715
Changes from 25 commits
e40fe94
c6047a2
27ddb14
c4738e8
90fc9dc
9790dfd
d8906d6
fbafc61
2819a23
a4d43e2
6eac5bb
09bded2
a0bb25d
af4cfeb
d32f02c
3880ba8
0d5d4f3
f1a55a5
74b9a1e
243b0f8
5054ca4
554b61c
504597f
636ad0b
134564e
a94f7ab
f9f3c61
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -194,7 +194,6 @@ function Authenticate(parameters) { | |
'partnerUserSecret', | ||
], parameters, commandName); | ||
|
||
// eslint-disable-next-line no-use-before-define | ||
return Network.post(commandName, { | ||
// When authenticating for the first time, we pass useExpensifyLogin as true so we check | ||
// for credentials for the expensify partnerID to let users Authenticate with their expensify user | ||
|
@@ -296,6 +295,33 @@ function reauthenticate(command = '') { | |
}); | ||
} | ||
|
||
/** | ||
* Calls the command=Authenticate API with an accountID, validateCode, and optional 2FA code. This is used specifically | ||
* for sharing sessions between e.com and this app. It will return an authToken that is used for initiating a session | ||
* in this app. This API call doesn't have any special handling (like retries or special error handling). | ||
* | ||
* @param {Object} parameters | ||
* @param {String} parameters.accountID | ||
* @param {String} parameters.validateCode | ||
* @param {String} [parameters.twoFactorAuthCode] | ||
* @returns {Promise<unknown>} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NAB / just curious but why There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think PHPStorm did that automatically, so I'm not sure why! I'll remove it |
||
*/ | ||
function AuthenticateWithAccountID(parameters) { | ||
const commandName = 'Authenticate'; | ||
|
||
requireParameters([ | ||
'accountID', | ||
'validateCode', | ||
], parameters, commandName); | ||
|
||
return Network.post(commandName, { | ||
accountID: parameters.accountID, | ||
validateCode: parameters.validateCode, | ||
twoFactorAuthCode: parameters.twoFactorAuthCode, | ||
doNotRetry: true, | ||
}); | ||
} | ||
|
||
/** | ||
* @param {Object} parameters | ||
* @param {String} parameters.oldPassword | ||
|
@@ -994,6 +1020,7 @@ function Inbox_CallUser(parameters) { | |
|
||
export { | ||
Authenticate, | ||
AuthenticateWithAccountID, | ||
BankAccount_Create, | ||
BankAccount_Get, | ||
BankAccount_SetupWithdrawal, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
const defaultScreenOptions = { | ||
cardStyle: { | ||
overflow: 'visible', | ||
}, | ||
headerShown: false, | ||
animationTypeForReplace: 'pop', | ||
}; | ||
|
||
export default defaultScreenOptions; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
import React, {Component} from 'react'; | ||
import {Text, TextInput, View} from 'react-native'; | ||
import lodashGet from 'lodash/get'; | ||
import PropTypes from 'prop-types'; | ||
import {withOnyx} from 'react-native-onyx'; | ||
import withLocalize, {withLocalizePropTypes} from '../components/withLocalize'; | ||
import validateLinkPropTypes from './validateLinkPropTypes'; | ||
import {continueSessionFromECom} from '../libs/actions/Session'; | ||
import styles from '../styles/styles'; | ||
import ExpensifyCashLogo from '../components/ExpensifyCashLogo'; | ||
import variables from '../styles/variables'; | ||
import themeColors from '../styles/themes/default'; | ||
import CONST from '../CONST'; | ||
import Button from '../components/Button'; | ||
import compose from '../libs/compose'; | ||
import ONYXKEYS from '../ONYXKEYS'; | ||
import Navigation from '../libs/Navigation/Navigation'; | ||
import ROUTES from '../ROUTES'; | ||
|
||
const propTypes = { | ||
/* Onyx Props */ | ||
|
||
/** The data about the current session */ | ||
session: PropTypes.shape({ | ||
/** The authToken for the current session */ | ||
authToken: PropTypes.string, | ||
}), | ||
|
||
/** The accountID and validateCode are passed via the URL */ | ||
route: validateLinkPropTypes, | ||
|
||
...withLocalizePropTypes, | ||
}; | ||
|
||
const defaultProps = { | ||
route: { | ||
params: {}, | ||
}, | ||
session: {}, | ||
}; | ||
class ValidateLogin2FANewWorkspacePage extends Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
this.validateAndSubmitForm = this.validateAndSubmitForm.bind(this); | ||
|
||
this.state = { | ||
twoFactorAuthCode: '', | ||
formError: false, | ||
loading: false, | ||
}; | ||
} | ||
|
||
componentDidMount() { | ||
// If the user has an active session already, they need to be redirected straight to the new workspace page | ||
if (this.props.session.authToken) { | ||
// 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 they user cancels | ||
// out of the new workspace modal, then they will be routed back to | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
NAB, I can see how this could be confusing (because the modal is not visible), but I think maybe it's not that mysterious. Curious if we should replace this commentary with a better explanation and have an idea about what's happening here... ValidateLogin2FANewWorkspacePage is the modal we are dismissing, it "exists", but the page is returning There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I'm all in favor of updating this comment to make more sense. If the real problem is that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I'm having trouble working out a better way. It feels like there are contexts where you'd want the default There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. All right, I was able to fix this. Turns out, I was navigating to that modal twice (once in Session, and again from ComponentDidMount (from when the same page was remounted: once in Once I removed the navigation in the Session action, it all worked like a charm. |
||
// /v/<accountID>/<validateCode>/new-workspace and we don't want that. We want them to go back to `/` and | ||
// by calling dismissModal(), the /v/... 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(ROUTES.WORKSPACE_NEW); | ||
} | ||
} | ||
|
||
validateAndSubmitForm() { | ||
if (!this.state.twoFactorAuthCode.trim()) { | ||
this.setState({formError: this.props.translate('passwordForm.pleaseFillOutAllFields')}); | ||
return; | ||
} | ||
|
||
this.setState({ | ||
formError: null, | ||
}); | ||
|
||
const accountID = lodashGet(this.props.route.params, 'accountID', ''); | ||
const validateCode = lodashGet(this.props.route.params, 'validateCode', ''); | ||
continueSessionFromECom(accountID, validateCode, this.state.twoFactorAuthCode); | ||
} | ||
|
||
render() { | ||
// If the user is already logged in, don't need to display anything because they will get redirected to the | ||
// new workspace page in componentDidMount | ||
if (this.props.session.authToken) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<View style={[styles.signInPageInnerNative]}> | ||
<View style={[styles.signInPageLogoNative]}> | ||
<ExpensifyCashLogo width={variables.componentSizeLarge} height={variables.componentSizeLarge} /> | ||
</View> | ||
<View style={[styles.mb6, styles.alignItemsCenter]}> | ||
<Text style={[styles.h1]}> | ||
{this.props.translate('signInPage.expensifyDotCash')} | ||
</Text> | ||
</View> | ||
|
||
<View style={[styles.signInPageFormContainer]}> | ||
<View style={[styles.mb4]}> | ||
<Text style={[styles.formLabel]}> | ||
{this.props.translate('passwordForm.enterATwoFactorAuthenticationCodeToContinue')} | ||
</Text> | ||
<TextInput | ||
style={[styles.textInput]} | ||
value={this.state.twoFactorAuthCode} | ||
placeholder={this.props.translate('passwordForm.twoFactorCode')} | ||
placeholderTextColor={themeColors.placeholderText} | ||
onChangeText={text => this.setState({twoFactorAuthCode: text})} | ||
onSubmitEditing={this.validateAndSubmitForm} | ||
keyboardType={CONST.KEYBOARD_TYPE.NUMERIC} | ||
/> | ||
</View> | ||
<View> | ||
<Button | ||
success | ||
style={[styles.mb2]} | ||
text={this.props.translate('common.continue')} | ||
isLoading={this.state.loading} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NAB: We never set this anywhere but the constructor, meaning the user has no feedback as to when we are actually loading There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll see about cleaning this up. |
||
onPress={this.validateAndSubmitForm} | ||
/> | ||
</View> | ||
{this.state.formError && ( | ||
<Text style={[styles.formError]}> | ||
{this.state.formError} | ||
</Text> | ||
)} | ||
</View> | ||
</View> | ||
); | ||
} | ||
} | ||
|
||
ValidateLogin2FANewWorkspacePage.propTypes = propTypes; | ||
ValidateLogin2FANewWorkspacePage.defaultProps = defaultProps; | ||
|
||
export default compose( | ||
withLocalize, | ||
withOnyx({ | ||
session: { | ||
key: ONYXKEYS.SESSION, | ||
}, | ||
}), | ||
)(ValidateLogin2FANewWorkspacePage); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NAB: I feel like
your
reads better thana
hereThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I can change this.