CounterCraft Deception Director

CounterCraft Deception Solution detects advanced adversaries. Automate counterintelligence campaigns to discover targeted attacks with real-time active response.

Deception & Breach Simulation · CounterCraft Deception Director

Details

IDCounterCraft Deception Director
ProviderCounterCraft
CategoryDeception & Breach Simulation
From Version5.0.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM

README

Overview


CounterCraft Deception Solution detects advanced adversaries. Automate counterintelligence campaigns to discover targeted attacks with real-time active response.
This integration was integrated and tested with version 2.5.13 of CounterCraft Deception Director

CounterCraft Deception Director Playbook


Use Cases


  • Query IOCs (objects) in your Deception Director
  • Retrieve events from your deception campaigns
  • Retrieve configuration from your Deception Director
  • Retrieve alerts (notifications) from your Deception Director
  • Create new deception campaigns
  • Create new deception hosts
  • Operate your campaigns, hosts, services and breadcrumbs

Prerequisites


You need to obtain the following Deception Director information.

  • Server URL
  • API Key
  • Secret Key

In order to obtain the API Key and the Secret Key you need to go to the user settings in the Deception Director
and copy both or generate a new pair if they are not already generated.

Configure CounterCraft Deception Director on Cortex XSOAR


  1. Navigate to Settings > Integrations > Servers & Services.
  2. Search for CounterCraft Deception Director.
  3. Click Add instance to create and configure a new integration instance.
    • Name: a textual name for the integration instance.
    • Deception Director Domain or IP Address: for example, https://192.168.1.1
    • Fetch incidents: if you select this option, your notifications in the Deception Director will be created as Cortex XSOAR incidents.
    • Incident type
    • API Key for Deception Director connection: paste your API Key.
    • Secret Key for Deception Director connection: paste your Secret Key.
    • Ignore SSL Warnings: in case the SSL certificate is self-signed.
    • Use system proxy settings: in case you need to connect through a proxy.
  4. Click Test to validate the URLs, token, and connection.

Fetched Incidents Data


Commands


You can execute these commands from the Cortex XSOAR 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.

  1. countercraft-list-campaigns
  2. countercraft-list-hosts
  3. countercraft-list-services
  4. countercraft-list-breadcrumbs
  5. countercraft-get-object
  6. countercraft-get-events
  7. countercraft-create-campaign
  8. countercraft-list-dsns
  9. countercraft-list-providers
  10. countercraft-create-host-machine
  11. countercraft-list-incidents
  12. countercraft-manage-campaign
  13. countercraft-manage-host
  14. countercraft-manage-service
  15. countercraft-manage-breadcrumb

1. countercraft-list-campaigns


List all deception campaigns

Required Permissions

Any interaction will be based on your permissions on the Deception Director. Please consult
your Deception Director administrator in you have any questions.

You will be able to list only the campaigns you have access to.

Base Command

countercraft-list-campaigns

Input
Argument Name Description Required
name Campaign Name Optional
Context Output
Path Type Description
CounterCraft.Campaign.ID number Campaign ID
CounterCraft.Campaign.Name string Campaign Name
CounterCraft.Campaign.Description string Campaign Description
CounterCraft.Campaign.StatusCode string Campaign Status
Command Example

!countercraft-list-campaigns

Human Readable Output
ID Name Description StatusCode
1 AntiPhishing Gather intelligence from phishers ACTIVE
2 External recoinassance Collect pre-attack evidence ACTIVE
3 Internal lateral movement Detect lateral movement ACTIVE
4 DMZ DMZ activity ACTIVE
5 VIP VIP mobile protection ACTIVE

2. countercraft-list-hosts


Lists all deception hosts

Required Permissions

Any interaction will be based on your permissions on the Deception Director. Please consult
your Deception Director administrator in you have any questions.

You will be able to list only the hosts you have access to.

Base Command

countercraft-list-hosts

Input
Argument Name Description Required
campaign_id Campaign ID Optional
Context Output
Path Type Description
CounterCraft.Host.ID number Host Id
CounterCraft.Host.Name string Host Name
CounterCraft.Host.Description string Host Description
CounterCraft.Host.StatusCode string Host Status
CounterCraft.Host.TypeCode string Host Type
Command Example

!countercraft-list-hosts campaign_id=2

Human Readable Output
ID Name Description StatusCode TypeCode
1 Ubuntu Web Wordpress ACTIVE MACHINE
2 Azure Windows 2019 RDP with breadcrumbs ACTIVE MACHINE
3 Office365 tenant Office365 with domain name ACTIVE CLOUD_ENTITY
4 Apache Struts Vulnerable Apache Struts ACTIVE MACHINE
5 CFO CFO persona ACTIVE IDENTITY

3. countercraft-list-services


