RSA NetWitness Security Analytics

RSA Security Analytics, compatible with prior to v11. A distributed and modular system that enables highly flexible deployment architectures that scale with the needs of the organization. Security Analytics allows administrators to collect two types of data from the network infrastructure, packet data and log data.

Analytics & SIEM · RSA NetWitness Security Analytics

Details

IDRSA NetWitness Security Analytics
ProviderPartnerOne
CategoryAnalytics & SIEM
From Version5.0.0
Supported ModulesAgentix XSIAM

README

RSA Security Analytics is a distributed and modular system that enables highly flexible deployment architectures that scale with the needs of the organization. Security Analytics allows administrators to collect two types of data from the network infrastructure, packet data and log data.
This integraitons should work with RSA Netwitness older than v11. For versions v11 and above use the integration RSA NetWitness v11.1.

Configure RSA NetWitness Security Analytics in Cortex

Parameter Description Required
url Server Url (192.168.56.101) True
username Username True
password Password True
isFetch Fetch incidents False
incidentType Incident type False
proxy Use system proxy settings False

Commands

You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.

nw-login


Logins to the system and returns valid sessionId

Base Command

nw-login

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

There is no context output for this command.

fetch-incidents


Simulates fetching incidents. Returns array of incidents from NetWitness.

Base Command

fetch-incidents

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

There is no context output for this command.

netwitness-im-list-incidents


Fetches incidents by filter

Base Command

netwitness-im-list-incidents

Input

Argument Name Description Required
query If query provided all other parameters ignored. Query should contain page, limit, start, sort and filter, joined by &, For example: page=1&start=0&limit=100&sort=[{“property”:”created”,”direction”:”DESC”}]&filter=[{“property”:”created”,”value”:[851171984031,1482323984031]}] Optional
page The default is 1. Indicates the page number of incidents Optional
start The default is 0. Indicates the start index of incident in page Optional
limit The default is 100. Limits the number of incidents per page Optional
sort By default sorts by “created” field in “DESC” order. Example: “[{"property":"created","direction":"DESC"}]” Optional
filter By default filters by “created” from 1996 to this date. Example: “[{"property":"id", "value":"INC-21"}]” Optional
incidentManagementId [optional number] This is the id of NetWitness INCIDENT_MANAGEMENT device/component id. It can be received by running netwitness-im-get-component command. If this argument is not filled/passed, the script will automatically get the first device of type INCIDENT_MANAGEMENT from the SA server. Optional
loadAlerts [optinal boolean] By default alerts and events related to incident not loaded. If loadAlerts is true, then command will load all alerts and their events from SA. Please be noticed THIS IS HAS PERFORMANCE IMPACT! For each alert XHR request send to SA. Optional

Context Output

Path Type Description
Netwitness.Incident.Id unknown Netwitness Incident ID
Netwitness.Incident.Name unknown Netwitness Incident Name
Netwitness.Incident.Priority unknown Netwitness Incident Priority
Netwitness.Incident.CreatedBy unknown User who created Netwitness Incident
Netwitness.Incident.Summary unknown Netwitness Incident Summary
Netwitness.Incident.Assignee unknown User Assigned To Incident
Netwitness.Incident.Created unknown Time of Incident Creation
Netwitness.Incident.FirstAlertTime unknown Time of Incident Creation
Netwitness.Incident.LastUpdatedByUserName unknown User who was last to update Incident
Netwitness.Incident.RiskScore unknown Netwitness Incident Risk Score
Netwitness.Incident.AverageAlertRiskScore unknown Netwitness Incident Average Risk Score
Netwitness.Incident.Categories unknown Netwitness Incident Category
Netwitness.Incident.AlertCount unknown Netwitness Incident Alerts Counts

netwitness-im-login


Logins to the system and returns valid sessionId

Base Command

netwitness-im-login

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

There is no context output for this command.

netwitness-im-get-components


Returns all the components in the system

Base Command

netwitness-im-get-components

Input

Argument Name Description Required
query [optional string] Query must contain page, start, limit Optional

Context Output

Path Type Description
Netwitness.Component.Id unknown Netwitness Component ID
Netwitness.Component.DisplayName unknown Netwitness Component DisplayName
Netwitness.Component.DeviceVersion unknown Netwitness Component Device Version
Netwitness.Component.DisplayType unknown Netwitness Component Device Type
Netwitness.Component.Host unknown Netwitness Component Device Host
Netwitness.Component.Port unknown Netwitness Component Device Port
Netwitness.Component.Validated unknown Netwitness Component is passed validation
Netwitness.Component.Licensed unknown Netwitness Component license
Netwitness.Component.Username unknown Netwitness Component User Name
Netwitness.Component.EnableSSL unknown Netwitness Component Enable SSL

netwitness-im-get-events


Returns all the events in defined time range

Base Command

netwitness-im-get-events

Input

Argument Name Description Required
timeRangeType Filter of time range in which events occured Required
deviceId [number] Id of the device where the events stored/occurred. In order to get list of available devices/components run command netwitness-im-get-components Required
collectionName [optional] Optional
predicateIds [optional] Optional
startDate [optional datetime] If timeRangeType defined as CUSTOM, set this argument Optional
endDate [optional datetime] If timeRangeType defined as CUSTOM, set this argument Optional
lastCollectionTime [optional datetime] Last collection time Optional
mid1 The unique meta id for this field. If nw-get-events was called this will be your starting id for this distinct value Optional
mid2 The unique meta id for this field. If nw-get-events was called this will be your ending id for this distinct value. Optional
investigationToken [optional guid] Investigation id token Optional
page [optional number] Default set to 1. The page number Optional
start [optional number] Default set to 0. The starting index of event in page. Optional
limit [optional number] Default set to 25. Limits the number of events per page Optional
sort By default sorts by “id” field in “ASC” order. Example: “[{"property":"id","direction":"ASC"}]” Optional
filter <string> Must provide key value pairs of fieldName and their value separated by comma. Example: “ip.src=1.1.1.1,meta.device.type="crowdstrike"” Optional

Context Output

There is no context output for this command.

netwitness-im-get-available-assignees


Returns the available users to be assigned to incidents

Base Command

netwitness-im-get-available-assignees

Input

| Argument Name | Description | Required |
| — | — | — |

Context Output

Path Type Description
Netwitness.Account.Id unknown Netwitness Account ID
Netwitness.Account.Name unknown Netwitness Account Name
Netwitness.Account.Login unknown Netwitness Account Login Name
Netwitness.Account.EmailAddress unknown Netwitness Account Email Address

netwitness-im-create-incident


Creating new incident

Base Command

netwitness-im-create-incident

Input

Argument Name Description Required
alertSummary [string] Short summary of the alert which will be attached to incident Required
severity [optional string] Default set to “50”. Optional
name [string] The name of the incident. Required
assigned [optional string] Set assignee login name if assignee has changed. You can execute netwitness-im-get-available-assignees to get the list of users. Example: demisto123 Optional
eventList List of event ids separated by comma [,] must not include spaces in it. In order to get list of events you can use netwitness-im-get-events Required
deviceId The id of the device/component (Concentrator, Log Decoder, Packet Decoder, etc.) from which the events are. You can view the list of devices by executing the command netwitness-im-get-components Required
priority Priority of the incident Required
summary Summary of the incident Optional
incidentManagementId [optional number] This is the id of NetWitness INCIDENT_MANAGEMENT device/component id. It can be received by running netwitness-im-get-component command. If this argument is not filled/passed, the script will automatically get the first device of type INCIDENT_MANAGEMENT from the SA server. Optional

