Skip to content
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

[Web Proxy] Use staging server for Web, Desktop when the "Use staging server" toggle is ON. #16432

Merged
merged 10 commits into from
Mar 28, 2023
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
NEW_EXPENSIFY_URL=https://new.expensify.com/
SECURE_EXPENSIFY_URL=https://secure.expensify.com.dev/
EXPENSIFY_URL=https://www.expensify.com.dev/
STAGING_EXPENSIFY_URL=https://staging.expensify.com.dev/
STAGING_SECURE_EXPENSIFY_URL=https://staging-secure.expensify.com.dev/
Prince-Mendiratta marked this conversation as resolved.
Show resolved Hide resolved
EXPENSIFY_PARTNER_NAME=chat-expensify-com
EXPENSIFY_PARTNER_PASSWORD=e21965746fd75f82bb66
PUSHER_APP_KEY=ac6d22b891daae55283a
Expand Down
9 changes: 9 additions & 0 deletions config/proxyConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* These are the base API root used to send requests to the proxy.
Prince-Mendiratta marked this conversation as resolved.
Show resolved Hide resolved
* We only specify for staging URLs as API requests are sent to the production
* servers by default.
*/
module.exports = {
STAGING: '/staging-',
STAGING_SECURE: '/staging-secure-',
};
Prince-Mendiratta marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions config/webpack/webpack.dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ module.exports = (env = {}) => portfinder.getPortPromise({port: BASE_PORT})
: {
proxy: {
'/api': 'http://[::1]:9000',
'/staging': 'http://[::1]:9000',
'/chat-attachments': 'http://[::1]:9000',
},
};
Expand Down
1 change: 1 addition & 0 deletions src/CONFIG.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,5 @@ export default {
DEV_PORT: process.env.PORT || 8080,
E2E_TESTING: lodashGet(Config, 'E2E_TESTING', 'false') === 'true',
SEND_CRASH_REPORTS: lodashGet(Config, 'SEND_CRASH_REPORTS', 'false') === 'true',
IS_USING_WEB_PROXY: getPlatform() === 'web' && useWebProxy,
};
6 changes: 6 additions & 0 deletions src/libs/ApiUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import ONYXKEYS from '../ONYXKEYS';
import CONFIG from '../CONFIG';
import CONST from '../CONST';
import * as Environment from './Environment/Environment';
import proxyConfig from '../../config/proxyConfig';

// To avoid rebuilding native apps, native apps use production config for both staging and prod
// We use the async environment check because it works on all platforms
Expand Down Expand Up @@ -41,6 +42,11 @@ function getApiRoot(request) {
const shouldUseSecure = lodashGet(request, 'shouldUseSecure', false);

if (shouldUseStagingServer) {
if (CONFIG.IS_USING_WEB_PROXY) {
return shouldUseSecure
? proxyConfig.STAGING_SECURE
: proxyConfig.STAGING;
}
Prince-Mendiratta marked this conversation as resolved.
Show resolved Hide resolved
return shouldUseSecure
? CONFIG.EXPENSIFY.STAGING_SECURE_API_ROOT
: CONFIG.EXPENSIFY.STAGING_API_ROOT;
Expand Down
42 changes: 31 additions & 11 deletions web/proxy.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,18 @@
const http = require('http');
const https = require('https');
const proxyConfig = require('../config/proxyConfig');
require('dotenv').config();

if (process.env.USE_WEB_PROXY === 'false') {
process.stdout.write('Skipping proxy as USE_WEB_PROXY was set to false.\n');
process.exit();
}

let host = 'www.expensify.com';

// If we are testing against the staging API then we must use the correct host here or nothing with work.
if (/staging/.test(process.env.EXPENSIFY_URL)) {
host = 'staging.expensify.com';
}
const host = new URL(process.env.EXPENSIFY_URL || 'https://www.expensify.com').hostname;
const stagingHost = new URL(process.env.STAGING_EXPENSIFY_URL || 'https://staging.expensify.com').hostname;
const stagingSecureHost = new URL(process.env.STAGING_SECURE_EXPENSIFY_URL || 'https://staging-secure.expensify.com').hostname;
Prince-Mendiratta marked this conversation as resolved.
Show resolved Hide resolved
Prince-Mendiratta marked this conversation as resolved.
Show resolved Hide resolved

// eslint-disable-next-line no-console
console.log(`Creating proxy with host: ${host}`);
console.log(`Creating proxy with host: ${host} for production API and ${stagingHost} for staging API`);

/**
* Local proxy server that hits the production endpoint
Expand All @@ -24,13 +21,36 @@ console.log(`Creating proxy with host: ${host}`);
* environment that has no local API.
*/
const server = http.createServer((request, response) => {
let hostname = host;
let requestPath = request.url;

/**
* When a request is matching a proxy config path we might direct it to a different host (e.g. staging)
* For requests matching proxy config patterns we replace the mapping url (prefix) with the actual path.
* This is done because the staging api root is only intended for the proxy,
* the actual server request must use the /api path.
* For example,
* /api?command=OpenReport => request sent to production server
* /staging-api?command=OpenReport => request sent to staging server
* /staging-secure-api?command=OpenReport => request sent to secure staging server
* /chat-attachments/46545... => request sent to production server
* /staging-chat-attachments/46545... => request sent to staging server
Prince-Mendiratta marked this conversation as resolved.
Show resolved Hide resolved
*/
if (request.url.startsWith(proxyConfig.STAGING_SECURE)) {
hostname = stagingSecureHost;
requestPath = request.url.replace(proxyConfig.STAGING_SECURE, '/');
} else if (request.url.startsWith(proxyConfig.STAGING)) {
hostname = stagingHost;
requestPath = request.url.replace(proxyConfig.STAGING, '/');
}

const proxyRequest = https.request({
hostname: host,
hostname,
method: 'POST',
path: request.url,
path: requestPath,
headers: {
...request.headers,
host,
host: hostname,
'user-agent': request.headers['user-agent'].concat(' Development-NewDot/1.0'),
},
port: 443,
Expand Down