diff --git a/src/CONFIG.js b/src/CONFIG.js
index 10512520c48..7dcfe5902d0 100644
--- a/src/CONFIG.js
+++ b/src/CONFIG.js
@@ -1,5 +1,6 @@
-// TODO: Figure out how to determine prod/dev on mobile, etc.
-const IS_IN_PRODUCTION = false;
+import {Platform} from 'react-native';
+
+const IS_IN_PRODUCTION = Platform.OS === 'web' ? process.env.NODE_ENV === 'production' : !__DEV__;
export default {
PUSHER: {
diff --git a/src/lib/Str.js b/src/lib/Str.js
index d8660585d8c..b768528bc0c 100644
--- a/src/lib/Str.js
+++ b/src/lib/Str.js
@@ -1,5 +1,7 @@
/* globals $, _ */
+import Guid from './Guid';
+
const Str = {
/**
* Returns the proper phrase depending on the count that is passed.
@@ -49,6 +51,15 @@ const Str = {
nl2br(str) {
return str.replace(/\n/g, '
');
},
+
+ /**
+ * Generates a random device login using Guid
+ *
+ * @returns {string}
+ */
+ generateDeviceLoginID() {
+ return `React-Native-Chat-${Guid()}`;
+ },
};
export default Str;
diff --git a/src/page/SignInPage.js b/src/page/SignInPage.js
index 80cc4e111b4..86d1d6c1d07 100644
--- a/src/page/SignInPage.js
+++ b/src/page/SignInPage.js
@@ -27,13 +27,14 @@ export default class App extends Component {
login: '',
password: '',
// eslint-disable-next-line react/no-unused-state
- error: Store.get(STOREKEYS.SESSION, 'error'),
+ error: null,
};
}
componentDidMount() {
// Listen for changes to our session
Store.subscribe(STOREKEYS.SESSION, this.sessionChanged);
+ Store.get(STOREKEYS.SESSION, 'error').then(error => this.setState({error}));
}
componentWillUnmount() {
@@ -54,7 +55,7 @@ export default class App extends Component {
* When the form is submitted, then we trigger our prop callback
*/
submit() {
- signIn(this.state.login, this.state.password);
+ signIn(this.state.login, this.state.password, true);
}
render() {
@@ -81,6 +82,9 @@ export default class App extends Component {
+ {this.state.error &&
+ {this.state.error}
+ }
>
diff --git a/src/store/actions/SessionActions.js b/src/store/actions/SessionActions.js
index 32901dcd16c..99f2c38746c 100644
--- a/src/store/actions/SessionActions.js
+++ b/src/store/actions/SessionActions.js
@@ -4,6 +4,8 @@ import {request} from '../../lib/Network';
import ROUTES from '../../ROUTES';
import STOREKEYS from '../STOREKEYS';
import CONFIG from '../../CONFIG';
+import Str from '../../lib/Str';
+import Guid from '../../lib/Guid';
/**
* Amount of time (in ms) after which an authToken is considered expired.
@@ -12,23 +14,36 @@ import CONFIG from '../../CONFIG';
* @private
* @type {Number}
*/
-const AUTH_TOKEN_EXPIRATION_TIME = 1000 * 60;
+const AUTH_TOKEN_EXPIRATION_TIME = 1000 * 60 * 90;
/**
* Create login
* @param {string} authToken
* @param {string} login
* @param {string} password
+ * @returns {Promise}
*/
function createLogin(authToken, login, password) {
- request('CreateLogin', {
+ return request('CreateLogin', {
authToken,
partnerName: CONFIG.EXPENSIFY.PARTNER_NAME,
partnerPassword: CONFIG.EXPENSIFY.PARTNER_PASSWORD,
partnerUserID: login,
partnerUserSecret: password,
- }).catch((err) => {
- Store.set(STOREKEYS.SESSION, {error: err});
+ }).then(() => Store.set(STOREKEYS.CREDENTIALS, {login, password}))
+ .catch(err => Store.set(STOREKEYS.SESSION, {error: err}));
+}
+
+/**
+ * Sets API data in the store when we make a successful "Authenticate"/"CreateLogin" request
+ * @param {object} data
+ * @returns {Promise}
+ */
+function setSuccessfulSignInData(data) {
+ return Store.multiSet({
+ [STOREKEYS.SESSION]: data,
+ [STOREKEYS.APP_REDIRECT_TO]: ROUTES.HOME,
+ [STOREKEYS.LAST_AUTHENTICATED]: new Date().getTime(),
});
}
@@ -42,56 +57,68 @@ function createLogin(authToken, login, password) {
*/
function signIn(login, password, useExpensifyLogin = false) {
let authToken;
- return Store.multiSet({
- [STOREKEYS.CREDENTIALS]: {login, password},
- [STOREKEYS.SESSION]: {},
+ return request('Authenticate', {
+ useExpensifyLogin,
+ partnerName: CONFIG.EXPENSIFY.PARTNER_NAME,
+ partnerPassword: CONFIG.EXPENSIFY.PARTNER_PASSWORD,
+ partnerUserID: login,
+ partnerUserSecret: password,
})
- .then(() => request('Authenticate', {
- useExpensifyLogin,
- partnerName: CONFIG.EXPENSIFY.PARTNER_NAME,
- partnerPassword: CONFIG.EXPENSIFY.PARTNER_PASSWORD,
- partnerUserID: login,
- partnerUserSecret: password,
- }))
.then((data) => {
authToken = data && data.authToken;
- // 404 We need to create a login
- if (data.jsonCode === 404 && !useExpensifyLogin) {
- return signIn(login, password, true)
- .then((newAuthToken) => {
- createLogin(newAuthToken, login, password);
- });
- }
-
// If we didn't get a 200 response from authenticate, the user needs to sign in again
if (data.jsonCode !== 200) {
// eslint-disable-next-line no-console
- console.warn('Did not get a 200 from authenticate, going back to sign in page');
- return Store.set(STOREKEYS.APP_REDIRECT_TO, ROUTES.SIGNIN);
+ console.debug('Non-200 from authenticate, going back to sign in page');
+ return Store.multiSet({
+ [STOREKEYS.CREDENTIALS]: {},
+ [STOREKEYS.SESSION]: {error: data.message},
+ [STOREKEYS.APP_REDIRECT_TO]: ROUTES.SIGNIN,
+ });
}
- return Store.multiSet({
- [STOREKEYS.SESSION]: data,
- [STOREKEYS.APP_REDIRECT_TO]: ROUTES.HOME,
- [STOREKEYS.LAST_AUTHENTICATED]: new Date().getTime(),
- });
+ // If Expensify login, it's the users first time logging in and we need to create a login for the user
+ if (useExpensifyLogin) {
+ return createLogin(data.authToken, Str.generateDeviceLoginID(), Guid())
+ .then(() => setSuccessfulSignInData(data));
+ }
+
+ return setSuccessfulSignInData();
})
.then(() => authToken)
.catch((err) => {
console.error(err);
- Store.set(STOREKEYS.SESSION, {error: err});
+ return Store.set(STOREKEYS.SESSION, {error: err.message});
});
}
+/**
+ * Delete login
+ * @param {string} authToken
+ * @param {string} login
+ * @returns {Promise}
+ */
+function deleteLogin(authToken, login) {
+ return request('DeleteLogin', {
+ authToken,
+ partnerName: CONFIG.EXPENSIFY.PARTNER_NAME,
+ partnerPassword: CONFIG.EXPENSIFY.PARTNER_PASSWORD,
+ partnerUserID: login,
+ }).catch(err => Store.set(STOREKEYS.SESSION, {error: err.message}));
+}
+
/**
* Sign out of our application
*
* @returns {Promise}
*/
-async function signOut() {
+function signOut() {
return Store.set(STOREKEYS.APP_REDIRECT_TO, ROUTES.SIGNIN)
- .then(Store.clear);
+ .then(() => Store.multiGet([STOREKEYS.SESSION, STOREKEYS.CREDENTIALS]))
+ .then(data => deleteLogin(data.session.authToken, data.credentials.login))
+ .then(Store.clear)
+ .catch(err => Store.set(STOREKEYS.SESSION, {error: err.message}));
}
/**
@@ -99,7 +126,7 @@ async function signOut() {
*
* @returns {Promise}
*/
-async function verifyAuthToken() {
+function verifyAuthToken() {
return Store.multiGet([STOREKEYS.LAST_AUTHENTICATED, STOREKEYS.CREDENTIALS])
.then(({last_authenticated, credentials}) => {
const haveCredentials = !_.isNull(credentials);