From 676d1cb10625494f5a34bbde2f37c12e7f0a236e Mon Sep 17 00:00:00 2001 From: Alicia Sykes Date: Sun, 19 Dec 2021 20:05:15 +0000 Subject: [PATCH] :sparkles: Writes a CORS proxy, to secure widget requests --- server.js | 9 ++++++++ services/cors-proxy.js | 47 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 services/cors-proxy.js diff --git a/server.js b/server.js index 52703461..bc66efc3 100644 --- a/server.js +++ b/server.js @@ -26,6 +26,7 @@ const saveConfig = require('./services/save-config'); // Saves users new conf.ym const rebuild = require('./services/rebuild-app'); // A script to programmatically trigger a build const systemInfo = require('./services/system-info'); // Basic system info, for resource widget const sslServer = require('./services/ssl-server'); // TLS-enabled web server +const corsProxy = require('./services/cors-proxy'); // Enables API requests to CORS-blocked services /* Helper functions, and default config */ const printMessage = require('./services/print-message'); // Function to print welcome msg on start @@ -102,6 +103,14 @@ const app = express() } catch (e) { res.end(JSON.stringify({ success: false, message: e })); } + }) + // GET for accessing non-CORS API services + .use(ENDPOINTS.corsProxy, (req, res) => { + try { + corsProxy(req, res); + } catch (e) { + res.end(JSON.stringify({ success: false, message: e })); + } }); /* Create HTTP server from app on port, and print welcome message */ diff --git a/services/cors-proxy.js b/services/cors-proxy.js new file mode 100644 index 00000000..cb2d264f --- /dev/null +++ b/services/cors-proxy.js @@ -0,0 +1,47 @@ +/** + * A simple CORS proxy, for accessing API services which aren't CORS-enabled. + * Receives requests from frontend, applies correct access control headers, + * makes request to endpoint, then responds to the frontend with the response + */ + +const axios = require('axios'); + +module.exports = (req, res) => { + // Apply allow-all response headers + res.header('Access-Control-Allow-Origin', '*'); + res.header('Access-Control-Allow-Methods', 'GET, PUT, PATCH, POST, DELETE'); + if (req.header('access-control-request-headers')) { + res.header('Access-Control-Allow-Headers', req.header('access-control-request-headers')); + } + + // Pre-flight + if (req.method === 'OPTIONS') { + res.send(); + return; + } + + // Get desired URL, from Target-URL header + const targetURL = req.header('Target-URL'); + if (!targetURL) { + res.send(500, { error: 'There is no Target-Endpoint header in the request' }); + return; + } + // Apply any custom headers, if needed + const headers = req.header('CustomHeaders') ? JSON.parse(req.header('CustomHeaders')) : {}; + + // Prepare the request + const requestConfig = { + method: req.method, + url: targetURL + req.url, + json: req.body, + headers, + }; + + // Make the request, and respond with result + axios.request(requestConfig) + .then((response) => { + res.send(200, response.data); + }).catch((error) => { + res.send(500, { error }); + }); +};