UNPKG

openhim-core

Version:

The OpenHIM core application that provides logging and routing of http requests

186 lines (142 loc) 7.44 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.fetchRewriteConfig = fetchRewriteConfig; exports.koaMiddleware = koaMiddleware; var _url = _interopRequireDefault(require("url")); var _winston = _interopRequireDefault(require("winston")); var utils = _interopRequireWildcard(require("../utils")); var router = _interopRequireWildcard(require("../middleware/router")); var _config = require("../config"); var _util = require("util"); function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const routerConf = _config.config.get('router'); // see https://regex101.com/r/lW0cN0/1 for an explanation of this regex const invertPathTransform = pathTransform => pathTransform.replace(/s\/(.*?)\/(.*?)(?:$|\/(.*)$)/, 's/$2/$1/$3'); function fetchRewriteConfig(channel, authType, callback) { // set the user defined rewrite config from current channel let rwConfig = []; if (channel.rewriteUrlsConfig != null) { rwConfig = rwConfig.concat(channel.rewriteUrlsConfig); } if (channel.addAutoRewriteRules) { /* * Add in default (virtual) rewrite rules for hosts we proxy * * For example if the SHR for some reason sent back a link to a patient in the CR * (using a direct link to the CR), then if we have a channel that points to the * CR on a primary route we are able to rewrite the link to point to us instead * because we know that host. */ return utils.getAllChannelsInPriorityOrder((err, channels) => { if (err != null) { return callback(err); } for (channel of Array.from(channels)) { for (const route of Array.from(channel.routes)) { if (route.primary) { /* * if this channel has a pathTranform on its primary route then * invert the path transform so that links that point to this route * have the path transform reversed when they are rewritten * * For example, say we have a channel with urlPattern=/CSD/ and a * pathTransform on the primary route as follows pathTransform=s/CSD/ihris/ * (ie. the actual server we are proxying is running on http://<host>:<port>/ihirs/). * If we get links back from this server it will be something like * http://<host>:<port>/ihirs/something/123 but we need it to be * http://<him_host>:<him_port>/CSD/something/123. To do this we can reverse * the pathTransform on the route (s/ihris/CSD/) and apply it while doing the * rewrite. */ let inverseTransform; let toPort; if (route.pathTransform) { inverseTransform = invertPathTransform(route.pathTransform); } // rewrite to the secure port if tls was used for this transaction if (authType != null === 'tls') { toPort = routerConf.httpsPort; } else { toPort = routerConf.httpPort; } // add 'virtual' rewrite config after any user defined config that has been set rwConfig.push({ fromHost: route.host, toHost: routerConf.externalHostname, fromPort: route.port, toPort, pathTransform: inverseTransform || null }); } } } return callback(null, rwConfig); }); } else { return callback(null, rwConfig); } } const rewriteUrls = (body, channel, authType, callback) => fetchRewriteConfig(channel, authType, (err, rwConfig) => { if (err != null) { return callback(err); } // rewrite each found href, src or fullUrl attribute (in JSON or XML) // See https://regex101.com/r/uY3fO1/1 for an explanation of this regex const newBody = body.replace(/["|']?(?:href|src|fullUrl)["|']?[:|=]\s?["|'](\S*?)["|']/g, (match, hrefUrl) => { let relativePath; const hrefUrlObj = _url.default.parse(hrefUrl); // default to using this channel's host if no host so we can match a rewrite rule if (hrefUrlObj.host == null) { for (const route of Array.from(channel.routes)) { if (route.primary) { hrefUrlObj.hostname = route.host; hrefUrlObj.port = route.port.toString(); relativePath = true; break; } } } for (const rewriteRule of Array.from(rwConfig)) { // if we find a matching rewrite rule if (rewriteRule.fromHost.toLowerCase() === hrefUrlObj.hostname && (rewriteRule.fromPort.toString() === hrefUrlObj.port || rewriteRule.fromPort === 80 && hrefUrlObj.port === null)) { hrefUrlObj.host = null; // so that hostname and port are used separately hrefUrlObj.hostname = rewriteRule.toHost; hrefUrlObj.port = rewriteRule.toPort; // rewrite protocol depending on the port the rewriteRule uses if (hrefUrlObj.protocol) { if (rewriteRule.toPort === routerConf.httpsPort) { hrefUrlObj.protocol = 'https'; } else { hrefUrlObj.protocol = 'http'; } } // if this rewrite rule requires the path to be transformed then do the transform if (rewriteRule.pathTransform) { hrefUrlObj.pathname = router.transformPath(hrefUrlObj.pathname, rewriteRule.pathTransform); } // we only run the first matching rule found break; } } if (relativePath) { // remove the host stuff before formating hrefUrlObj.host = null; hrefUrlObj.hostname = null; hrefUrlObj.port = null; } // replace the url in the match const replacement = _url.default.format(hrefUrlObj); _winston.default.debug(`Rewriting url ${hrefUrl} as ${replacement}`); return match.replace(hrefUrl, replacement); }); return callback(null, newBody); }); if (process.env.NODE_ENV === 'test') { exports.invertPathTransform = invertPathTransform; exports.rewriteUrls = rewriteUrls; } async function koaMiddleware(ctx, next) { // do nothing to the request await next(); // on response rewrite urls if (ctx.authorisedChannel.rewriteUrls) { const rewrite = (0, _util.promisify)(rewriteUrls); ctx.response.body = await rewrite(ctx.response.body.toString(), ctx.authorisedChannel, ctx.authenticationType); return _winston.default.info(`Rewrote url in the response of transaction: ${ctx.transactionId}`); } } //# sourceMappingURL=rewriteUrls.js.map