Context Output

Path Type Description
Netwitness.Incident.Id unknown Netwitness Incident ID
Netwitness.Incident.Name unknown Netwitness Incident Name
Netwitness.Incident.Priority unknown Netwitness Incident Priority
Netwitness.Incident.CreatedBy unknown User who created Netwitness.Incident
Netwitness.Incident.AlertIDList unknown Alerts which rised by incident

netwitness-im-add-events-to-incident


This command will add new events to existing incident

Base Command

netwitness-im-add-events-to-incident

Input

Argument Name Description Required
incidentId [string] Existing incident id. Required
eventList [array of strings] List of event ids separated by comma [,] must not include spaces in it. In order to get list of events you can use netwitness-im-get-events. Example: “23,12,3” Required
alertSummary [string] Short summary of the alert which will be attached to incident Required
severity [number] Severity of the incident. Example: 50 Required
deviceId [number] The id of the device/component (Concentrator, Log Decoder, Packet Decoder, etc.) from which the events are. You can view the list of devices by executing the command netwitness-im-get-components Required
incidentManagementId [optional number] This is the id of NetWitness INCIDENT_MANAGEMENT device/component id. It can be received by running netwitness-im-get-component command. If this argument is not filled/passed, the script will automatically get the first device of type INCIDENT_MANAGEMENT from the SA server. Optional

Context Output

There is no context output for this command.

netwitness-im-update-incident


Updates incident

Base Command

netwitness-im-update-incident

Input

Argument Name Description Required
idList List of incident ids which will be updated, separated by comma [,]. Must not contain spaces. Example: “INC-13,INC-15,INC-23” Required
name [optional string] Set name if incident name has been changed Optional
summary [optional string] Updated incident summary Optional
assignee [optional string] Set assignee login name if assignee has changed. You can execute netwitness-im-get-available-assignees to get the list of users. Example: demisto123 Optional
comment [optional string] Add a journal entry describing your changes Optional
status [optional status] Set status if changed Optional
priority [optional priority] Set priority if incident priority has been changed Optional
categories List of categories. Optional
incidentManagementId [optional number] This is the id of NetWitness INCIDENT_MANAGEMENT device/component id. It can be received by running netwitness-im-get-component command. If this argument is not filled/passed, the script will automatically get the first device of type INCIDENT_MANAGEMENT from the SA server. Optional

Context Output

There is no context output for this command.

netwitness-im-get-alerts


Return all the alerts filtered by filter.

Base Command

netwitness-im-get-alerts

Input

Argument Name Description Required
page The default is 1. Indicates the page number of incidents Optional
start The default is 0. Indicates the start index of incident in page Optional
limit The default is 100. Limits the number of incidents per page Optional
sort By default sorts by “alert.timestamp” field in “DESC” order. Example: “[{"property":"alert.timestamp","direction":"DESC"}]” Optional
filter By default filters by “alert.timestamp” from 1996 to this date. Example: “[{"property":"incidentId", "value":"INC-21"}]” Optional

Context Output

There is no context output for this command.

netwitness-im-get-alert-details


Return single alert by id

Base Command

netwitness-im-get-alert-details

Input

Argument Name Description Required
alertId Alert id Required

Context Output

Path Type Description
Netwitness.Alert.Id unknown Netwitness Alert ID
Netwitness.Alert.Name unknown Netwitness Alert Name
Netwitness.Alert.IncidentId unknown Id of Incident which caused to Alert
Netwitness.Alert.Timestamp unknown Time of Alert
Netwitness.Alert.HostSummary unknown Netwitness Alert Summary
Netwitness.Alert.SignatureId unknown Singnature Id of Alert
Netwitness.Alert.Source unknown Score of Alert
Netwitness.Alert.Type unknown Type of Alert
Netwitness.Alert.RiskScore unknown Risk score of Alert
Netwitness.Alert.SourceCountry unknown Netwitness Alert Source Country
Netwitness.Alert.DestinationCountry unknown Netwitness Alert Destination Country
Netwitness.Alert.NumEvents unknown Netwitness Alert Evevts Number
Netwitness.Alert.SourceIp unknown Netwitness Alert Source Ip
Netwitness.Alert.DestonationIp unknown Netwitness Alert Destonation Ip
Netwitness.Alert.DestonationPort unknown Netwitness Alert Destonation Port

netwitness-im-get-event-details


Returns two entries. One is event details json and the second is

Base Command

netwitness-im-get-event-details

Input

Argument Name Description Required
deviceId [number] Id of the device where the events stored/occurred. In order to get list of available devices/components run command netwitness-im-get-components Required
eventId [number] Id of the event Required

Context Output

Path Type Description
Netwitness.Event.EventId unknown Netwitness Event ID
Netwitness.Event.DeviceId unknown Netwitness Event Device Id
Netwitness.Event.ReconstructedContentType unknown Netwitness Event Reconstructed Content
Netwitness.Event.PacketsTotal unknown Total Packets Netwitness Event
Netwitness.Event.PacketsProcessed unknown Packets Processed in Current Event

netwitness-im-get-incident-details


Returns incident json by id

Base Command

netwitness-im-get-incident-details

Input

Argument Name Description Required
incidentId [number] ID of incident. Example: “INC-12” Required

Context Output

Path Type Description
Netwitness.Incident.Id unknown Netwitness Incident ID
Netwitness.Incident.Name unknown Netwitness Incident Name
Netwitness.Incident.Priority unknown Netwitness Incident Priority
Netwitness.Incident.CreatedBy unknown User who created Netwitness Incident
Netwitness.Incident.Summary unknown Netwitness Incident Summary
Netwitness.Incident.Assignee unknown User Assigned To Incident
Netwitness.Incident.Created unknown Time of Incident Creation
Netwitness.Incident.FirstAlertTime unknown Time of Incident Creation
Netwitness.Incident.LastUpdatedByUserName unknown User who was last to update Incident
Netwitness.Incident.RiskScore unknown Netwitness Incident Risk Score
Netwitness.Incident.AverageAlertRiskScore unknown Netwitness Incident Average Risk Score
Netwitness.Incident.Categories unknown Netwitness Incident Category
Netwitness.Incident.AlertCount unknown Netwitness Incident Alerts Counts

netwitness-im-get-alert-original


Returns the original events which this alert contains

Base Command

netwitness-im-get-alert-original

Input

Argument Name Description Required
alertId Id of the alert Required

Configuration parameters

  • url — Server Url (192.168.56.101) (required)
  • username — Username
  • password — Password
  • credentials — Username
  • isFetch — Fetch incidents
  • incidentType — Incident type
  • incidentFetchInterval — Incidents Fetch Interval
  • proxy — Use system proxy settings