List services currently deployed on deception hosts

Required Permissions

Any interaction will be based on your permissions on the Deception Director. Please consult
your Deception Director administrator in you have any questions.

You will be able to list only the services you have access to.

Base Command

countercraft-list-services

Input
Argument Name Description Required
host_id Host Id Optional
Context Output
Path Type Description
CounterCraft.Service.ID number Service ID
CounterCraft.Service.Name string Service Name
CounterCraft.Service.Description string Service.Description
CounterCraft.Service.StatusCode string Service Status
CounterCraft.Service.TypeCode string Service Type
Command Example

!countercraft-list-services host_id=1

Human Readable Output
ID Name Description StatusCode TypeCode
1 Operating system User events ACTIVE SYSTEM
2 WebApp Web application ACTIVE WEB_SERVER
8 Tailored Service Anonymous FTP ACTIVE FTP_SERVER
9 Phishing Sinkhole Sinkhole ACTIVE SMTP_SERVER

4. countercraft-list-breadcrumbs


List breadcrumbs in a campaign

Required Permissions

Any interaction will be based on your permissions on the Deception Director. Please consult
your Deception Director administrator in you have any questions.

You will be able to list only the breadcrumbs you have access to.

Base Command

countercraft-list-breadcrumbs

Input
Argument Name Description Required
campaign_id Campaign ID Optional
Context Output
Path Type Description
CounterCraft.Breadcrumb.ID number Breadcrumb ID
CounterCraft.Breadcrumb.Name string Breadcrumb Name
CounterCraft.Breadcrumb.Description string Breadcrumb Description
CounterCraft.Breadcrumb.StatusCode string Breadcrumb Status
CounterCraft.Breadcrumb.TypeCode string Breadcrumb Type
Command Example

!countercraft-list-breadcrumbs campaign_id=1

Human Readable Output
ID Name Description StatusCode TypeCode
1 Fake document   ACTIVE DOCUMENT
2 Mobile App   ACTIVE MOBILE_APP
3 SSL Certificate   ACTIVE SSL_CERTIFICATE
4 LinkedIn_persona   ACTIVE HONEYTOKEN

5. countercraft-get-object


Get information about an object (IoC)

Required Permissions

Any interaction will be based on your permissions on the Deception Director. Please consult
your Deception Director administrator in you have any questions.

You will be able to list only the objects you have access to.

Base Command

countercraft-get-object

Input
Argument Name Description Required
value Object value Required
Context Output
Path Type Description
CounterCraft.Object.ID number Object ID
CounterCraft.Object.Value string Object value
CounterCraft.Object.Hits number Object hits
CounterCraft.Object.Score number Object score
CounterCraft.Object.TypeCode string Object type
CounterCraft.Object.FirstSeen date Object first seen
CounterCraft.Object.LastSeen date Object last seen
CounterCraft.Object.EventsCount number Object events count
CounterCraft.Object.Tags string Object tags
Command Example

!countercraft-get-object value=root

Human Readable Output
   
Id 852
Value root
EventsCount 7
TypeCode CC_USERNAME
Score 0
FirstSeen Wed Jan 29 12:33:34 2020
LastSeen Wed Jan 29 12:53:19 2020
Tags  

6. countercraft-get-events


Get full list of Events

Required Permissions

Any interaction will be based on your permissions on the Deception Director. Please consult
your Deception Director administrator in you have any questions.

You will be able to list only the objects you have access to.

Base Command

countercraft-get-events

Input
Argument Name Description Required
criteria Search criteria Required
max_results Maximum number of results Required
Context Output
Path Type Description
CounterCraft.Event.ID number Event id
CounterCraft.Event.CampaignName string Campaign name
CounterCraft.Event.CategoryCode string Category Code
CounterCraft.Event.EventDate date Event date
CounterCraft.Event.HostName string Host name
CounterCraft.Event.ServiceName string Service name
CounterCraft.Event.TypeCode string Type
CounterCraft.Event.Score number Score
CounterCraft.Event.Tags string Tags
CounterCraft.Events.Data unknown Data
Command Example

!countercraft-get-events criteria="type_code:ValidAuth" max_results="1"

Human Readable Output
     
Id 45  
Campaignname External recoinassance  
Hostname Azure Windows
Servicename OS Logs (Azure Windows)
Eventdate Thu Jan 30 08:11:01 2020  
Score 100  
Typecode ValidAuth  
Data event: ValidAuth subject: A session was reconnected to a Window Station event_id: 4778 …  
Tags attack.T1078  

7. countercraft-create-campaign


Create a new deception campaign

Required Permissions

Any interaction will be based on your permissions on the Deception Director. Please consult
your Deception Director administrator in you have any questions.

You can only create campaigns if you have the role ARCHITECT.

