Skip to content

Commit

Permalink
feat(cli): instance proxy server
Browse files Browse the repository at this point in the history
  • Loading branch information
mediremi committed Sep 6, 2021
1 parent ced1762 commit 02567be
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 2 deletions.
3 changes: 2 additions & 1 deletion adapter/src/components/LoginModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import i18n from '../locales'
import { post } from '../utils/api'

const staticUrl = process.env.REACT_APP_DHIS2_BASE_URL
const defaultUrl = process.env.REACT_APP_DHIS2_DEFAULT_BASE_URL

export const LoginModal = () => {
const [server, setServer] = useState(
staticUrl || window.localStorage.DHIS2_BASE_URL || ''
staticUrl || defaultUrl || window.localStorage.DHIS2_BASE_URL || ''
)
const [username, setUsername] = useState('')
const [password, setPassword] = useState('')
Expand Down
1 change: 1 addition & 0 deletions cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
"fs-extra": "^8.1.0",
"gaze": "^1.1.3",
"handlebars": "^4.3.3",
"http-proxy": "^1.18.1",
"i18next-conv": "^9",
"i18next-scanner": "^2.10.3",
"inquirer": "^7.3.3",
Expand Down
38 changes: 37 additions & 1 deletion cli/src/commands/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const i18n = require('../lib/i18n')
const loadEnvFiles = require('../lib/loadEnvFiles')
const parseConfig = require('../lib/parseConfig')
const makePaths = require('../lib/paths')
const createProxyServer = require('../lib/proxy')
const { compileServiceWorker } = require('../lib/pwa')
const makeShell = require('../lib/shell')
const { validatePackage } = require('../lib/validatePackage')
Expand All @@ -18,6 +19,8 @@ const handler = async ({
force,
port = process.env.PORT || defaultPort,
shell: shellSource,
proxy,
proxyPort,
}) => {
const paths = makePaths(cwd)

Expand All @@ -36,6 +39,30 @@ const handler = async ({
process.exit(1)
}

const newPort = await detectPort(port)

if (proxy) {
const newProxyPort = await detectPort(proxyPort)
const proxyBaseUrl = `http://localhost:${newProxyPort}`
process.env.DHIS2_DEFAULT_BASE_URL = proxyBaseUrl

reporter.print('')
reporter.info('Starting proxy server...')
reporter.print(
`The proxy for ${chalk.bold(
proxy
)} is now available on port ${newProxyPort}`
)
reporter.print('')

createProxyServer({
target: proxy,
baseUrl: proxyBaseUrl,
port: newProxyPort,
shellPort: newPort,
})
}

await exitOnCatch(
async () => {
if (!(await validatePackage({ config, paths, offerFix: false }))) {
Expand Down Expand Up @@ -77,7 +104,6 @@ const handler = async ({
reporter.info('Generating manifests...')
await generateManifests(paths, config, process.env.PUBLIC_URL)

const newPort = await detectPort(port)
if (String(newPort) !== String(port)) {
reporter.print('')
reporter.warn(
Expand Down Expand Up @@ -123,6 +149,16 @@ const command = {
type: 'number',
description: 'The port to use when running the development server',
},
proxy: {
alias: 'P',
type: 'string',
description: 'The remote DHIS2 instance the proxy should point to',
},
proxyPort: {
type: 'number',
description: 'The port to use when running the proxy',
default: 8080,
},
},
handler,
}
Expand Down
72 changes: 72 additions & 0 deletions cli/src/lib/proxy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
const url = require('url')
const { reporter } = require('@dhis2/cli-helpers-engine')
const httpProxy = require('http-proxy')

const stripCookieSecure = cookie => {
return cookie
.split(';')
.filter(v => v.trim().toLowerCase() !== 'secure')
.join('; ')
}

const rewriteLocation = ({ location, target, baseUrl }) => {
const parsedLocation = url.parse(location)
const parsedTarget = url.parse(target)
const parsedBaseUrl = url.parse(baseUrl)

if (
parsedLocation.host === parsedTarget.host &&
parsedLocation.pathname.startsWith(parsedTarget.pathname)
) {
return url.format({
...parsedBaseUrl,
pathname: parsedLocation.pathname.replace(
parsedTarget.pathname,
''
),
search: parsedLocation.search,
})
}
return location
}

exports = module.exports = ({ target, baseUrl, port, shellPort }) => {
const proxyServer = httpProxy.createProxyServer({
target,
changeOrigin: true,
secure: false,
protocolRewrite: 'http',
cookieDomainRewrite: '',
cookiePathRewrite: '/',
})

proxyServer.on('proxyRes', (proxyRes, req, res) => {
if (proxyRes.headers['access-control-allow-origin']) {
res.setHeader(
'access-control-allow-origin',
`http://localhost:${shellPort}`
)
}

if (proxyRes.headers.location) {
proxyRes.headers.location = rewriteLocation({
location: proxyRes.headers.location,
target,
baseUrl,
})
}

const sc = proxyRes.headers['set-cookie']
if (Array.isArray(sc)) {
proxyRes.headers['set-cookie'] = sc.map(stripCookieSecure)
}
})

proxyServer.on('error', error => {
reporter.warn(error)
})

proxyServer.listen(port)
}

exports.rewriteLocation = rewriteLocation
45 changes: 45 additions & 0 deletions cli/src/lib/proxy.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const { rewriteLocation } = require('./proxy')

describe('rewriteLocation', () => {
it('rewrites locations if they match the proxy target', () => {
const baseUrl = 'http://localhost:8080'

expect(
rewriteLocation({
location: 'https://play.dhis2.org/dev/login.action',
target: 'https://play.dhis2.org/dev',
baseUrl,
})
).toBe(`${baseUrl}/login.action`)

expect(
rewriteLocation({
location: 'https://play.dhis2.org/dev/page?param=value',
target: 'https://play.dhis2.org/dev',
baseUrl,
})
).toBe(`${baseUrl}/page?param=value`)
})

it('does not rewrite locations if they do not match the proxy target', () => {
;[
{
location: 'https://example.com/path',
target: 'https://play.dhis2.org/dev',
baseUrl: 'http://localhost:8080',
},
{
location: 'https://play.dhis2.org/2.35dev',
target: 'https://play.dhis2.org/dev',
baseUrl: 'http://localhost:8080',
},
{
location: 'http://server.com:1234',
target: 'http://server.com:5678',
baseUrl: 'http://localhost:8080',
},
].forEach(args => {
expect(rewriteLocation(args)).toBe(args.location)
})
})
})
9 changes: 9 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9746,6 +9746,15 @@ http-proxy@^1.17.0:
follow-redirects "^1.0.0"
requires-port "^1.0.0"

http-proxy@^1.18.1:
version "1.18.1"
resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549"
integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==
dependencies:
eventemitter3 "^4.0.0"
follow-redirects "^1.0.0"
requires-port "^1.0.0"

http-signature@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
Expand Down

0 comments on commit 02567be

Please sign in to comment.