Commands (27)

  • fetch-incidents

    Simulates fetching incidents. Returns array of incidents from NetWitness.

  • netwitness-im-add-events-to-incident

    This command will add new events to existing incident.

  • netwitness-im-create-incident

    Creating new incident.

  • netwitness-im-get-alert-details

    Return single alert by id

  • netwitness-im-get-alert-original

    Returns the original events which this alert contains.

  • netwitness-im-get-alerts

    Return all the alerts filtered by filter.

  • netwitness-im-get-available-assignees

    Returns the available users to be assigned to incidents.

  • netwitness-im-get-components

    Returns all the components in the system.

  • netwitness-im-get-event-details

    Returns two entries. One is event details json and the second is.

  • netwitness-im-get-events

    Returns all the events in defined time range.

  • netwitness-im-get-incident-details

    Returns incident json by id.

  • netwitness-im-list-incidents

    Fetches incidents by filter.

  • netwitness-im-login

    Logins to the system and returns valid sessionId.

  • netwitness-im-update-incident

    Updates incident.

  • nw-add-events-to-incident Deprecated

    This command will add new events to existing incident.

  • nw-create-incident Deprecated

    Creating new incident.

  • nw-get-alert-details Deprecated

    Return single alert by id

  • nw-get-alert-original Deprecated

    Returns the original events which this alert contains.

  • nw-get-alerts Deprecated

    Return all the alerts filtered by filter.

  • nw-get-available-assignees Deprecated

    Returns the available users to be assigned to incidents.

  • nw-get-components Deprecated

    Returns all the components in the system.

  • nw-get-event-details Deprecated

    Returns two entries. One is event details json and the second is event/session content.

  • nw-get-events Deprecated

    Returns all the events in defined time range.

  • nw-get-incident-details Deprecated

    Returns incident json by id.

  • nw-list-incidents Deprecated

    Fetches incidents by filter.

  • nw-login

    Logins to the system and returns valid sessionId.

  • nw-update-incident Deprecated

    Updates incident.

var url = params.url;
if (url.indexOf("https://") < 0) {
    url = 'https://' + url;
}
var username = params.credentials ?  params.credentials.identifier : params.username;
var password = params.credentials ?  params.credentials.password : params.password;
var proxy = params.proxy || false;
var COOKIE_PREFIX = 'RSA_SA_LICENSE=true; JSESSIONID=';

function FailedRequestError(message, url, query, reqBody, resBody) {
    return {
        message: message,
        url: url,
        query: query,
        reqBody: reqBody,
        resBody: resBody,
        toString: function() {
            var error = [
                message,
                'Request url: ' + url,
            ];

            if (query) {
                error.push('Request query: ' + JSON.stringify(query));
            }
            if (reqBody) {
                error.push('Request body:' + JSON.stringify(reqBody));
            }

            error.push('Response: ' + resBody);

            return error.join('\n');
        }
    };
}

function escapeRegExp(str) {
    return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
}

function replaceAll(str, find, replace) {
    return str.replace(new RegExp(escapeRegExp(find), 'g'), replace);
}

function login(url, username, password) {
    if (!(username && password)){
        raise ('Username and Password must be provided.');
    }
    var fullUrl = url + '/j_spring_security_check';
    var res = http(
        fullUrl,
        {
            Method: 'POST',
            Headers: {
                'Origin': [url],
                'Content-Type': ['application/x-www-form-urlencoded'],
                'Referer': [url + '/login']
            },
            Body: 'j_username=' + username + '&j_password=' + password
        },
        true,
        proxy,
        true
    );

    if (res.StatusCode !== 302) {
        throw 'Failed to login with status [' + res.StatusCode + ']. Expected status 302. Check username or password. \nOriginal error: ' + res.Body;
    }

    var sessionId = null;
    res.Cookies.forEach(function(cookie) {
        if (cookie.Name === 'JSESSIONID') {
            sessionId = cookie.Value;
        }
    });

    try {
        getAvailableAssignees(sessionId);
    } catch(err) {
        throw 'Failed to login! Check username or password. Error: ' + err;
    }

    return sessionId;
}

function logout(url, sessionId) {
    var fullUrl = url + '/j_spring_security_logout';

    var res = http(
        fullUrl,
        {
            Method: 'GET',
            Headers: {
                'Origin': [url],
                'Content-Type': ['application/x-www-form-urlencoded'],
                'Cookie': [COOKIE_PREFIX + sessionId]
            }
        },
        true,
        proxy,
        true
    );

    if (res.StatusCode !== 302) {
        throw 'Failed to logout with status [' + res.StatusCode + ']. Expected status 302.\nOriginal error: ' + res.Body;
    }
}

function createQuery(args, defaultQuery) {
    args = args || {};
    defaultQuery = defaultQuery || {};
    var query = {};

    if (args.page || defaultQuery.page) {
        query.page = args.page || defaultQuery.page;
    }

    if (args.start || defaultQuery.start) {
        query.start = args.start || defaultQuery.start;
    }

    if (args.limit || defaultQuery.limit) {
        query.limit = args.limit || defaultQuery.limit;
    }

    if (args.sort || defaultQuery.sort) {
        query.sort = args.sort || defaultQuery.sort;
    }

    if (args.filter || defaultQuery.filter) {
        query.filter = args.filter || defaultQuery.filter;
    }

    return query;
}

function createQueryFromString(q) {
    if (!q.match(/(.*=.*&)*(.*=.*)/)) {
        throw 'invalid query. query must be of structure: key1=value1&key2=value2&keyN=valueN';
    }
    var query = replaceAll(q, '\"', '"')
        .split('&')
        .reduce(function(qArgs, nextArg) {
            var na = nextArg.split('=');
            var argKey = na[0];
            var argValue = na[1];
            qArgs[argKey] = argValue;
            return qArgs;
        }, {});

    return query;
}

var defaultIncidentFilter = {
    page: 1,
    start: 0,
    limit: 50,
    sort: JSON.stringify([
        {
            property:'created',
            direction: 'DESC'
        }
    ]),
    filter: JSON.stringify([
        {
            property: 'created',
            value: [
                851171984031, // year 1996
                new Date().getTime()
            ]
        }
    ])
};

function listIncidents(sessionId, args, incidentManagementId) {
    var fullUrl = url + '/ajax/incidents/' + incidentManagementId;
    var query = {};
    if (args.query) {
        query = createQueryFromString(args.query);
    } else {
        query = createQuery(args, defaultIncidentFilter);
    }

    fullUrl += encodeToURLQuery(query);

    var res = http(
        fullUrl,
        {
            Method: 'GET',
            Headers: {
                'Cookie': [COOKIE_PREFIX + sessionId]
            }
        },
        true,
        proxy
    );

    if (res.StatusCode < 200 || res.StatusCode >= 300) {
        throw 'Failed to fetch incidents with status [' + res.StatusCode + ']. \nOriginal error: ' + res.Body;
    }

    try {
        incidentsRes = JSON.parse(res.Body);
        if (incidentsRes.success) {
            var incidents = incidentsRes.data;
            if (!args.loadAlerts) {
                return incidents;
            }

            // loading all the alerts which related to incident
            // we load the alerts and original alerts which contains the original events which the alert created from
            // this has performance impact
            for (var i = 0; i < incidents.length; i++) {
                var alerts = filterAlerts(sessionId, {
                    filter: JSON.stringify([
                        {
                            property: 'incidentId',
                            value: incidents[i].id
                        }
                    ])
                })
                incidents[i].alerts = [];
                alerts.forEach(function(alert) {
                    var originalAlert = getOriginalAlertById(sessionId, { alertId: alert.id });
                    incidents[i].alerts.push({
                        alert: alert,
                        orignalAlert: originalAlert
                    });
                });
            }

            return incidents;
        } else {
            throw FailedRequestError('Fetch incidents failed.', fullUrl, query, null, incidentsRes).toString();
        }
    } catch (err) {
        throw FailedRequestError('Unexpected error while fetching incidents. \nOriginal error: ' + err, fullUrl, query, null, res.Body).toString();
    }
}