Base Command

countercraft-create-campaign

Input
Argument Name Description Required
name Campaign name Required
description Campaign description Required
Context Output
Path Type Description
CounterCraft.Campaign.ID number Campaign ID
CounterCraft.Campaign.Name string Name
CounterCraft.Campaign.Description string Description
CounterCraft.Campaign.StatusCode string Status Code
Command Example

!countercraft-create-campaign name="TestCampaign" description="Test Description"

Human Readable Output
   
Id 5
Name TestCampaign
Description Test Description
StatusCode DESIGN

8. countercraft-list-dsns


List Deception Support Nodes (DSNs)

Required Permissions

Any interaction will be based on your permissions on the Deception Director. Please consult
your Deception Director administrator in you have any questions.

You can only create campaigns if you have the role ARCHITECT.

Base Command

countercraft-list-dsns

Input

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

Context Output
Path Type Description
CounterCraft.DSN.ID number ID
CounterCraft.DSN.Name string Name
CounterCraft.DSN.Description string Description
CounterCraft.DSN.Hostname string Hostname
CounterCraft.DSN.Port number Port
Command Example

!countercraft-list-dsns

Human Readable Output
   
Id 1
Name Local DSN
Description Local DSN in the intranet
Hostname 192.168.1.2
Port  4567

9. countercraft-list-providers


List providers (providers for hosts or services i.e. AWS or Office365)

Required Permissions

Any interaction will be based on your permissions on the Deception Director. Please consult
your Deception Director administrator in you have any questions.

You will be able to list only the providers you have access to.

Base Command

countercraft-list-providers

Input

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

Context Output
Path Type Description
ID number ID
CounterCraft.Provider.Name string Name
CounterCraft.Provider.Description string Description
CounterCraft.Provider.TypeCode string Type
CounterCraft.Provider.StatusCode string Status
Command Example

!countercraft-list-providers

Human Readable Output
ID Name Description StatusCode TypeCode
1 Splunk Internal Splunk HEALTHY SPLUNK_PROVIDER
3 Signal Signal notifications HEALTHY SIGNAL_PROVIDER
4 Office365 Office365 Tenant HEALTHY OFFICE365_PROVIDER
5 AWS AWS EC2 HEALTHY AWS_PROVIDER

10. countercraft-create-host-machine


Deploy a new deception host

Required Permissions

Any interaction will be based on your permissions on the Deception Director. Please consult
your Deception Director administrator in you have any questions.

You will be able to create a host if you are MANAGER in a campaign.

Base Command

countercraft-create-host-machine

Input
Argument Name Description Required
name Name Required
description Description Optional
provider_id Provider Required
deception_support_node_id Deception Support Node ID Required
campaign_id Campaign Required
os_family Operating System Required
ip_address IP Address Required
port Port Required
username Username Required
password Password Required
Context Output
Path Type Description
CounterCraft.Host.Id number Host ID
Command Example

!countercraft-create-host-machine campaign_id=2 deception_support_node_id=1 os_family=linux ip_address=192.168.1.2 port=22 name="Test host" description="Test Description" username="ubuntu" password="ubuntu provider_id=1"

Human Readable Output
   
Id 8
Name Test Host
Description Test Description
StatusCode DESIGN
TypeCode MACHINE

11. countercraft-list-incidents


List all incidents currently active

Required Permissions

Any interaction will be based on your permissions on the Deception Director. Please consult
your Deception Director administrator in you have any questions.

You will be able to list only the incidents you have access to.

Base Command

countercraft-list-incidents

Input
Argument Name Description Required
campaign_id Campaign ID Required
Context Output
Path Type Description
CounterCraft.Incident.ID number Incident ID
CounterCraft.Incident.Name string Name
CounterCraft.Incident.Description string Description
CounterCraft.Incident.StatusCode string Status
CounterCraft.Incident.TLPCode string TLP code
Command Example

!countercraft-list-incidents campaign_id=1

Human Readable Output
ID Name Description StatusCode TLPCode Tags
1 APT incident State-sponsored OPEN AMBER  
2 Internal Fraud SWIFT apps CLOSED AMBER  

12. countercraft-manage-campaign


Manage Campaign parameters

Required Permissions

Any interaction will be based on your permissions on the Deception Director. Please consult
your Deception Director administrator in you have any questions.

You will be able to manage only the campaigns you have access to.

Base Command

countercraft-manage-campaign

Input
Argument Name Description Required
campaign_id Campaign ID Required
operation Operation Required
Context Output
Path Type Description
CounterCraft.Campaign.Message string Result message
CounterCraft.Campaign.ID number Campaign ID
Command Example

!countercraft-manage-campaign campaign_id=5 operation=activate

Human Readable Output
   
