Skip to content

Commit

Permalink
Merge branch 'master' into tgolen-report-port
Browse files Browse the repository at this point in the history
  • Loading branch information
tgolen committed Aug 8, 2020
2 parents 3ad42d4 + c859882 commit cbeeb55
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 17 deletions.
2 changes: 1 addition & 1 deletion js/lib/DateUtils.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* globals moment */
import moment from 'moment';
import Str from './Str.js';

// Non-Deprecated Methods
Expand Down
5 changes: 3 additions & 2 deletions js/lib/Network.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ let isAppOffline = false;
* @param {string} [type]
* @returns {$.Deferred}
*/
async function request(command, data, type) {
async function request(command, data, type = 'post') {
console.debug(`Making "${command}" ${type} request`);
const formData = new FormData();
formData.append('authToken', await Store.get('session', 'authToken'));
for (const property in data) {
Expand All @@ -21,7 +22,7 @@ async function request(command, data, type) {
let response = await fetch(
`https://www.expensify.com.dev/api?command=${command}`,
{
method: 'post',
method: type,
body: formData,
},
);
Expand Down
1 change: 1 addition & 0 deletions js/store/STOREKEYS.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ export default {
ACTIVE_REPORT: 'active_report',
REPORTS: 'reports',
SESSION: 'session',
LAST_AUTHENTICATED: 'last_authenticated',
};
89 changes: 75 additions & 14 deletions js/store/actions/SessionActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,64 @@ import { request } from '../../lib/Network.js';
import ROUTES from '../../ROUTES.js';
import STOREKEYS from '../STOREKEYS.js';
import * as PersistentStorage from '../../lib/PersistentStorage.js';
import * as _ from 'lodash';

// TODO: Figure out how to determine prod/dev on mobile, etc.
const IS_IN_PRODUCTION = false;
const partnerName = IS_IN_PRODUCTION ? 'chat-expensify-com' : 'android';
const partnerPassword = IS_IN_PRODUCTION
? 'e21965746fd75f82bb66'
: 'c3a9ac418ea3f152aae2';

/**
* Amount of time (in ms) after which an authToken is considered expired.
* Currently set to 90min
*
* @private
* @type {Number}
*/
const AUTH_TOKEN_EXPIRATION_TIME = 1000 * 60;

/**
* Sign in with the API
* @param {string} login
* @param {string} password
* @param {boolean} useExpensifyLogin
*/
function signIn(login, password) {
function signIn(login, password, useExpensifyLogin = false) {
Store.set(STOREKEYS.CREDENTIALS, { login, password });
Store.set(STOREKEYS.SESSION, {});

request('Authenticate', {
useExpensifyLogin: true,
partnerName: 'expensify.com',
partnerPassword: 'MkgLvVAyaTlmw',
return request('Authenticate', {
useExpensifyLogin: useExpensifyLogin,
partnerName: partnerName,
partnerPassword: partnerPassword,
partnerUserID: login,
partnerUserSecret: password,
})
.then((data) => {
// 404 We need to create a login
if (data.jsonCode === 404 && !useExpensifyLogin) {
signIn(login, password, true).then((expensifyLoginData) => {
createLogin(expensifyLoginData.authToken, login, password);
});
return;
}

// If we didn't get a 200 response from authenticate, the user needs to sign in again
if (data.jsonCode !== 200) {
console.warn(
'Did not get a 200 from authenticate, going back to sign in page',
);
Store.set(STOREKEYS.APP_REDIRECT_TO, ROUTES.SIGNIN);
return;
}

Store.set(STOREKEYS.SESSION, data);
Store.set(STOREKEYS.APP_REDIRECT_TO, ROUTES.HOME);
Store.set(STOREKEYS.LAST_AUTHENTICATED, new Date().getTime());

return data;
})
.then((data) => {
Store.set(STOREKEYS.SESSION, data);
Store.set(STOREKEYS.APP_REDIRECT_TO, ROUTES.HOME);
Expand All @@ -30,6 +71,24 @@ function signIn(login, password) {
});
}

/**
* Create login
* @param {string} authToken
* @param {string} login
* @param {string} password
*/
function createLogin(authToken, login, password) {
request('CreateLogin', {
authToken: authToken,
partnerName,
partnerPassword,
partnerUserID: login,
partnerUserSecret: password,
}).catch((err) => {
Store.set(STOREKEYS.SESSION, { error: err });
});
}

/**
* Sign out of our application
*/
Expand All @@ -42,10 +101,15 @@ async function signOut() {
* Make sure the authToken we have is OK to use
*/
async function verifyAuthToken() {
const currentAuthToken = await Store.get(STOREKEYS.SESSION, 'authToken');
// If there is no authToken, then there is nothing to verify and they should sign in
if (!currentAuthToken) {
Store.set(STOREKEYS.APP_REDIRECT_TO, ROUTES.SIGNIN);
const lastAuthenticated = await Store.get(STOREKEYS.LAST_AUTHENTICATED);
const credentials = await Store.get(STOREKEYS.CREDENTIALS);
const haveCredentials = !_.isNull(credentials);
const haveExpiredAuthToken =
lastAuthenticated < new Date().getTime() - AUTH_TOKEN_EXPIRATION_TIME;

if (haveExpiredAuthToken && haveCredentials) {
console.debug('Invalid auth token: Token has expired.');
signIn(credentials.login, credentials.password);
return;
}

Expand All @@ -54,12 +118,9 @@ async function verifyAuthToken() {
console.debug('We have valid auth token');
Store.set(STOREKEYS.SESSION, data);
return;
} else if (data.jsonCode === 407) {
console.warn('We need to re-auth');
return;
}

// If the auth token is bad, we want them to go to the sign in page
// If the auth token is bad and we didn't have credentials saved, we want them to go to the sign in page
Store.set(STOREKEYS.APP_REDIRECT_TO, ROUTES.SIGNIN);
});
}
Expand Down
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"@react-native-community/async-storage": "^1.11.0",
"jquery": "^3.5.1",
"lodash": "^4.17.19",
"moment": "^2.27.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-native": "0.63.2",
Expand Down

0 comments on commit cbeeb55

Please sign in to comment.