function fetchIncidents(sessionId, args, incidentManagementId) {
    var now = new Date().getTime();
    var lastRun = getLastRun().lastRun || now - 1*60*1000; // last minute
    var lastRunNext = lastRun;

    var tillNow = now;
    var query = {
        loadAlerts: true,
        page: 1,
        start: 0,
        limit: 50,
        filter: JSON.stringify([{
            property: 'created',
            value: [
                lastRun,
                tillNow
            ]
        }])
    };

    // TODO handle paging. If number of incidents are more than 50, then we need to
    // fetch the next pages too.
    var lastIncidents = listIncidents(sessionId, query, incidentManagementId);
    var convertedIncidents = [];
    for (var i = 0; i < lastIncidents.length; i++) {
        var inc = lastIncidents[i];
        if (inc.created > lastRunNext) {
            // we get the last incident which created
            lastRunNext = inc.created + 1;
        }

        convertedIncidents.push({
            name: inc.id,
            occurred: new Date(inc.firstAlertTime),
            owner: inc.assignee ? inc.assignee.login : '',
            reason: inc.name,
            rawJSON: JSON.stringify(inc)
        });
    }

    setLastRun({ lastRun: lastRunNext });
    return JSON.stringify(convertedIncidents);
}

function getIncidentById(sessionId, args, incidentManagementId) {
    var fullUrl = [
        url,
        'ajax/incident',
        incidentManagementId,
        args.incidentId
    ].join('/');

    var res = http(
        fullUrl,
        {
            Method: 'GET',
            Headers: {
                'Cookie': [COOKIE_PREFIX + sessionId]
            }
        },
        true,
        proxy
    );

    if (res.StatusCode < 200 || res.StatusCode >= 300) {
        throw 'Failed to get incident by id with status [' + res.StatusCode + ']. \nOriginal error: ' + res.Body;
    }

    try {
        incident = JSON.parse(res.Body);
        if (incident.success) {
            return incident.data;
        } else {
            throw FailedRequestError('Fetch incident by id failed.', fullUrl, null, null, incident).toString();
        }
    } catch (err) {
        throw FailedRequestError('Unexpected error while fetching incident by id. \nOriginal error: ' + err, fullUrl, null, null, res.Body).toString();
    }
}

var defaultComponentFilter = {
    page: 1,
    start: 0,
    limit: 1000,
    sort: replaceAll(JSON.stringify([
        {
            property: 'displayName',
            direction: 'ASC'
        }
    ]), '\"', '"')
};

function getComponents(sessionId, argz, types) {
    var fullUrl = url + '/common/devices';
    var query = {};
    if (argz.query) {
        query = createQueryFromString(argz.query);
    } else {
        query = createQuery(argz, defaultComponentFilter);
    }
    fullUrl += types ? '/types/' + types.join('/') : '';
    fullUrl += encodeToURLQuery(query);

    var res = http(
        fullUrl,
        {
            Method: 'GET',
            Headers: {
                'Cookie': [COOKIE_PREFIX + sessionId]
            }
        },
        true,
        proxy
    );

    if (res.StatusCode < 200 || res.StatusCode >= 300) {
        throw 'Failed to fetch components with status [' + res.StatusCode + ']. \nOriginal error: ' + res.Body;
    }

    try {
        components = JSON.parse(res.Body);
        if (components.success) {
            return components.data;
        } else {
            throw FailedRequestError('Fetch components failed.', fullUrl, query, null, components).toString();
        }
    } catch (err) {
        throw FailedRequestError('Unexpected error when fetching components. \nOriginal error: ' + err, fullUrl, query, null, res.Body).toString();
    }
}

function getIncidentManagementId(sessionId) {
    var incidentManagement = getComponents(sessionId, {}, ['INCIDENT_MANAGEMENT']);

    if (!incidentManagement || incidentManagement.length === 0) {
        throw 'Failed to find RSA NetWitness INCIDENT_MANAGEMENT component/device: ' + JSON.stringify(incidentManagement);
    }

    return incidentManagement[0].id;
}

function createEventsQuery(args, predicateIds) {
    args = args || {};
    var query = {};

    query.deviceId = args.deviceId;
    query.collectionName = args.collectionName || '';
    query.predicateIds = predicateIds ? predicateIds.join(',') : '';
    query.timeRangeType = args.timeRangeType;
    query.startDate = args.startDate || '';
    query.endDate = args.endDate || '';
    query.lastCollectionTime = args.lastCollectionTime || '';
    query.mid1 = args.mid1 || 0;
    query.mid2 = args.mid2 || 0;
    query.investigationToken = args.investigationToken || '';
    query.page = args.page || 1;
    query.start = args.start || 0;
    query.limit = args.limit || 25;
    query.sort = args.sort
        ? replaceAll(args.sort, '\"', '"')
        : JSON.stringify([
            {
                property: 'id',
                direction: 'ASC'
            }
        ]);

    return query;
}
function getEvents(sessionId, args) {
    var predicateIds = [];
    if (args.filter) {
        var eventsViewHTML = getEventsViewHtml(sessionId);
        var csrfToken = extractCsrfTokenFromHTML(eventsViewHTML);
        var filters = args.filter.split(',');
        for (var i = 0; i < filters.length; i++) {
            var predicate = postEventsTransient(sessionId, filters[i], csrfToken);
            predicateIds.push(predicate);
        }
    }
    var query = createEventsQuery(args, predicateIds);
    var fullUrl = url + '/ajax/investigation/events' + encodeToURLQuery(query);

    var res = http(
        fullUrl,
        {
            Method: 'GET',
            Headers: {
                'Cookie': [COOKIE_PREFIX + sessionId]
            }
        },
        true,
        proxy
    );

    if (res.StatusCode < 200 || res.StatusCode >= 300) {
        throw 'Failed to fetch events with status [' + res.StatusCode + ']. \nOriginal error: ' + res.Body;
    }

    try {
        events = JSON.parse(res.Body);
        if (events.success) {
            return events.data;
        } else {
            throw FailedRequestError('Fetch events failed.', fullUrl, query, null, events).toString();
        }
    } catch (err) {
        throw FailedRequestError('Unexpected while fetching events. \nOriginal error: ' + err, fullUrl, query, null, res.Body).toString();
    }
}
function postEventsTransient(sessionId, query, ctoken) {
    var fullUrl = url + '/predicates/transient';
    var body = {
        name: query,
        query: query,
        ctoken: ctoken
    };
    var res = http(
        fullUrl,
        {
            Method: 'POST',
            Headers: {
                'Cookie': [COOKIE_PREFIX + sessionId],
                'Content-Type': ['application/x-www-form-urlencoded']
            },
            Body: encodeToURLQuery(body).replace(/^\?/, '')
        },
        true,
        proxy
    );

    if (res.StatusCode < 200 || res.StatusCode >= 300) {
        throw 'Failed to fetch events with status [' + res.StatusCode + ']. \nOriginal error: ' + res.Body;
    }

    try {
        transient = JSON.parse(res.Body);
        if (transient.success) {
            return transient.object;
        } else {
            throw FailedRequestError('Posting transient for events failed.', fullUrl, null, body, transient).toString();
        }
    } catch (err) {
        throw FailedRequestError('Unexpected while posting transient for events. \nOriginal error: ' + err, fullUrl, null, body, res.Body).toString();
    }
}