Id 5
Message Campaign is currently in state: PAUSED. Action activate discarded

13. countercraft-manage-host


Manage a deception host

Required Permissions

Any interaction will be based on your permissions on the Deception Director. Please consult
your Deception Director administrator in you have any questions.

You will be able to manage only the hosts you have access to.

Base Command

countercraft-manage-host

Input
Argument Name Description Required
host_id Host ID Required
operation Operation Required
Context Output
Path Type Description
CounterCraft.Host.Message string Result message
CounterCraft.Host.ID number Host ID
Command Example

!countercraft-manage-campaign host_id=5 operation=activate

Human Readable Output
   
Id 5
Message Host is currently in state: PAUSED. Action activate discarded

14. countercraft-manage-service


Manage a deception service

Required Permissions

Any interaction will be based on your permissions on the Deception Director. Please consult
your Deception Director administrator in you have any questions.

You will be able to manage only the services you have access to.

Base Command

countercraft-manage-service

Input
Argument Name Description Required
service_id Service ID Required
operation Operation Required
Context Output
Path Type Description
CounterCraft.Service.Message string Result message
CounterCraft.Service.ID number Service ID
Command Example

!countercraft-manage-campaign service_id=5 operation=activate

Human Readable Output
   
Id 5
Message Service is currently in state: PAUSED. Action activate discarded

15. countercraft-manage-breadcrumb


Manage breadcrumb

Required Permissions

Any interaction will be based on your permissions on the Deception Director. Please consult
your Deception Director administrator in you have any questions.

You will be able to manage only the breadcrumbs you have access to.

Base Command

countercraft-manage-breadcrumb

Input
Argument Name Description Required
breadcrumb_id Breadcrumb ID Required
operation Operation Required
Context Output
Path Type Description
CounterCraft.Breadcrumb.Message string Result message
CounterCraft.Breadcrumb.ID number Breadcrumb ID
Command Example

!countercraft-manage-campaign breadcrumb_id=5 operation=activate

Human Readable Output
   
Id 5
Message Breadcrumb is currently in state: PAUSED. Action activate discarded

Additional Information


Please check the Deception Director user manual for more guidance on how to use and deploy campaigns.

Configuration parameters

  • server — Deception Director Domain or IP Address (required)
  • api_key — API Key for Deception Director connection (required)
  • secret_key — Secret Key for Deception Director connection (required)
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings
  • isFetch — Fetch incidents
  • incidentType — Incident type
  • incidentFetchInterval — Incidents Fetch Interval

Commands (15)

  • countercraft-create-campaign

    Create a new deception campaign.

  • countercraft-create-host-machine

    Deploy a new deception host.

  • countercraft-get-events

    Get full list of Events.

  • countercraft-get-object

    Get information about an object (IoC).

  • countercraft-list-breadcrumbs

    List breadcrumbs in a campaign.

  • countercraft-list-campaigns

    List all deception campaigns.

  • countercraft-list-dsns

    List Deception Support Nodes (DSNs).

  • countercraft-list-hosts

    Lists all deception hosts.

  • countercraft-list-incidents

    List all incidents currently active.

  • countercraft-list-providers

    List providers (providers for hosts or services i.e. AWS or Office365).

  • countercraft-list-services

    List services currently deployed on deception hosts.

  • countercraft-manage-breadcrumb

    Manage breadcrumb.

  • countercraft-manage-campaign

    Manage Campaign parameters.

  • countercraft-manage-host

    Manage a deception host.

  • countercraft-manage-service

    Manage a deception service.

import demistomock as demisto
import pytest
from CommonServerPython import formatEpochDate

SERVER_URL = "https://1.2.3.4"


@pytest.fixture(autouse=True)
def get_params(requests_mock, mocker):
    mocker.patch.object(
        demisto,
        "params",
        return_value={
            "server": SERVER_URL,
            "api_key": "1234567890",
            "secret_key": "s3cr3t",
            "insecure": False,
        },
    )


def test_list_dsns_command(requests_mock, mocker):
    from CounterCraft import list_dsns_command
    from test_data.api_response import response_dsns as json_response

    requests_mock.get(f"{SERVER_URL}/api/deception_support_nodes", json=json_response, status_code=200)

    mocker.patch.object(demisto, "results")
    list_dsns_command()
    results = demisto.results.call_args[0][0]
    assert (
        results["HumanReadable"]
        == "### Deception Support Node\n|Id|Name|Description|Hostname|Port|\n|---|---|---|---|---|\n| 2 | \
Remote DSN | Remote DSN | 1.2.3.3 | 7080 |\n| 1 | Local network | Local network | thedsn | 7080 |\n"
    )
    assert results["Contents"] == json_response["data"]
    assert results["EntryContext"] == {
        "CounterCraft.DSN(val.ID && val.ID === obj.ID)": [
            {
                "ID": 2,
                "Name": "Remote DSN",
                "Description": "Remote DSN",
                "Hostname": "1.2.3.3",
                "Port": 7080,
            },
            {
                "ID": 1,
                "Name": "Local network",
                "Description": "Local network",
                "Hostname": "thedsn",
                "Port": 7080,
            },
        ]
    }


