Skip to content

Commit

Permalink
Merge pull request #3597 from Expensify/Rory-UseEncryptedAuthToken
Browse files Browse the repository at this point in the history
Use encrypted auth token for images
  • Loading branch information
roryabraham authored Jun 22, 2021
2 parents 0b5862d + cf8ec7e commit 76c3157
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 113 deletions.
50 changes: 0 additions & 50 deletions src/components/AnchorForCommentsOnly/AnchorWithAuthToken.js

This file was deleted.

13 changes: 7 additions & 6 deletions src/components/AnchorForCommentsOnly/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import {
propTypes as anchorForCommentsOnlyPropTypes,
defaultProps as anchorForCommentsOnlyDefaultProps,
} from './anchorForCommentsOnlyPropTypes';
import AnchorWithAuthToken from './AnchorWithAuthToken';
import BaseAnchorForCommentsOnly from './BaseAnchorForCommentsOnly';
import addEncryptedAuthTokenToURL from '../../libs/addEncryptedAuthTokenToURL';

const propTypes = {
/** Do we need an auth token to view this link or download the remote resource? */
Expand All @@ -27,11 +27,12 @@ const defaultProps = {
*/
const AnchorForCommentsOnly = (props) => {
const propsToPass = _.omit(props, 'isAuthTokenRequired');
return props.isAuthTokenRequired
// eslint-disable-next-line react/jsx-props-no-spreading
? <AnchorWithAuthToken {...propsToPass} />
// eslint-disable-next-line react/jsx-props-no-spreading
: <BaseAnchorForCommentsOnly {...propsToPass} />;
if (props.isAuthTokenRequired) {
propsToPass.href = addEncryptedAuthTokenToURL(props.href);
propsToPass.shouldDownloadFile = true;
}
// eslint-disable-next-line react/jsx-props-no-spreading
return <BaseAnchorForCommentsOnly {...propsToPass} />;
};

AnchorForCommentsOnly.propTypes = propTypes;
Expand Down
22 changes: 4 additions & 18 deletions src/components/AttachmentModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@ import React, {PureComponent} from 'react';
import PropTypes from 'prop-types';
import {View} from 'react-native';
import Str from 'expensify-common/lib/str';
import {withOnyx} from 'react-native-onyx';
import CONST from '../CONST';
import Modal from './Modal';
import AttachmentView from './AttachmentView';
import styles from '../styles/styles';
import themeColors from '../styles/themes/default';
import ONYXKEYS from '../ONYXKEYS';
import addAuthTokenToURL from '../libs/addAuthTokenToURL';
import addEncryptedAuthTokenToURL from '../libs/addEncryptedAuthTokenToURL';
import compose from '../libs/compose';
import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions';
import Button from './Button';
Expand Down Expand Up @@ -41,11 +39,6 @@ const propTypes = {
/** Do the urls require an authToken? */
isAuthTokenRequired: PropTypes.bool,

/** Current user session */
session: PropTypes.shape({
authToken: PropTypes.string.isRequired,
}).isRequired,

...withLocalizePropTypes,

...windowDimensionsPropTypes,
Expand Down Expand Up @@ -89,11 +82,9 @@ class AttachmentModal extends PureComponent {
}

render() {
const sourceURL = addAuthTokenToURL({
url: this.state.sourceURL,
authToken: this.props.session.authToken,
required: this.props.isAuthTokenRequired,
});
const sourceURL = this.props.isAuthTokenRequired
? addEncryptedAuthTokenToURL(this.state.sourceURL)
: this.state.sourceURL;

const attachmentViewStyles = this.props.isSmallScreenWidth
? [styles.imageModalImageCenterContainer]
Expand Down Expand Up @@ -164,10 +155,5 @@ AttachmentModal.propTypes = propTypes;
AttachmentModal.defaultProps = defaultProps;
export default compose(
withWindowDimensions,
withOnyx({
session: {
key: ONYXKEYS.SESSION,
},
}),
withLocalize,
)(AttachmentModal);
23 changes: 5 additions & 18 deletions src/components/ThumbnailImage.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import React, {PureComponent} from 'react';
import {View} from 'react-native';
import PropTypes from 'prop-types';
import {withOnyx} from 'react-native-onyx';
import ONYXKEYS from '../ONYXKEYS';
import ImageWithSizeCalculation from './ImageWithSizeCalculation';
import addAuthTokenToURL from '../libs/addAuthTokenToURL';
import addEncryptedAuthTokenToURL from '../libs/addEncryptedAuthTokenToURL';
import styles, {getWidthAndHeightStyle} from '../styles/styles';

const propTypes = {
Expand All @@ -15,11 +13,6 @@ const propTypes = {
// eslint-disable-next-line react/forbid-prop-types
style: PropTypes.any,

/** Current user session */
session: PropTypes.shape({
authToken: PropTypes.string.isRequired,
}).isRequired,

/** Do the urls require an authToken? */
isAuthTokenRequired: PropTypes.bool.isRequired,
};
Expand Down Expand Up @@ -50,11 +43,9 @@ class ThumbnailImage extends PureComponent {
}

render() {
const url = addAuthTokenToURL({
url: this.props.previewSourceURL,
authToken: this.props.session.authToken,
required: this.props.isAuthTokenRequired,
});
const url = this.props.isAuthTokenRequired
? addEncryptedAuthTokenToURL(this.props.previewSourceURL)
: this.props.previewSourceURL;

return (
<View
Expand All @@ -77,8 +68,4 @@ class ThumbnailImage extends PureComponent {

ThumbnailImage.propTypes = propTypes;
ThumbnailImage.defaultProps = defaultProps;
export default withOnyx({
session: {
key: ONYXKEYS.SESSION,
},
})(ThumbnailImage);
export default ThumbnailImage;
5 changes: 4 additions & 1 deletion src/libs/API.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,10 @@ function reauthenticate(command = '') {

// Update authToken in Onyx and in our local variables so that API requests will use the
// new authToken
Onyx.merge(ONYXKEYS.SESSION, {authToken: response.authToken});
Onyx.merge(ONYXKEYS.SESSION, {
authToken: response.authToken,
encryptedAuthToken: response.encryptedAuthToken,
});
authToken = response.authToken;

// The authentication process is finished so the network can be unpaused to continue
Expand Down
13 changes: 7 additions & 6 deletions src/libs/actions/Session.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function setSuccessfulSignInData(data) {
PushNotification.register(data.accountID);
Onyx.merge(ONYXKEYS.SESSION, {
shouldShowComposeInput: true,
..._.pick(data, 'authToken', 'accountID', 'email'),
..._.pick(data, 'authToken', 'accountID', 'email', 'encryptedAuthToken'),
});
}

Expand Down Expand Up @@ -143,9 +143,10 @@ 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
*/
function createTemporaryLogin(authToken, email) {
function createTemporaryLogin(authToken, encryptedAuthToken, email) {
const autoGeneratedLogin = Str.guid('expensify.cash-');
const autoGeneratedPassword = Str.guid();

Expand All @@ -163,7 +164,7 @@ function createTemporaryLogin(authToken, email) {
throw new Error(createLoginResponse.message);
}

setSuccessfulSignInData(createLoginResponse);
setSuccessfulSignInData({...createLoginResponse, encryptedAuthToken});

// If we have an old generated login for some reason
// we should delete it before storing the new details
Expand Down Expand Up @@ -211,8 +212,8 @@ function signIn(password, twoFactorAuthCode) {
email: credentials.login,
})
.then((authenticateResponse) => {
const {authToken, email} = authenticateResponse;
createTemporaryLogin(authToken, email);
const {authToken, encryptedAuthToken, email} = authenticateResponse;
createTemporaryLogin(authToken, encryptedAuthToken, email);
})
.catch((error) => {
Onyx.merge(ONYXKEYS.ACCOUNT, {error: error.message, loading: false});
Expand Down Expand Up @@ -256,7 +257,7 @@ function setPassword(password, validateCode, accountID) {
})
.then((response) => {
if (response.jsonCode === 200) {
createTemporaryLogin(response.authToken, response.email);
createTemporaryLogin(response.authToken, response.encryptedAuthToken, response.email);
return;
}

Expand Down
14 changes: 0 additions & 14 deletions src/libs/addAuthTokenToURL.js

This file was deleted.

19 changes: 19 additions & 0 deletions src/libs/addEncryptedAuthTokenToURL.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import lodashGet from 'lodash/get';
import Onyx from 'react-native-onyx';
import ONYXKEYS from '../ONYXKEYS';

let encryptedAuthToken = '';
Onyx.connect({
key: ONYXKEYS.SESSION,
callback: session => encryptedAuthToken = lodashGet(session, 'encryptedAuthToken', ''),
});

/**
* Add encryptedAuthToken to this attachment URL
*
* @param {String} url
* @returns {String}
*/
export default function (url) {
return `${url}?encryptedAuthToken=${encryptedAuthToken}`;
}
2 changes: 2 additions & 0 deletions src/libs/migrateOnyx.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import AddEncryptedAuthToken from './migrations/AddEncryptedAuthToken';
import RenameActiveClientsKey from './migrations/RenameActiveClientsKey';
import RenamePriorityModeKey from './migrations/RenamePriorityModeKey';

Expand All @@ -10,6 +11,7 @@ export default function () {
const migrationPromises = [
RenameActiveClientsKey,
RenamePriorityModeKey,
AddEncryptedAuthToken,
];

// Reduce all promises down to a single promise. All promises run in a linear fashion, waiting for the
Expand Down
41 changes: 41 additions & 0 deletions src/libs/migrations/AddEncryptedAuthToken.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import _ from 'underscore';
import Onyx from 'react-native-onyx';
import ONYXKEYS from '../../ONYXKEYS';
import {reauthenticate} from '../API';

/**
* This migration adds an encryptedAuthToken to the SESSION key, if it is not present.
*
* @returns {Promise}
*/
export default function () {
return new Promise((resolve) => {
const connectionID = Onyx.connect({
key: ONYXKEYS.SESSION,
callback: (session) => {
Onyx.disconnect(connectionID);

if (session && !_.isEmpty(session.encryptedAuthToken)) {
console.debug('[Migrate Onyx] Skipped migration AddEncryptedAuthToken');
return resolve();
}

if (!session || !session.authToken) {
console.debug('[Migrate Onyx] Skipped migration AddEncryptedAuthToken');
return resolve();
}

// If there is an auth token but no encrypted auth token, reauthenticate.
if (session.authToken && _.isUndefined(session.encryptedAuthToken)) {
return reauthenticate('Onyx_Migration_AddEncryptedAuthToken')
.then(() => {
console.debug('[Migrate Onyx] Ran migration AddEncryptedAuthToken');
return resolve();
});
}

return resolve();
},
});
});
}

0 comments on commit 76c3157

Please sign in to comment.