function getEventDetails(sessionId, args) {
    var fullUrl = url + '/investigation/reconstruct/event';
    var eventsViewHTML = getEventsViewHtml(sessionId);
    var csrfToken = extractCsrfTokenFromHTML(eventsViewHTML);

    var body = {
        deviceId: args.deviceId,
        collectionName: args.collectionName || '',
        eventId: args.eventId,
        contentType: 'AUTO',
        contentSide: 'REQUEST_AND_RESPONSE',
        contentLayout: 'TOP_TO_BOTTOM',
        packetOverride: -1,
        ctoken: csrfToken
    };
    var res = http(
        fullUrl,
        {
            Method: 'POST',
            Headers: {
                'Cookie': [COOKIE_PREFIX + sessionId],
                'Content-Type': ['application/x-www-form-urlencoded']
            },
            Body: encodeToURLQuery(body).replace(/^\?/, '')
        },
        true,
        proxy
    );

    if (res.StatusCode < 200 || res.StatusCode >= 300) {
        throw 'Failed to fetch event with status [' + res.StatusCode + ']. \nOriginal error: ' + res.Body;
    }

    try {
        event = JSON.parse(res.Body);
        if (event.success) {
            var content = getEventContent(sessionId, event.data.uri);
            return {data: event.data, content: content};
        } else {
            throw FailedRequestError('Fetching event details', fullUrl, null, body, event).toString();
        }
    } catch (err) {
        throw FailedRequestError('Unexpected while fetching event details. \nOriginal error: ' + err, fullUrl, null, body, res.Body).toString();
    }
}

// Returns events/session data content.
function getEventContent(sessionId, urlSuffix) {
    var fullUrl = url + urlSuffix;
    var res = http(
        fullUrl,
        {
            Method: 'GET',
            Headers: {
                'Cookie': [COOKIE_PREFIX + sessionId]
            }
        },
        true,
        proxy
    );

    if (res.StatusCode < 200 || res.StatusCode >= 300) {
        throw 'Failed to fetch event data (recontruction) with status [' + res.StatusCode + ']. \nOriginal error: ' + res.Body;
    }

    try {
        return res.Body;
    } catch (err) {
        throw FailedRequestError('Unexpected while fetching event data (recontruction). \nOriginal error: ' + err, fullUrl, query, null, res.Body).toString();
    }
}

var defaultAlertQuery = {
    page: 1,
    start: 0,
    limit: 100,
    sort: JSON.stringify([
        {
            property:'alert.timestamp',
            direction: 'DESC'
        }
    ]),
    filter: JSON.stringify([
        {
            property: 'alert.timestamp',
            value: [
                851171984031, // year 1996
                new Date().getTime()
            ]
        }
    ])
};
function filterAlerts(sessionId, args) {
    var query = createQuery(args, defaultAlertQuery);
    var fullUrl = [
        url,
        '/ajax/alerts/',
        incidentManagementId,
        encodeToURLQuery(query)
    ].join('');

    var res = http(
        fullUrl,
        {
            Method: 'GET',
            Headers: {
                'Cookie': [COOKIE_PREFIX + sessionId]
            }
        },
        true,
        proxy
    );

    if (res.StatusCode < 200 || res.StatusCode >= 300) {
        throw 'Failed to fetch alerts with status [' + res.StatusCode + ']. \nOriginal error: ' + res.Body;
    }

    try {
        alerts = JSON.parse(res.Body);
        if (alerts.success) {
            return alerts.data;
        } else {
            throw FailedRequestError('Fetch alerts failed.', fullUrl, query, null, alerts).toString();
        }
    } catch (err) {
        throw FailedRequestError('Unexpected while fetching alerts. Original error:' + err, fullUrl, query, null, res.Body).toString();
    }
}

function getAlertById(sessionId, args) {
    var fullUrl = [
        url,
        'ajax/alerts',
        incidentManagementId,
        args.alertId
    ].join('/');

    var res = http(
        fullUrl,
        {
            Method: 'GET',
            Headers: {
                'Cookie': [COOKIE_PREFIX + sessionId]
            }
        },
        true,
        proxy
    );

    if (res.StatusCode < 200 || res.StatusCode >= 300) {
        throw 'Failed to get events of alert with status [' + res.StatusCode + ']. \nOriginal error: ' + res.Body;
    }

    try {
        alert = JSON.parse(res.Body);
        if (alert.success) {
            return alert.data;
        } else {
            throw FailedRequestError('Fetch alert details failed.', fullUrl, query, null, alert).toString();
        }
    } catch (err) {
        throw FailedRequestError('Unexpected while fetching alert details. \nOriginal error: ' + err, fullUrl, null, null, res.Body).toString();
    }
}

function getOriginalAlertById(sessionId, args) {
    var fullUrl = [
        url,
        'ajax/alerts/originalalert',
        incidentManagementId,
        args.alertId
    ].join('/');

    var res = http(
        fullUrl,
        {
            Method: 'GET',
            Headers: {
                'Cookie': [COOKIE_PREFIX + sessionId]
            }
        },
        true,
        proxy
    );

    if (res.StatusCode < 200 || res.StatusCode >= 300) {
        throw 'Failed to get events of alert with status [' + res.StatusCode + ']. \nOriginal error: ' + res.Body;
    }

    try {
        alert = JSON.parse(res.Body);
        if (alert.success) {
            return alert.data;
        } else {
            throw FailedRequestError('Fetch alert details failed.', fullUrl, query, null, alert).toString();
        }
    } catch (err) {
        throw FailedRequestError('Unexpected while fetching alert details. \nOriginal error: ' + err, fullUrl, null, null, res.Body).toString();
    }
}

function getAvailableAssignees(sessionId) {
    var fullUrl = url + '/ajax/incident/user/availableAssignees';

    var res = http(
        fullUrl,
        {
            Method: 'GET',
            Headers: {
                'Cookie': ['RSA_SA_LICENSE=true; SaneID=10.64.49.14-1456516139492605; s_pers=%20s_fid%3D0D47AAAFD2A1592B-3436DC4A7A7EB300%7C1531522908438%3B%20gpv_pn%3DMYTOOLSSTATIC%252FTOOLS%252FTHE%2520SQUARE%7C1468452708438%3B%20s_lv%3D1468450908454%7C1563058908454%3B%20s_lv_s%3DLess%2520than%25201%2520day%7C1468452708454%3B; s_vi=[CS]v1|2B6795DE050118E9-40001608C00050FA[CE]; s_fid=3D8DF632622AC544-1283F8DF4BA4E8DC; JSESSIONID=' + sessionId]
            }
        },
        true,
        proxy
    );

    if (res.StatusCode < 200 || res.StatusCode >= 300) {
        throw 'Failed to fetch availabe assignees with status [' + res.StatusCode + ']. \nOriginal error: ' + res.Body;
    }

    try {
        availableAssignees = JSON.parse(res.Body);
        if (availableAssignees.success) {
            return availableAssignees.data;
        } else {
            throw FailedRequestError('Fetch available assignees failed.', fullUrl, null, null, availableAssignees).toString();
        }
    } catch (err) {
        throw FailedRequestError('Unexpected error while fetching available assignees. \nOriginal error: ' + err, fullUrl, null, null, res.Body).toString();
    }
}