def test_list_providers_command(requests_mock, mocker):
    from CounterCraft import list_providers_command
    from test_data.api_response import response_providers as json_response

    requests_mock.get(f"{SERVER_URL}/api/providers", json=json_response, status_code=200)

    mocker.patch.object(demisto, "results")
    list_providers_command()
    results = demisto.results.call_args[0][0]
    assert (
        results["HumanReadable"]
        == "### Providers\n|Id|Name|Description|Typecode|Statuscode|\n|---|---|---|---|---|\n| 1 | \
ManualMachine | Hosts that are manually created | MANUAL_MACHINE | ACTIVE |\n| 2 | CompanyProvider | \
Hosts that are automatically created when activating breadcrumbs | COMPANY_PROVIDER | ACTIVE |\n| 3 | \
ManualIdentity | Identities that are manually created | MANUAL_IDENTITY | ACTIVE |\n| 4 | ManualRouter | \
Routers that are manually created | MANUAL_ROUTER | ACTIVE |\n| 5 | MISP Provider |  | MISP_PROVIDER | ACTIVE |\n"
    )
    assert results["Contents"] == json_response["data"]
    assert results["EntryContext"] == {
        "CounterCraft.Provider(val.ID && val.ID === obj.ID)": [
            {
                "ID": 1,
                "Name": "ManualMachine",
                "Description": "Hosts that are manually created",
                "TypeCode": "MANUAL_MACHINE",
                "StatusCode": "ACTIVE",
            },
            {
                "ID": 2,
                "Name": "CompanyProvider",
                "Description": "Hosts that are automatically created when activating breadcrumbs",
                "TypeCode": "COMPANY_PROVIDER",
                "StatusCode": "ACTIVE",
            },
            {
                "ID": 3,
                "Name": "ManualIdentity",
                "Description": "Identities that are manually created",
                "TypeCode": "MANUAL_IDENTITY",
                "StatusCode": "ACTIVE",
            },
            {
                "ID": 4,
                "Name": "ManualRouter",
                "Description": "Routers that are manually created",
                "TypeCode": "MANUAL_ROUTER",
                "StatusCode": "ACTIVE",
            },
            {
                "ID": 5,
                "Name": "MISP Provider",
                "TypeCode": "MISP_PROVIDER",
                "StatusCode": "ACTIVE",
            },
        ]
    }


def test_list_campaigns_command(requests_mock, mocker):
    from CounterCraft import list_campaigns_command
    from test_data.api_response import response_campaigns as json_response

    requests_mock.get(f"{SERVER_URL}/api/campaigns", json=json_response, status_code=200)

    mocker.patch.object(demisto, "results")
    list_campaigns_command()
    results = demisto.results.call_args[0][0]

    assert (
        results["HumanReadable"]
        == "### Campaigns\n|Id|Name|Description|Statuscode|\n|---|---|---|---|\n| 1 | \
Devel Campaign | Campaign just to be used in devel | DESIGN |\n| 2 | 2nd Campaign | \
Campaign just to be used in devel 2 | DESIGN |\n"
    )
    assert results["Contents"] == json_response["data"]
    assert results["EntryContext"] == {
        "CounterCraft.Campaign(val.ID && val.ID === obj.ID)": [
            {
                "ID": 1,
                "Name": "Devel Campaign",
                "Description": "Campaign just to be used in devel",
                "StatusCode": "DESIGN",
            },
            {
                "ID": 2,
                "Name": "2nd Campaign",
                "Description": "Campaign just to be used in devel 2",
                "StatusCode": "DESIGN",
            },
        ]
    }


def test_list_hosts_command(requests_mock, mocker):
    from CounterCraft import list_hosts_command
    from test_data.api_response import response_hosts as json_response

    requests_mock.get(f"{SERVER_URL}/api/hosts", json=json_response, status_code=200)

    mocker.patch.object(demisto, "results")
    list_hosts_command()
    results = demisto.results.call_args[0][0]

    assert (
        results["HumanReadable"]
        == "### Hosts\n|Id|Name|Description|Statuscode|Typecode|\n|---|---|---|---|---|\n| 1 | \
Linux in AWS | Linux machine in AWS | DESIGN | MACHINE |\n"
    )
    assert results["Contents"] == json_response["data"]
    assert results["EntryContext"] == {
        "CounterCraft.Host(val.ID && val.ID === obj.ID)": [
            {
                "ID": 1,
                "Name": "Linux in AWS",
                "Description": "Linux machine in AWS",
                "TypeCode": "MACHINE",
                "StatusCode": "DESIGN",
            }
        ],
        "Host(val.IP && val.IP === obj.IP)": [{"ID": "61daa693-11cf-49a6-8fae-5111f630ee39", "IP": "1.4.5.6"}],
    }


