Skip to content

Commit

Permalink
✨ Started working on server-side endoint for action buttons (gchq#383)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lissy93 committed Apr 16, 2022
1 parent 32ca899 commit ae94fdf
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 0 deletions.
11 changes: 11 additions & 0 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ require('./services/config-validator'); // Include and kicks off the config file

/* Include route handlers for API endpoints */
const statusCheck = require('./services/status-check'); // Used by the status check feature, uses GET
const actionButton = require('./services/action-buttons-call'); // Used by action buttons, to execute users web hooks
const saveConfig = require('./services/save-config'); // Saves users new conf.yml to file-system
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
Expand Down Expand Up @@ -84,6 +85,16 @@ const app = express()
printWarning(`Error running status check for ${req.url}\n`, e);
}
})
// GET endpoint for executing web-hooks for action buttons
.use(ENDPOINTS.actionButtonCall, (req, res) => {
try {
actionButton(req.url, async (results) => {
await res.end(results);
});
} catch (e) {
printWarning(`Error executing web hook for ${req.url}\n`, e);
}
})
// POST Endpoint used to save config, by writing conf.yml to disk
.use(ENDPOINTS.save, method('POST', (req, res) => {
try {
Expand Down
82 changes: 82 additions & 0 deletions services/action-buttons-call.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/**
* Endpoint called from the client, to execute action buttons,
* by making GET request to web hook URL, and returning response
*/
const axios = require('axios').default;
const https = require('https');

/* Makes human-readable response text for failed check */
const makeErrorMessage = (data) => `❌ Service Unavailable: ${data.hostname || 'Server'} `
+ `resulted in ${data.code || 'a fatal error'} ${data.errno ? `(${data.errno})` : ''}`;

/* Kicks of a HTTP request, then formats and renders results */
const makeRequest = (url, options, render) => {
const {
headers, enableInsecure, maxRedirects,
} = options;
const startTime = new Date();
// Create HTTPS agent for request
const requestMaker = axios.create({
httpsAgent: new https.Agent({
rejectUnauthorized: !enableInsecure,
}),
});
// Make request, with params
requestMaker.request({
url,
headers,
maxRedirects,
}).then((response) => ({
statusCode: response.status,
responseText: response.statusText,
successStatus: true,
timeTaken: (new Date() - startTime),
})).catch((error) => ({
successStatus: false,
message: makeErrorMessage(error),
})).then((results) => {
// Request completed (either successfully, or failed) - render results
render(JSON.stringify(results));
});
};

const decodeHeaders = (maybeHeaders) => {
if (!maybeHeaders) return {};
const decodedHeaders = decodeURIComponent(maybeHeaders);
let parsedHeaders = {};
try {
parsedHeaders = JSON.parse(decodedHeaders);
} catch (e) { /* Not valid JSON, will just return false */ }
return parsedHeaders;
};

/* Returned if the URL param is not present or correct */
const immediateError = (render) => {
render(JSON.stringify({
successStatus: false,
message: '❌ Missing URL or Malformed Options',
}));
};

/* Main function, will check if a URL present, and call function */
module.exports = (paramStr, render) => {
// If no parameters passed, then fail
if (!paramStr || !paramStr.includes('=')) {
immediateError(render);
return;
}
// Prepare the parameters, which are got from the URL
const params = new URLSearchParams(paramStr);
const url = decodeURIComponent(params.get('url'));
const maxRedirects = decodeURIComponent(params.get('maxRedirects')) || 0;
const headers = decodeHeaders(params.get('headers'));
const enableInsecure = !!params.get('enableInsecure');
// Check target URL is present
if (!url || url === 'undefined') immediateError(render);
// Put options together
const options = {
headers, enableInsecure, maxRedirects,
};
// Make the request
makeRequest(url, options, render);
};

0 comments on commit ae94fdf

Please sign in to comment.