function getEventsViewHtml(sessionId) {
    var fullUrl = url + '/investigation/events';

    var res = http(
        fullUrl,
        {
            Method: 'GET',
            Headers: {
                'Cookie': [COOKIE_PREFIX + sessionId]
            }
        },
        true,
        proxy
    );

    if (res.StatusCode < 200 || res.StatusCode >= 300) {
        throw 'Failed to fetch CSRF token with status [' + res.StatusCode + ']. \nOriginal error: ' + res.Body;
    }

    return res.Body;
}

function extractCsrfTokenFromHTML(html) {
    var matched = html.match(/<meta name="csrf-token" content=".*"/);
    if (!matched) {
        throw 'CSRF token not found! Internal error in NetWitness. Response  body: \n' + html;
    }

    var csrfToken = replaceAll(matched[0].replace('<meta name="csrf-token" content=', ''), '"', '');
    return csrfToken;
}

function extractLoggedUserFromHTML(html) {
    var matchedLoggedUser = html.match(/name: Ext\.htmlDecode\(.*\)/);
    if (!matchedLoggedUser) {
        throw 'Failed to determine logged in user. Html: ' + html;
    }

    var name = matchedLoggedUser[0].replace('name: Ext.htmlDecode(\'', '').replace('\')', '');
    var user = {
        name: name
    };

    return user;
}

var DEFAULT_SEVERITY = "50";
function createAlert(sessionId, args, incidentManagementId, createdUser, csrfToken) {
    var eventListString = replaceAll(args.eventList, ' ', '');
    var fullUrl = [
        url,
        'ajax/alert/create',
        args.deviceId,
        eventListString,
        incidentManagementId + '',
        '?ctoken=' + csrfToken
    ].join('/');

    var body = {
        alertSummary: args.alertSummary,
        event_id_list: eventListString.split(','),
        severity: args.severity ? args.severity + '' : DEFAULT_SEVERITY,
        create_by_user: createdUser.name
    };

    var res = http(
        fullUrl,
        {
            Method: 'POST',
            Headers: {
                'Cookie': [COOKIE_PREFIX + sessionId],
                'Content-Type': ['application/json']
            },
            Body: JSON.stringify(body)
        },
        true,
        proxy
    );

    if (res.StatusCode < 200 || res.StatusCode >= 300) {
        throw 'Failed to create new alert with status [' + res.StatusCode + ']. \nOriginal error: ' + res.Body;
    }

    try {
        var alertRes = JSON.parse(res.Body);
        if (alertRes.success) {
            return alertRes.data;
        } else {
            throw FailedRequestError('Failed to create alert.', fullUrl, null, body, alertRes).toString();
        }
    } catch (err) {
        throw FailedRequestError('Unexpected error while creating alert. \nOriginal error: ' + err, fullUrl, null, body, res.Body).toString();
    }
}

function createIncident(sessionId, args, incidentManagementId, availableAssignees) {
    var eventsViewHTML = getEventsViewHtml(sessionId);
    var csrfToken = extractCsrfTokenFromHTML(eventsViewHTML);
    var loggedUser = extractLoggedUserFromHTML(eventsViewHTML);
    // currently we extract only the name of the logged in user. But the all the user object is exist in the html.
    // it just will take more development time.
    // that is why we look for the user in availableAssigness
    availableAssignees.forEach(function(user) {
        if (user.name === loggedUser.name) {
            loggedUser = user;
        }
    });

    var newAlert = createAlert(sessionId, args, incidentManagementId, loggedUser, csrfToken);

    var fullUrl = [
        url,
        'ajax/incident/create',
        incidentManagementId + '',
        '?ctoken=' + csrfToken
    ].join('/');

    var newIncident = {
        name: args.name,
        summary: args.summary || '',
        priority: args.priority,
        createdBy: loggedUser.name,
        alert_id_list: [
            newAlert.id
        ]
    };

    var res = http(
        fullUrl,
        {
            Method: 'POST',
            Headers: {
                'Cookie': [COOKIE_PREFIX + sessionId],
                'Content-Type': ['application/json']
            },
            Body: JSON.stringify(newIncident)
        },
        true,
        proxy
    );

    if (res.StatusCode < 200 || res.StatusCode >= 300) {
        throw 'Failed to create incident with status [' + res.StatusCode + ']\n.'
            + 'Request Body: ' + JSON.stringify(body) + '\n. Response Body: ' + res.Body;
    }

    try {
        var newIncidentRes = JSON.parse(res.Body);
        if (newIncidentRes.success) {
            newIncident.id = newIncidentRes.data.id;
            return newIncident;
        } else {
            throw FailedRequestError('Failed to create incident.', fullUrl, null, body, newIncidentRes).toString();
        }
    } catch (err) {
        throw FailedRequestError('Unexpected error while creating incident. \nOriginal error: ' + err, fullUrl, null, body, res.Body).toString();
    }
}

function addEventsToIncident(sessionId, args, incidentManagementId, availableAssignees) {
    var eventsViewHTML = getEventsViewHtml(sessionId);
    var csrfToken = extractCsrfTokenFromHTML(eventsViewHTML);
    var loggedUser = extractLoggedUserFromHTML(eventsViewHTML);
    // currently we extract only the name of the logged in user. But the all the user object is exist in the html.
    // it just will take more development time.
    // that is why we look for the user in availableAssigness
    availableAssignees.forEach(function(user) {
        if (user.name === loggedUser.name) {
            loggedUser = user;
        }
    });

    var newAlert = createAlert(sessionId, args, incidentManagementId, loggedUser, csrfToken);

    var fullUrl = [
        url,
        'ajax/incident/addToIncident',
        incidentManagementId + '',
        '?ctoken=' + csrfToken
    ].join('/');

    var reqBody = {
        alertIds: [
            newAlert.id
        ],
        incidentId: args.incidentId
    };

    var res = http(
        fullUrl,
        {
            Method: 'POST',
            Headers: {
                'Cookie': [COOKIE_PREFIX + sessionId],
                'Content-Type': ['application/json']
            },
            Body: JSON.stringify(reqBody)
        },
        true,
        proxy
    );

    if (res.StatusCode < 200 || res.StatusCode >= 300) {
        throw 'Failed to add events to incident with status [' + res.StatusCode + ']\n.'
            + 'Request Body: ' + JSON.stringify(body) + '\n. Response Body: ' + res.Body;
    }

    try {
        var resObject = JSON.parse(res.Body);
        if (resObject.success) {
            return true;
        } else {
            throw FailedRequestError('Failed to add events to incident.', fullUrl, null, body, newIncidentRes).toString();
        }
    } catch (err) {
        throw FailedRequestError('Unexpected error while adding new events to incident. \nOriginal error: ' + err, fullUrl, null, body, res.Body).toString();
    }
}

