dashboard/scripts/standalone/index.js

171 lines
5.1 KiB
JavaScript

const fs = require('fs');
const https = require('https');
const path = require('path');
const { createProxyMiddleware } = require('http-proxy-middleware');
const express = require('express');
const base = path.resolve(__dirname, '.');
const dist = path.resolve(base, 'ui');
const options = {
key: fs.readFileSync(path.resolve(base, 'cert/server.key')),
cert: fs.readFileSync(path.resolve(base, 'cert/server.crt'))
};
let api = process.env.API || 'http://localhost:8989';
if ( !api.startsWith('http') ) {
api = `https://${ api }`;
}
let PORT = process.env.PORT || '5443';
PORT = parseInt(PORT, 10);
if (isNaN(PORT)) {
console.log('Invalid port'); // eslint-disable-line no-console
process.exit(1);
}
const dev = (process.env.NODE_ENV !== 'production');
const devPorts = dev || process.env.DEV_PORTS === 'true';
const proxy = {
'/k8s': proxyWsOpts(api), // Straight to a remote cluster (/k8s/clusters/<id>/)
'/pp': proxyWsOpts(api), // For (epinio) standalone API
'/api': proxyWsOpts(api), // Management k8s API
'/apis': proxyWsOpts(api), // Management k8s API
'/v1': proxyWsOpts(api), // Management Steve API
'/v3': proxyWsOpts(api), // Rancher API
'/v3-public': proxyOpts(api), // Rancher Unauthed API
'/api-ui': proxyOpts(api), // Browser API UI
'/meta': proxyMetaOpts(api), // Browser API UI
'/rancherversion': proxyOpts(api), // Rancher version endpoint
'/v1-*': proxyOpts(api), // SAML, KDM, etc
// These are for Ember embedding
'/c/*/edit': proxyOpts('https://127.0.0.1:8000'), // Can't proxy all of /c because that's used by Vue too
'/k/': proxyOpts('https://127.0.0.1:8000'),
'/g/': proxyOpts('https://127.0.0.1:8000'),
'/n/': proxyOpts('https://127.0.0.1:8000'),
'/p/': proxyOpts('https://127.0.0.1:8000'),
'/assets': proxyOpts('https://127.0.0.1:8000'),
'/translations': proxyOpts('https://127.0.0.1:8000'),
'/engines-dist': proxyOpts('https://127.0.0.1:8000')
};
const proxies = {};
const app = express();
for (const [key, value] of Object.entries(proxy)) {
const config = createProxyMiddleware(value);
proxies[key] = config;
app.use(key, config);
}
app.use(express.static(dist));
// Catch reload on a dynamic page
// Check that the requestor will accept html and send them the index file
app.use('*', (req, res, next) => {
const accept = req.headers.accept || '';
const acceptArray = accept.split(',');
const html = acceptArray.find((h) => h.trim() === 'text/html');
if (html) {
return res.sendFile(path.join(dist, 'index.html'));
}
next();
});
const server = https.createServer(options, app);
const appServer = server.listen(PORT);
console.log(`Running Dashboard web server on port ${ PORT }`); // eslint-disable-line no-console
// Just proxy web sockets for v1 and v3 endpoints
appServer.on('upgrade', (req, socket, head) => {
if (req.url.startsWith('/v1')) {
return proxies['/v1'].upgrade(req, socket, head);
} else if (req.url.startsWith('/v3')) {
return proxies['/v3'].upgrade(req, socket, head);
} else if (req.url.startsWith('/k8s/')) {
return proxies['/k8s'].upgrade(req, socket, head);
} else {
console.log(`Unknown Web socket upgrade request for ${ req.url }`); // eslint-disable-line no-console
}
});
// ===============================================================================================
// Functions for the request proxying used in dev
// ===============================================================================================
function proxyMetaOpts(target) {
return {
target,
followRedirects: true,
secure: !dev,
ws: false,
changeOrigin: true,
onProxyReq,
onProxyReqWs,
onError,
onProxyRes,
};
}
function proxyOpts(target) {
return {
target,
secure: !devPorts,
ws: false,
changeOrigin: true,
onProxyReq,
onProxyReqWs,
onError,
onProxyRes,
};
}
function onProxyRes(proxyRes, req, res) {
if (devPorts) {
proxyRes.headers['X-Frame-Options'] = 'ALLOWALL';
}
}
function proxyWsOpts(target) {
return {
...proxyOpts(target),
ws: false,
changeOrigin: true,
secure: false,
};
}
function onProxyReq(proxyReq, req) {
if (!(proxyReq._currentRequest && proxyReq._currentRequest._headerSent)) {
proxyReq.setHeader('x-api-host', req.headers['host']);
proxyReq.setHeader('x-forwarded-proto', 'https');
// console.log(proxyReq.getHeaders());
}
}
function onProxyReqWs(proxyReq, req, socket, options, head) {
req.headers.origin = options.target.href;
proxyReq.setHeader('origin', `${ options.target.href }/`);
proxyReq.setHeader('x-api-host', req.headers['host']);
proxyReq.setHeader('x-forwarded-proto', 'https');
socket.on('error', (err) => {
console.error('Proxy WS Error:', err); // eslint-disable-line no-console
});
}
function onError(err, req, res) {
res.statusCode = 598;
console.error('Proxy Error:', err); // eslint-disable-line no-console
res.write(JSON.stringify(err));
}