def test_list_services_command(requests_mock, mocker):
    from CounterCraft import list_services_command
    from test_data.api_response import response_services as json_response

    requests_mock.get(f"{SERVER_URL}/api/services", json=json_response, status_code=200)

    mocker.patch.object(demisto, "results")
    list_services_command()
    results = demisto.results.call_args[0][0]

    assert (
        results["HumanReadable"]
        == "### Services\n|Id|Name|Description|Statuscode|Typecode|\n|---|---|---|---|---|\n| 1 | \
Employee web portal | <p>-</p> | ACTIVE | WEB_SERVER |\n| 2 | Test | <p>-</p> | DESIGN | WEB_SERVER |\n"
    )
    assert results["Contents"] == json_response["data"]
    assert results["EntryContext"] == {
        "CounterCraft.Service(val.ID && val.ID === obj.ID)": [
            {
                "ID": 1,
                "Name": "Employee web portal",
                "Description": "<p>-</p>",
                "TypeCode": "WEB_SERVER",
                "StatusCode": "ACTIVE",
            },
            {
                "ID": 2,
                "Name": "Test",
                "Description": "<p>-</p>",
                "TypeCode": "WEB_SERVER",
                "StatusCode": "DESIGN",
            },
        ]
    }


def test_list_breadcrumbs_command(requests_mock, mocker):
    from CounterCraft import list_breadcrumbs_command
    from test_data.api_response import response_breadcrumbs as json_response

    requests_mock.get(f"{SERVER_URL}/api/breadcrumbs", json=json_response, status_code=200)

    mocker.patch.object(demisto, "results")
    list_breadcrumbs_command()
    results = demisto.results.call_args[0][0]

    assert (
        results["HumanReadable"]
        == "### Breadcrumbs\n|Id|Name|Description|Statuscode|Typecode|\n|---|---|---|---|---|\n| 1 | \
Fake Document | <p>-</p> | DESIGN | DOCUMENT |\n| 2 | Fake Mobile App | <p>-</p> | ACTIVE | MOBILE_APP |\n"
    )
    assert results["Contents"] == json_response["data"]
    assert results["EntryContext"] == {
        "CounterCraft.Breadcrumb(val.ID && val.ID === obj.ID)": [
            {
                "ID": 1,
                "Name": "Fake Document",
                "Description": "<p>-</p>",
                "TypeCode": "DOCUMENT",
                "StatusCode": "DESIGN",
            },
            {
                "ID": 2,
                "Name": "Fake Mobile App",
                "Description": "<p>-</p>",
                "TypeCode": "MOBILE_APP",
                "StatusCode": "ACTIVE",
            },
        ]
    }


def test_list_incidents_command(requests_mock, mocker):
    from CounterCraft import list_incidents_command
    from test_data.api_response import response_incidents as json_response

    requests_mock.get(f"{SERVER_URL}/api/incidents", json=json_response, status_code=200)

    mocker.patch.object(demisto, "results")
    list_incidents_command()
    results = demisto.results.call_args[0][0]

    assert (
        results["HumanReadable"]
        == "### Incidents\n|Id|Name|Description|Statuscode|Tlpcode|Tags|\n|---|---|---|---|---|---|\n| 1 | \
Invalid auth | Invalid auth incident. | OPEN | GREEN |  |\n"
    )
    assert results["Contents"] == json_response["data"]
    assert results["EntryContext"] == {
        "CounterCraft.Incident(val.ID && val.ID === obj.ID)": [
            {
                "ID": 1,
                "Name": "Invalid auth",
                "Description": "Invalid auth incident.",
                "StatusCode": "OPEN",
                "TLPCode": "GREEN",
            }
        ]
    }