function updateIncident(sessionId, args, incidentManagementId, availableAssignees) {
    var eventsViewHTML = getEventsViewHtml(sessionId);
    var csrfToken = extractCsrfTokenFromHTML(eventsViewHTML);
    var loggedUser = extractLoggedUserFromHTML(eventsViewHTML);
    // currently we extract only the name of the logged in user. But the all the user object is exist in the html.
    // it just will take more development time.
    // that is why we look for the user in availableAssigness
    availableAssignees.forEach(function(user) {
        if (user.name === loggedUser.name) {
            loggedUser = user;
        }
    });

    var fullUrl = [
        url,
        'ajax/incidents/update',
        incidentManagementId + '',
        '?ctoken=' + csrfToken
    ].join('/');

    var updatedIncident = {
        id_list: replaceAll(args.idList, ' ', '').split(','),
        attribute_map: {
            lastUpdatedByUser: loggedUser
        },
        benign_domain_list: []
    };
    if (args.name) {
        updatedIncident.attribute_map.name = args.name;
    }
    if (args.priority) {
        updatedIncident.attribute_map.priority = args.priority;
    }
    if (args.status) {
        updatedIncident.attribute_map.status = args.status;
    }
    if (args.summary) {
        updatedIncident.attribute_map.summary = args.summary;
    }
    if (args.comment) {
        updatedIncident.attribute_map.comment = args.comment;
    }
    if (args.assignee) {
        var assigneeUser = null;
        availableAssignees.forEach(function(user) {
            if (user.login === args.assignee) {
                assigneeUser = user;
            }
        });
        if (!assigneeUser) {
            throw 'assignee argument is invalid. No such [' + args.assignee + '] available assignee user exist';
        }
        updatedIncident.attribute_map.assignee = assigneeUser;
    }
    if (args.categories) {
        updatedIncident.attribute_map.categories = args.categories;
    }

    var res = http(
        fullUrl,
        {
            Method: 'POST',
            Headers: {
                'Cookie': [COOKIE_PREFIX + sessionId],
                'Content-Type': ['application/json']
            },
            Body: JSON.stringify(updatedIncident)
        },
        true,
        proxy
    );

    if (res.StatusCode < 200 || res.StatusCode >= 300) {
        throw 'Failed to create incident with status [' + res.StatusCode + ']\n.'
            + 'Request Body: ' + JSON.stringify(updatedIncident) + '\n. Response Body: ' + res.Body;
    }

    try {
        var updateRes = JSON.parse(res.Body);
        if (updateRes.success) {
            return updateRes;
        } else {
            throw FailedRequestError('Failed to update incident.', fullUrl, null, updatedIncident, updateRes).toString();
        }
    } catch (err) {
        throw FailedRequestError('Failed to update incident.', fullUrl, null, updatedIncident, res.Body).toString();
    }
}

function makeUpperCase (o) {
    for (var key in o ) {
        if(o.hasOwnProperty(key)) {
            var newKey = key.charAt(0).toUpperCase() + key.slice(1);
            o[newKey] = o[key];
            delete o[key];
        }
    }
    return o;
}

function getIncidentObject(e) {
    return {
        "Id": e.id,
        "Name": e.name,
        "Status": e.status,
        "Priority": e.priority,
        "Summary": e.summary,
        "Assignee": e.assignee ? e.assignee.name : "",
        "CreatedBy": e.createdBy,
        "Created": convertTimestampToString(e.created),
        "FirstAlertTime": convertTimestampToString(e.firstAlertTime),
        "LastUpdatedByUserName": e.lastUpdatedByUserName,
        "RiskScore": e.riskScore,
        "AverageAlertRiskScore": e.averageAlertRiskScore,
        "Categories": e.categories,
        "AlertCount": e.alertCount
    };
}

function getAlert (alert) {
    return {
        "Id": alert.id,
        "Name": alert.name,
        "IncidentId": alert.incidentId,
        "Timestamp": convertTimestampToString(alert.timestamp),
        "HostSummary": alert.host_summary,
        "SignatureId": alert.signature_id,
        "Source": alert.source,
        "Type": alert.type,
        "RiskScore": alert.risk_score,
        "SourceCountry": alert.groupby_source_country,
        "DestinationCountry": alert.groupby_destination_country,
        "NumEvents": alert.numEvents,
        "SourceIp": alert.groupby_source_ip,
        "DestonationIp": alert.groupby_destination_ip,
        "DestonationPort": alert.groupby_destination_port
    };
}
function buildRetValListIncidents (incidets) {
    var md = [];
    var ctx = {"Netwitness.Incident":[]}
    if (!Array.isArray(incidets)) {
        incidets = [incidets]
    }
    incidets.forEach(function (e) {
        var toPush = getIncidentObject(e);
        md.push(toPush);
        ctx["Netwitness.Incident"].push(toPush);
    })
    return {Type: entryTypes.note, Contents: incidets, ContentsFormat: formats.json, HumanReadable: tableToMarkdown(command, md), ReadableContentsFormat: formats.markdown, EntryContext: ctx};
}

function buildRetValGetIncidentDetails (incident) {
    var md = [];
    var ctx = {"Netwitness.Incident":[]}
    var toPush = getIncidentObject(incident);
    md.push(toPush);
    ctx["Netwitness.Incident"].push(toPush);
    return {Type: entryTypes.note, Contents: incident, ContentsFormat: formats.json, HumanReadable: tableToMarkdown(command, md), ReadableContentsFormat: formats.markdown, EntryContext: ctx};
}

function buildRetValGetComponents (components) {
    var md = [];
    var ctx = {"Netwitness.Component":[]}
    if (!Array.isArray(components)) {
        components = [components]
    }
    components.forEach(function (e) {
        var toPush = {
            "Id": e.id,
            "DisplayName": e.displayName,
            "DeviceVersion": e.deviceVersion,
            "DisplayType": e.deviceType,
            "Host": e.host,
            "Port": e.port,
            "Validated": e.validated,
            "Licensed": e.licensed,
            "Username": e.username,
            "EnableSSL": e.enableSSL
        };
        md.push(toPush)
        ctx["Netwitness.Component"].push(toPush);
    })
    return {Type: entryTypes.note, Contents: components, ContentsFormat: formats.json, HumanReadable: tableToMarkdown(command, md), ReadableContentsFormat: formats.markdown, EntryContext:  ctx};
}

function buildRetValGetEvents (events) {
    var md = [];
    var ctx = {"Netwitness.Event":[]}
    if (!Array.isArray(events)) {
        events = [events]
    }
    events.forEach(function (event) {
        var toPush = {
            "Id": event.id,
            "Medium": event.medium,
            "Service": event.service,
            "Size": event.size
        }
        event["meta"].forEach(function (meta) {
            toPush["meta." + meta.name] = meta.value
        });
        md.push(toPush);
    });
    return {Type: entryTypes.note, Contents: events, ContentsFormat: formats.json, HumanReadable: tableToMarkdown(command, md), ReadableContentsFormat: formats.markdown};
}

function buildRetValGetEventDetails (event) {
    var md = [];
    var ctx = {"Netwitness.Event":[]};
    var data = event.data;
    var content = event.content;
    var toPush = {
        "EventId": data.eventId,
        "DeviceId": data.deviceId,
        "ReconstructedContentType": data.reconstructedContentType,
        "PacketsTotal": data.stats ? data.stats.packetsTotal : "",
        "PacketsProcessed": data.stats ? data.stats.packetsProcessed : ""
    };
    data.summaryAttributes.forEach(function (e) {
        toPush[e.name] = e.value
    });
    md.push(toPush);
    ctx["Netwitness.Event"].push(toPush);
    return {Type: entryTypes.note, Contents: event, ContentsFormat: formats.json, HumanReadable: tableToMarkdown(command, md), ReadableContentsFormat: formats.markdown, EntryContext:  ctx};
}

