-
Václav Bartoš authored
Needs some more testing, but everything seems to work well.
Václav Bartoš authoredNeeds some more testing, but everything seems to work well.
newcase.js 5.58 KiB
const request = require('request');
//const fs = require('fs');
//const path = require('path');
//const caFile = path.resolve(__dirname, '../../ca.cert.pem'); // TODO resolve where the CA file should be located / configured
export default function (server) {
server.route({
path: '/api/thehive_button/new_case',
method: 'POST',
handler: newCaseHandler,
});
server.route({
path: '/api/thehive_button/add_observables',
method: 'POST',
handler: addObservablesHandler,
});
}
// Handler of ajax requests to create a new Case in The Hive
function newCaseHandler(req, resp) {
// Parse the request to get connection parameters
// (everything is configured in forntend and sent as part of the request,
// since I don't know how to configure the backend)
var base_url = req.payload['base_url'];
var api_key = req.payload['api_key'];
var req_body = req.payload['body'];
// check it's a valid URL with slash at the end
if (!base_url) {
return {'error': 'Base URL not set'};
}
if (!base_url.match(/https?:\/\/(([a-z\d.-]+)|((\d{1,3}\.){3}\d{1,3}))(\:\d+)?(\/[-a-z\d%_.~+]*)*\//i)) {
//if (!base_url.match(/https?:\/\/.*\//)) {
return {'error': 'Invalid base URL (it must begin with "http[s]" and end with "/")'};
}
if (!api_key) {
return {'error': 'API key not set'};
}
return new Promise( function(resolve, reject) {
request({
method: 'POST',
url: base_url + 'api/case',
auth: {'bearer': api_key},
json: true,
body: req_body,
//ca: fs.readFileSync(caFile), // TODO resolve the issue with custom CA, where to get its cert?
rejectUnauthorized: false,
},
// handler of the reply from The Hive - just return as reply
function (error, response, body) {
// TODO: find out how to set response code, for now we always return sucess and encode original status code in the content
if (error) {
console.error("ERROR when trying to send request to The Hive:", error);
resolve({'error': error.message});
}
else {
if (response.statusCode < 200 || response.statusCode >= 300) {
console.error("ERROR Unexpected reply received from The Hive:", response.statusCode, response.statusMessage, "\n", body)
}
resolve({
'status_code': response.statusCode,
'status_msg': response.statusMessage,
'body': body
});
}
} // handler function
); // request()
}); // Promise()
}
// Note:
// There are two ways to create multiple Observables (artifacts) via The Hive API:
// 1. post one request with an array of observables in "data" field
// - this allows to create all in one request, but doesn't allow to set
// different parameters (IOC, TLP, etc.) to different observables
// 2. post each observable in a separate request
// The second way is used here.
// Handler of ajax requests to add Observables to a Case in The Hive
function addObservablesHandler(req, resp) {
// Parse the request to get connection parameters
// (everything is configured in forntend and sent as part of the request,
// since I don't know how to configure the backend)
var base_url = req.payload['base_url'];
var api_key = req.payload['api_key'];
// check it's a valid URL with slash at the end
if (!base_url) {
return {'error': 'Base URL not set'};
}
if (!base_url.match(/https?:\/\/(([a-z\d.-]+)|((\d{1,3}\.){3}\d{1,3}))(\:\d+)?(\/[-a-z\d%_.~+]*)*\//i)) {
//if (!base_url.match(/https?:\/\/.*\//)) {
return {'error': 'Invalid base URL (it must begin with "http[s]" and end with "/")'};
}
// TODO add "/" to the end automatically
if (!api_key) {
return {'error': 'API key not set'};
}
const caseid = req.payload['caseid'];
const observables = req.payload['observables']; // array of obersvable specifications
return new Promise( async function(resolve, reject) {
// Run one request for each observable
// (A way to run multiple async tasks sequentially inspired by:
// https://jrsinclair.com/articles/2019/how-to-run-async-js-in-parallel-or-sequential/ )
const starterPromise = Promise.resolve(null);
await observables.reduce(
(p, obs) => p.then(() => addObservable(base_url, api_key, caseid, obs)),
starterPromise
).catch((err_msg) => {
console.error(err_msg); // log whole message
resolve({'error': err_msg.split("\n", 1)[0]}); // send the first line to frontend
return;
}
);
resolve({});
});
}
function addObservable(base_url, api_key, caseid, obs) {
return new Promise( function(resolve, reject) {
//console.log("Adding observable:", obs);
request({
method: 'POST',
url: base_url + 'api/case/' + caseid + "/artifact",
auth: {'bearer': api_key},
json: true,
body: obs,
//ca: fs.readFileSync(caFile), // TODO resolve the issue with custom CA, where to get its cert?
rejectUnauthorized: false,
},
// handler of the reply from The Hive - just return as reply
function (error, response, body) {
if (error) {
reject("ERROR when trying to send request to The Hive: " + error);
}
else if (response.statusCode < 200 || response.statusCode >= 300) {
reject("ERROR: Unexpected reply received from The Hive: " + response.statusCode + " " + response.statusMessage + "\n" + JSON.stringify(body));
}
else {
// success - continue with the next observable
resolve("OK");
resolve({})
}
} // handler function
); // request()
}); //Promise()
}