def test_get_object_command(requests_mock, mocker):
    from CounterCraft import get_object_command
    from test_data.api_response import response_objects as json_response

    mocker.patch.object(demisto, "args", return_value={"value": "1.2.3.3"})

    requests_mock.get(f"{SERVER_URL}/api/objects", json=json_response, status_code=200)

    mocker.patch.object(demisto, "results")
    get_object_command()
    results = demisto.results.call_args[0][0]

    assert (
        results["HumanReadable"]
        == f"### Objects\n|Id|Value|Hits|Eventscount|Typecode|Score|Firstseen|Lastseen|Tags|\n|\
---|---|---|---|---|---|---|---|---|\n| 1411 | 1.2.3.3 | 370 | 168 | CC_IP | 0 | \
{formatEpochDate(json_response['data'][0]['first_seen'])} | {formatEpochDate(json_response['data'][0]['last_seen'])} |  |\n"
    )

    # Only dates have been changed
    results["Contents"][0]["first_seen"] = 1507030039.331
    results["Contents"][0]["last_seen"] = 1507313997.703
    assert results["Contents"] == json_response["data"]
    assert results["EntryContext"] == {
        "CounterCraft.Object(val.ID && val.ID === obj.ID)": [
            {
                "ID": 1411,
                "Value": "1.2.3.3",
                "Hits": 370,
                "Score": 0,
                "TypeCode": "CC_IP",
                "FirstSeen": f"{formatEpochDate(json_response['data'][0]['first_seen'])}",
                "LastSeen": f"{formatEpochDate(json_response['data'][0]['last_seen'])}",
                "EventsCount": 168,
            }
        ]
    }


def test_get_events_command(requests_mock, mocker):
    from CounterCraft import get_events_command
    from test_data.api_response import response_events as json_response

    mocker.patch.object(
        demisto,
        "args",
        return_value={"criteria": "type_code:ValidAuth", "max_results": 1},
    )

    requests_mock.get(f"{SERVER_URL}/api/events", json=json_response, status_code=200)

    mocker.patch.object(demisto, "results")
    get_events_command()
    results = demisto.results.call_args[0][0]

    assert (
        results["HumanReadable"]
        == f"### Events\n|Id|Campaignname|Categorycode|Hostname|Servicename|Eventdate|Score|\
Typecode|Data|Tags|\n|---|---|---|---|---|---|---|---|---|---|\n| 7882 | Linux Campaign |  | \
Ubuntu18.04 | SYSTEM (Ubuntu18.04) | {formatEpochDate(json_response['data'][0]['event_date'])} | 100 | ValidAuth | \
event: ValidAuth<br>subject: Login successful<br>username: ubuntu<br>logon_type: -1<br>process_basename: su | \
attack.T1078 |\n"
    )

    # Only dates have been changed
    results["Contents"][0]["event_date"] = 1570049630.0
    assert results["Contents"] == json_response["data"]
    assert results["EntryContext"] == {
        "CounterCraft.Event(val.ID && val.ID === obj.ID)": [
            {
                "ID": 7882,
                "CampaignName": "Linux Campaign",
                "HostName": "Ubuntu18.04",
                "ServiceName": "SYSTEM (Ubuntu18.04)",
                "EventDate": f"{formatEpochDate(json_response['data'][0]['event_date'])}",
                "Score": 100,
                "TypeCode": "ValidAuth",
                "Data": {
                    "event": "ValidAuth",
                    "subject": "Login successful",
                    "username": "ubuntu",
                    "logon_type": -1,
                    "process_basename": "su",
                },
                "Tags": ["attack.T1078"],
            }
        ]
    }


def test_create_campaign_command(requests_mock, mocker):
    from CounterCraft import create_campaign_command
    from test_data.api_response import response_campaigns as json_response

    mocker.patch.object(
        demisto,
        "args",
        return_value={"name": "TestCampaign", "description": "Test Description"},
    )

    requests_mock.post(f"{SERVER_URL}/api/campaigns", json=json_response["data"][0], status_code=201)

    mocker.patch.object(demisto, "results")
    create_campaign_command()
    results = demisto.results.call_args[0][0]

    assert (
        results["HumanReadable"]
        == "### Campaign\n|Id|Name|Description|Statuscode|\n|---|---|---|---|\n| 1 | Devel Campaign | \
Campaign just to be used in devel | DESIGN |\n"
    )

    assert results["Contents"] == json_response["data"][0]
    assert results["EntryContext"] == {
        "CounterCraft.Campaign(val.ID && val.ID === obj.ID)": {
            "ID": 1,
            "Name": "Devel Campaign",
            "Description": "Campaign just to be used in devel",
            "StatusCode": "DESIGN",
        }
    }


def test_manage_campaign_command(requests_mock, mocker):
    from CounterCraft import manage_campaign_command

    mocker.patch.object(
        demisto,
        "args",
        return_value={"campaign_id": "1", "operation": "activate"},
    )

    requests_mock.patch(
        f"{SERVER_URL}/api/campaigns/1",
        json={"message": "Action successful"},
        status_code=200,
    )

    mocker.patch.object(demisto, "results")
    manage_campaign_command()
    results = demisto.results.call_args[0][0]

    assert results["HumanReadable"] == "### Campaign Management\n|Id|Message|\n|---|---|\n| 1 | Action successful |\n"

    assert results["Contents"] == {"message": "Action successful"}
    assert results["EntryContext"] == {
        "CounterCraft.Campaign(val.ID && val.ID === obj.ID)": [{"ID": "1", "Message": "Action successful"}]
    }