function buildRetValGetAlerts (alerts) {
    var md = [];
    var ctx = {"Netwitness.Alert":[]}
    if (!Array.isArray(alerts)) {
        alerts = [alerts]
    }
    alerts.forEach(function (e) {
        var toPush = getAlert(e);
        md.push(toPush);
        ctx["Netwitness.Alert"].push(toPush);
    })
    return {Type: entryTypes.note, Contents: alerts, ContentsFormat: formats.json, HumanReadable: tableToMarkdown(command, md), ReadableContentsFormat: formats.markdown, EntryContext: ctx};
}

function buildRetValGetAlert (alert) {
    var ctx = {"Netwitness.Alert":[]}
    var alertValue = getAlert(alert);
    var eventValue = [];
    alert.events.forEach(function (evnt) {
        eventValue.push(treeToFlattenObject(evnt));
    });
    var relatedLinksValue = alert.related_links;
    var hr = tableToMarkdown('Alerts',alertValue)  + tableToMarkdown('Events', eventValue)  + tableToMarkdown('Related Links', relatedLinksValue);
    ctx["Netwitness.Alert"].push(alertValue);
    return {Type: entryTypes.note, Contents: alert, ContentsFormat: formats.json, HumanReadable: hr, ReadableContentsFormat: formats.markdown, EntryContext: ctx};
}

function buildRetValGetAlertOrig (alertOrig) {
    var md = [];
    var ctx = {"Netwitness.Event": []}
    if(!alertOrig.events) {
        return {"ContentsFormat": formats["markdown"], "Type": entryTypes["error"], "Contents": "Received an error from NetWitness Please ensure that the referred alert Id exist in NetWitness"};
    }
    alertOrig.events.forEach(function (evnt) {
        for (var key in evnt) {
            if (key === 'time') {
                evnt[key] = convertTimestampToString(evnt[key]);
            }
        }
    });
    md = alertOrig.events;
    ctx["Netwitness.Event"] = alertOrig.events;
    return {Type: entryTypes.note, Contents: alertOrig, ContentsFormat: formats.json, HumanReadable: tableToMarkdown(command, md), ReadableContentsFormat: formats.markdown, EntryContext: ctx};
}

function buildRetValAvailableAssignees(availableAssignees) {
    var md = [];
    var ctx = {"Netwitness.Account":[]}
    if (!Array.isArray(availableAssignees)) {
        availableAssignees = [availableAssignees]
    }
    availableAssignees.forEach(function (e) {
        var toPush ={
            "Id": e.id,
            "Name": e.name,
            "Login": e.login,
            "EmailAddress": e.emailAddress
        };
        md.push(toPush);
        ctx["Netwitness.Account"].push(toPush);
    })
    return {Type: entryTypes.note, Contents: availableAssignees, ContentsFormat: formats.json, HumanReadable: tableToMarkdown(command, md), ReadableContentsFormat: formats.markdown, EntryContext:  ctx};
}

function buildRetValCreateIncident (newIncident) {
    var md = [];
    var ctx = {"Netwitness.Incident":[]}
    var toPush = {
        "Id": newIncident.id,
        "Name": newIncident.name,
        "Priority": newIncident.priority,
        "CreatedBy": newIncident.createdBy,
        "AlertIDList": newIncident.alertIdList
    };
    md.push(toPush);
    ctx["Netwitness.Incident"].push(toPush)
    results = {Type: entryTypes.note, Contents: newIncident, ContentsFormat: formats.json, HumanReadable: tableToMarkdown(command, md), ReadableContentsFormat: formats.markdown, EntryContext:  ctx};
}


// The command input arg holds the command sent from the user.
var sessionId = login(url, username, password);
var incidentManagementId = args.incidentManagementId || getIncidentManagementId(sessionId);
var results = false;
switch (command) {
    case 'fetch-incidents':
        results = fetchIncidents(sessionId, args, incidentManagementId);
        break;
    case 'test-module':
        results = 'ok';
        break;
    case 'nw-login':
        results = sessionId;
        break;
    case 'netwitness-im-list-incidents':
        var incidents = listIncidents(sessionId, args, incidentManagementId);
        results = buildRetValListIncidents(incidents);
        break;
    case 'netwitness-im-get-incident-details':
        var incident = getIncidentById(sessionId, args, incidentManagementId);
        results = buildRetValGetIncidentDetails(incident);
        break;
    case 'netwitness-im-get-components':
        var components = getComponents(sessionId, args);
        results = buildRetValGetComponents(components);
        break;
    case 'netwitness-im-get-events':
        var events = getEvents(sessionId, args);
        results = buildRetValGetEvents(events);
        break;
    case 'netwitness-im-get-event-details':
        event = getEventDetails(sessionId, args);
        results = buildRetValGetEventDetails(event);
        break;
    case 'netwitness-im-get-alerts':
        var alerts = filterAlerts(sessionId, args);
        results = buildRetValGetAlerts(alerts);
        break;
    case 'netwitness-im-get-alert-details':
        var alert = getAlertById(sessionId, args);
        results = buildRetValGetAlert(alert);
        break;
    case 'netwitness-im-get-alert-original':
        var alert = getOriginalAlertById(sessionId, args);
        results = buildRetValGetAlertOrig(alert);
        break;
    case 'netwitness-im-get-available-assignees':
        var availableAssignees = getAvailableAssignees(sessionId);
        results = buildRetValAvailableAssignees(availableAssignees);
        break;
    case 'netwitness-im-create-incident':
        var availableAssignees = getAvailableAssignees(sessionId);
        var newIncident = createIncident(sessionId, args, incidentManagementId, availableAssignees);
        results = buildRetValCreateIncident(newIncident);
        break;
    case 'netwitness-im-add-events-to-incident':
        var md = [];
        var availableAssignees = getAvailableAssignees(sessionId, args);
        var isSuccess = addEventsToIncident(sessionId, args, incidentManagementId, availableAssignees);
        md.push({ success: isSuccess })
        results = {Type: entryTypes.note, Contents: { success: isSuccess }, ContentsFormat: formats.json, HumanReadable: tableToMarkdown(command, md), ReadableContentsFormat: formats.markdown};
        break;
    case 'netwitness-im-update-incident':
        var availableAssignees = getAvailableAssignees(sessionId, args);
        var update_incident = updateIncident(sessionId, args, incidentManagementId, availableAssignees);
        if( update_incident.success != true) {
            results = {"ContentsFormat": formats["markdown"], "Type": entryTypes["error"], "Contents": "Didn't succed to update incident.\n" + tableToMarkdown("Data returned:", update_incident)};
        }
        else if (update_incident.success == true && update_incident.data < 1) {
            results = {"ContentsFormat": formats["markdown"], "Type": entryTypes["error"], "Contents": "Received an error from NetWitness Please ensure that the referred incidents exist in NetWitness.  Incidents count = " + update_incident.data};
        }
        else {
            results = {
                "ContentsFormat": formats["text"],
                "Type": entryTypes["note"],
                "Contents": "Incident updated successfully."
            };
        }
        break;
    default:
        // You can use args[argName] or args.argName to get a specific arg. args are strings.
        // You can use params[paramName] or params.paramName to get a specific params.
        // Params are of the type given in the integration page creation.
}

logout(url, sessionId);
return results;