Skip to content

Commit

Permalink
XSOAR NG CoreRestAPI support (#23804)
Browse files Browse the repository at this point in the history
* fix

* yml fixes

* more fixes

* add support to Standard and Advanced

* fix readme and yml

* update RN

* Update Packs/DemistoRESTAPI/Integrations/CoreRESTAPI/CoreRESTAPI.yml

Co-authored-by: Anar Azadaliyev <aazadaliyev@paloaltonetworks.com>

* support empty auth_method

* remove marketplaces field

* auth ID handle and deprecate DemistoRestApi

* update RN

* fix validation errors

* remove additional info

* more fixes

* more fixes

* Add core-api-install-packs

* Fix names

* deprecate in description

* deprecate in description

* update RN

* more fixes

Co-authored-by: Anar Azadaliyev <aazadaliyev@paloaltonetworks.com>
  • Loading branch information
dansterenson and anara123 committed Jan 19, 2023
1 parent 6d18dfa commit 3633261
Show file tree
Hide file tree
Showing 8 changed files with 352 additions and 47 deletions.
241 changes: 205 additions & 36 deletions Packs/DemistoRESTAPI/Integrations/CoreRESTAPI/CoreRESTAPI.js
Expand Up @@ -2,38 +2,95 @@ var serverURL = params.url;
if (serverURL.slice(-1) === '/') {
serverURL = serverURL.slice(0,-1);
}
serverURL = serverURL + '/xsoar'

sendMultipart = function (uri, entryID, body) {
if (params.auth_id || (params.creds_apikey && params.creds_apikey.identifier)) {
serverURL = serverURL + '/xsoar'
}

var marketplace_url = params.marketplace_url? params.marketplace_url : 'https://storage.googleapis.com/marketplace-dist/content/packs/'

getTenantAccountName = function () {
// example: for 'https://account-testing-ysdkvou:443/acc_Test' will return 'acc_Test'
const urls = demistoUrls()
const server_url = urls['server'].toString()
// server_url example - https://account-testing-ysdkvou:443/acc_Test
var account_name = ''
// check if server_url contains "/acc_" string
if (server_url.indexOf("/acc_") >= 0){
const words = server_url.split('acc_')
const tenant_name = words[words.length - 1]
if (tenant_name !== "") {
account_name = 'acc_' + tenant_name
}
}
return account_name
}

getStandardAuthMethodHeaders = function(key, auth_id, content_type) {
return {
'Authorization': [key],
'x-xdr-auth-id': [auth_id],
'Content-Type': [content_type],
'Accept': ['application/json']
}
}

getAdvancedAuthMethodHeaders = function(key, auth_id, content_type,) {
const nonce = Array.from({length: 64}, () => Math.random().toString(36).charAt(2)).join("");
const timestamp = Date.now().toString();
var auth_key = key + nonce + timestamp
auth_key = unescape(encodeURIComponent(auth_key));
const auth_key_hash = SHA256_hash(auth_key)

return {
'x-xdr-timestamp': [timestamp],
'x-xdr-nonce': [nonce],
'x-xdr-auth-id': [auth_id],
'Authorization': [auth_key_hash],
'Content-Type': [content_type],
'Accept': ['application/json']
}
}

getRequestURL = function (uri) {
var requestUrl = serverURL;
if (uri.slice(-1) !== '/') {
if (params.use_tenant){
requestUrl += '/' + getTenantAccountName();
}
if (uri.slice(0, 1) !== '/') {
requestUrl += '/';
}
requestUrl += uri;
return requestUrl
}

sendMultipart = function (uri, entryID, body) {
var requestUrl = getRequestURL(uri)
try {
body = JSON.parse(body);
} catch (ex) {
// do nothing, use the body as is in the request.
logDebug('could not parse body as a JSON object, passing as is. body: ' + JSON.stringify(body));
}
var key = [params.apikey? params.apikey : (params.creds_apikey? params.creds_apikey.password : '')];
var key = params.apikey? params.apikey : (params.creds_apikey? params.creds_apikey.password : '');
if (key == ''){
throw 'API Key must be provided.';
}
var auth_id = [params.auth_id? params.auth_id : (params.creds_apikey? params.creds_apikey.identifier : '')];
if (auth_id == ''){
throw 'Auth ID must be provided.';
var auth_id = params.auth_id? params.auth_id : (params.creds_apikey? params.creds_apikey.identifier : '');
var headers = {}
// in case the integration was installed before auth_method was added, the auth_method param will be empty so
// we will use the standard auth method
if (!params.auth_method || params.auth_method == 'Standard'){
headers = getStandardAuthMethodHeaders(key, auth_id, 'multipart/form-data')
}
else if (params.auth_method == 'Advanced') {
headers = getAdvancedAuthMethodHeaders(key, auth_id, 'multipart/form-data')
}
var res = httpMultipart(
requestUrl,
entryID,
{
Headers: {
'Authorization': key,
'x-xdr-auth-id': auth_id,
'Content-Type': ['multipart/form-data'],
'Accept': ['application/json']
},
Headers: headers,
},
body,
params.insecure,
Expand All @@ -42,7 +99,7 @@ sendMultipart = function (uri, entryID, body) {
'file'
);
if (res.StatusCode < 200 || res.StatusCode >= 300) {
throw 'Demisto REST APIs - Request Failed.\nStatus code: ' + res.StatusCode + '.\nBody: ' + JSON.stringify(res) + '.';
throw 'Core REST APIs - Request Failed.\nStatus code: ' + res.StatusCode + '.\nBody: ' + JSON.stringify(res) + '.';
}
try {
var response = res.Body;
Expand All @@ -53,35 +110,35 @@ sendMultipart = function (uri, entryID, body) {
}
return {response: response};
} catch (ex) {
throw 'Demisto REST APIs - Error parsing response - ' + ex + '\nBody:' + res.Body;
throw 'Core REST APIs - Error parsing response - ' + ex + '\nBody:' + res.Body;
}

};

var sendRequest = function(method, uri, body, raw) {
var requestUrl = serverURL;
if (uri.slice(0, 1) !== '/') {
requestUrl += '/';
}
requestUrl += uri;
var key = [params.apikey? params.apikey : (params.creds_apikey? params.creds_apikey.password : '')];
var requestUrl = getRequestURL(uri)
var key = params.apikey? params.apikey : (params.creds_apikey? params.creds_apikey.password : '');
if (key == ''){
throw 'API Key must be provided.';
}
var auth_id = [params.auth_id? params.auth_id : (params.creds_apikey? params.creds_apikey.identifier : '')];
if (auth_id == ''){
throw 'Auth ID must be provided.';
var auth_id = params.auth_id? params.auth_id : (params.creds_apikey? params.creds_apikey.identifier : '');
var headers = {}
// in case the integration was installed before auth_method was added, the auth_method param will be empty so
// we will use the standard auth method
if (!params.auth_method || params.auth_method == 'Standard'){
headers = getStandardAuthMethodHeaders(key, auth_id, 'application/json')
}
else if (params.auth_method == 'Advanced') {
if (!auth_id) {
throw 'Core REST APIs - please choose "Standard Authentication method" or provide the Auth ID.';
}
headers = getAdvancedAuthMethodHeaders(key, auth_id, 'application/json')
}
var res = http(
requestUrl,
{
Method: method,
Headers: {
'Accept': ['application/json'],
'content-type': ['application/json'],
'authorization': key,
'x-xdr-auth-id': auth_id
},
Headers: headers,
Body: body,
SaveToFile: raw
},
Expand All @@ -90,7 +147,7 @@ var sendRequest = function(method, uri, body, raw) {
);

if (res.StatusCode < 200 || res.StatusCode >= 300) {
throw 'Demisto REST APIs - Request Failed.\nStatus code: ' + res.StatusCode + '.\nBody: ' + JSON.stringify(res) + '.';
throw 'Core REST APIs - Request Failed.\nStatus code: ' + res.StatusCode + '.\nBody: ' + JSON.stringify(res) + '.';
}
if (raw) {
return res;
Expand All @@ -104,12 +161,40 @@ var sendRequest = function(method, uri, body, raw) {
}
return {response: response};
} catch (ex) {
throw 'Demisto REST APIs - Error parsing response - ' + ex + '\nBody:' + res.Body;
throw 'Core REST APIs - Error parsing response - ' + ex + '\nBody:' + res.Body;
}
}
};

var deleteIncidents = function(ids_to_delete) {
function reduce_one_entry(data, keep_fields) {
var new_d = {};
for (var field_index = 0; field_index < keep_fields.length; field_index += 1) {
var field = keep_fields[field_index];
if (data[field]) {
new_d[field] = data[field];
}
}
return new_d;
}

function reduce_data(data, fields_to_keep) {
if (data instanceof Array) {
var new_data = [];
for (var data_index = 0; data_index < data.length; data_index += 1) {
var d = data[data_index];
new_data.push(reduce_one_entry(d, fields_to_keep));
}
return new_data;
}
else {
if (data.constructor == Object) {
return [reduce_one_entry(data, fields_to_keep)];
}
}
return data;
}

var deleteIncidents = function(ids_to_delete, fields_to_keep) {
var body = {
ids: ids_to_delete,
all: false,
Expand All @@ -121,8 +206,11 @@ var deleteIncidents = function(ids_to_delete) {
throw res[0].Contents;
}

var response = res['response']
var md = tableToMarkdown('Demisto delete incidents', response, ['data', 'total', "notUpdated"]);
var response = res['response'];
if (fields_to_keep && (fields_to_keep != "all")) {
response['data'] = reduce_data(response['data'], fields_to_keep);
}
var md = tableToMarkdown('Core delete incidents', response, ['data', 'total', "notUpdated"]);

return {
ContentsFormat: formats.json,
Expand All @@ -132,6 +220,83 @@ var deleteIncidents = function(ids_to_delete) {
};
};

var installPack = function(pack_url, entry_id, skip_verify, skip_validation){
let file_path;
if (entry_id){
file_path = entry_id;
}
else{
// download pack zip file
var res = http(
pack_url,
{
Method: 'GET',
Headers: {},
SaveToFile: true
});

if (res.StatusCode < 200 || res.StatusCode >= 300) {
throw 'Core REST APIs - Failed to download pack file from ' + pack_url;
}
file_path = res.Path;
}

let upload_url = 'contentpacks/installed/upload?'

// set the skipVerify parameter
if(isDemistoVersionGE('6.5.0')){
if (skip_verify && skip_verify === 'false') {
upload_url+='skipVerify=false'
}else{
upload_url+='skipVerify=true'
}
}

// set the skipValidation parameter
if(isDemistoVersionGE('6.6.0')){
if (skip_validation && skip_validation === 'false') {
upload_url+='&skipValidation=false'
}else{
upload_url+='&skipValidation=true'
}
}
// upload the pack
sendMultipart(upload_url, file_path,'{}');
};

var installPacks = function(packs_to_install, file_url, entry_id, skip_verify, skip_validation) {
if ((!packs_to_install) && (!file_url) && (!entry_id)) {
throw 'Either packs_to_install, file_url or entry_id argument must be provided.';
}
else if (file_url) {
installPack(file_url, undefined, skip_verify, skip_validation)
logDebug('Pack installed successfully from ' + file_url)
return 'The pack installed successfully from the file ' + file_url
}
else if (entry_id) {
installPack(undefined, entry_id, skip_verify, skip_validation)
logDebug('The pack installed successfully from the file.')
return 'The pack installed successfully from the file.'
}
else{
let installed_packs = []
let packs = JSON.parse(packs_to_install);

for (let pack_index = 0; pack_index < packs.length; pack_index += 1) {
let pack = packs[pack_index];
let pack_id = Object.keys(pack)[0]
let pack_version = pack[pack_id]

let pack_url = '{0}{1}/{2}/{3}.zip'.format(marketplace_url,pack_id,pack_version,pack_id)
installPack(pack_url, undefined, skip_verify, skip_validation)
logDebug(pack_id + ' pack installed successfully')
installed_packs.push(pack_id)
}

return 'The following packs installed successfully: ' + installed_packs.join(", ")
}
};

switch (command) {
case 'test-module':
sendRequest('GET','user');
Expand Down Expand Up @@ -174,7 +339,11 @@ switch (command) {
case 'demisto-delete-incidents':
case 'core-delete-incidents':
var ids = argToList(args.ids);
return deleteIncidents(ids);
var fields = argToList(args.fields);
return deleteIncidents(ids, fields);
case 'demisto-api-install-packs':
case 'core-api-install-packs':
return installPacks(args.packs_to_install, args.file_url, args.entry_id, args.skip_verify, args.skip_validation);
default:
throw 'Core REST APIs - unknown command';
}

0 comments on commit 3633261

Please sign in to comment.