def test_create_host_command(requests_mock, mocker):
    from CounterCraft import create_host_machine_command
    from test_data.api_response import response_hosts as json_response

    mocker.patch.object(
        demisto,
        "args",
        return_value={
            "name": "TestCampaign",
            "description": "Test Description",
            "provider_id": 1,
            "deception_support_node_id": 1,
            "campaign_id": 1,
            "ip_address": "1.1.1.1",
            "port": 22,
            "username": "ubuntu",
            "password": "password",
        },
    )

    requests_mock.post(f"{SERVER_URL}/api/hosts", json=json_response["data"][0], status_code=201)

    mocker.patch.object(demisto, "results")
    create_host_machine_command()
    results = demisto.results.call_args[0][0]

    assert (
        results["HumanReadable"]
        == "### Hosts\n|Id|Name|Description|Statuscode|Typecode|\n|---|---|---|---|---|\n| 1 | \
Linux in AWS | Linux machine in AWS | DESIGN | MACHINE |\n"
    )

    assert results["Contents"] == json_response["data"][0]
    assert results["EntryContext"] == {
        "CounterCraft.Host(val.ID && val.ID === obj.ID)": {
            "ID": 1,
            "Name": "Linux in AWS",
            "Description": "Linux machine in AWS",
            "TypeCode": "MACHINE",
            "StatusCode": "DESIGN",
        }
    }


def test_manage_host_command(requests_mock, mocker):
    from CounterCraft import manage_host_command

    mocker.patch.object(
        demisto,
        "args",
        return_value={"host_id": "1", "operation": "activate"},
    )

    requests_mock.patch(
        f"{SERVER_URL}/api/hosts/1",
        json={"message": "Action successful"},
        status_code=200,
    )

    mocker.patch.object(demisto, "results")
    manage_host_command()
    results = demisto.results.call_args[0][0]

    assert results["HumanReadable"] == "### Host Management\n|Id|Message|\n|---|---|\n| 1 | Action successful |\n"

    assert results["Contents"] == {"message": "Action successful"}
    assert results["EntryContext"] == {
        "CounterCraft.Host(val.ID && val.ID === obj.ID)": {
            "ID": "1",
            "Message": "Action successful",
        }
    }


def test_manage_service_command(requests_mock, mocker):
    from CounterCraft import manage_service_command

    mocker.patch.object(
        demisto,
        "args",
        return_value={"service_id": "1", "operation": "activate"},
    )

    requests_mock.patch(
        f"{SERVER_URL}/api/services/1",
        json={"message": "Action successful"},
        status_code=200,
    )

    mocker.patch.object(demisto, "results")
    manage_service_command()
    results = demisto.results.call_args[0][0]

    assert results["HumanReadable"] == "### Service Management\n|Id|Message|\n|---|---|\n| 1 | Action successful |\n"

    assert results["Contents"] == {"message": "Action successful"}
    assert results["EntryContext"] == {
        "CounterCraft.Service(val.ID && val.ID === obj.ID)": {
            "ID": "1",
            "Message": "Action successful",
        }
    }


def test_manage_breadcrumb_command(requests_mock, mocker):
    from CounterCraft import manage_breadcrumb_command

    mocker.patch.object(
        demisto,
        "args",
        return_value={"breadcrumb_id": "1", "operation": "activate"},
    )

    requests_mock.patch(
        f"{SERVER_URL}/api/breadcrumbs/1",
        json={"message": "Action successful"},
        status_code=200,
    )

    mocker.patch.object(demisto, "results")
    manage_breadcrumb_command()
    results = demisto.results.call_args[0][0]

    assert results["HumanReadable"] == "### Breadcrumb Management\n|Id|Message|\n|---|---|\n| 1 | Action successful |\n"

    assert results["Contents"] == {"message": "Action successful"}
    assert results["EntryContext"] == {
        "CounterCraft.Breadcrumb(val.ID && val.ID === obj.ID)": {
            "ID": "1",
            "Message": "Action successful",
        }
    }


def test_fetch_incidents_command(requests_mock, mocker):
    from CounterCraft import fetch_incidents_command
    from test_data.api_response import response_alerts as json_response

    requests_mock.get(
        f"{SERVER_URL}/api/notifications",
        json=json_response,
        status_code=200,
    )

    mocker.patch.object(demisto, "incidents")
    fetch_incidents_command()
    incidents = demisto.incidents.call_args[0][0]
    assert demisto.incidents.call_count == 1
    assert len(incidents) == 1
    assert incidents[0]["name"] == "Possible mimikatz"