EclecticIQ Platform v2 Deprecated

Deprecated. Use EclecticIQ Intelligence Center v3 instead.

Data Enrichment & Threat Intelligence · EclecticIQ Platform

Details

IDEclecticIQ Platform v2
ProviderEclecticIQ
CategoryData Enrichment & Threat Intelligence
From Version6.5.0
Docker Imagedemisto/python3:3.10.13.72123
Supported ModulesAgentix XSIAM

README

EclecticIQ Platform v2

Threat Intelligence Platform that connects and interprets intelligence data from open sources, commercial suppliers and industry partnerships.
This integration was integrated and tested with version of EclecticIQ Platform v2

Configure EclecticIQ Platform v2 in Cortex

Parameter Required
Server URL (e.g. https://ic-playground.eclecticiq.com/api/v1) True
API Key True
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.

EclecticIQ_lookup_observables


Lookup observables from EclecticIQ Intelligence Center Platform

Base Command

EclecticIQ_lookup_observables

Input

Argument Name Description Required
type Type of the value to lookup observables from . Possible values are: ipv4, ipv6, domain, uri, email, hash-md5, hash-sha256, hash-sha1, hash-sha512. Required
value Value to search the related observables from EclecticIQ Intelligence Center Platform. Required

Context Output

Path Type Description
EclecticIQ.Observables.type string EclecticIQ Observables type
EclecticIQ.Entity.confidence string EclecticIQ Entity confidence
EclecticIQ.Entity.observables string EclecticIQ Entity related observables
EclecticIQ.Entity.threat_start_time date EclecticIQ Threat start time
EclecticIQ.Entity.title string EclecticIQ Entity Title

Command Example

!EclecticIQ_lookup_observables type="ipv4" value="001.001.001.001"

Context Example

{
    "EclecticIQ":{
       "DBotScore":{
          "Created":"2022-12-20T12:47:24.531410+00:00",
          "ID":"9382489",
          "LastUpdated":"2022-12-20T12:47:24.398456+00:00",
          "Type":"ipv4",
          "indicator":"ipv4",
          "score":3
       },
       "Entity":{
          "confidence":"unknown",
          "threat_start_time":"2022-12-20T12:47:24.474221+00:00",
          "title":"sighting",
          "observables":{
             "classification":"high",
             "type":"ipv4",
             "value":"000.001.001.001",
             "Malicious":{
                "Description":"EclectiqIQ maliciousness confidence level: high",
                "Vendor":"EclectiqIQ"
             },
             "data":[
                {
                   "created_at":"2022-08-24T10:02:04.609448+00:00",
                   "entities":[
                      "https://ic-playground.eclecticiq.com/api/v1/entities/183fa404-ba48-471b-980d-02600fe89a2b"
                   ],
                   "id":7938475,
                   "last_updated_at":"2022-11-23T06:25:55.945630+00:00",
                   "meta":{
                      "maliciousness":"medium"
                   },
                   "sources":[
                      "https://ic-playground.eclecticiq.com/api/v1/sources/9a479225-37d1-4dae-9554-172eeccea193"],
                   "type":"ipv4",
                   "value":"000.001.001.001"
                }
             ]
          }
       }
    }
 }
Human Readable Output

EclecticIQ observable reputation - 001.001.001.001

confidence description observables source_name tags threat_start_time title
low creationofsighting {‘type’: ‘ipv4’, ‘value’: ‘001.001.001.001, ‘classification’: ‘low’}     2022-08-25T04:50:56+00:00 sighting

EclecticIQ_create_sighting


create sighting in the EclecticIQ Intelligence Center Platform

Base Command

EclecticIQ_create_sighting

Input

Argument Name Description Required
value value for the sighting. Required
description description about the sighting. Required
title Title for the sighting. Required
tags Tag for the sighting. Required
type type for the sighting. Possible values are: ipv4, ipv6, domain, uri, email, hash-md5, hash-sha256, hash-sha1, hash-sha512. Required
confidence_level severity level of the sighting. Possible values are: low, medium, high, unknown. Required

Context Output

Path Type Description
Sighting.Data.data.type string Sighting Type
Sighting.Data.data.tags string Sighting Tags
Sighting.Data.data.title string Sighting Title
Sighting.Data.data.description string Sighting Description
Sighting.Data.data.timestamp string Sighting timestamp

Command Example

!EclecticIQ_create_sighting type="ipv4" value="001.001.001.001" description="sighting creation" title="sighting" tags="Alert" confidence_level="high"

Context Example

{
   "Sighting":{
      "Data":{
         "data":{
            "last_updated_at":"2022-12-28T12:45:05.465825+00:00",
            "outgoing_feeds":[],
            "meta":{
               "estimated_observed_time":"2022-12-28T12:45:05.508090+00:00",
               "half_life":182,
               "attacks":[],
               "estimated_threat_start_time":"2022-12-28T12:45:04+00:00",
               "taxonomies":[],
               "estimated_threat_end_time":"null",
               "source_reliability":"A",
               "tags":["Alert"],
               "tlp_color":null
            },
            "created_at":"2022-12-28T12:45:05.508090+00:00",
            "data":{
               "confidence":"high",
               "description":"sighting creation",
               "id":"{https://ic-playground.eclecticiq.com}eclecticiq-sighting-742ad072-86ad-11ed-ad71-067b5e23fb5e",
               "timestamp":"2022-12-28T12:45:04+00:00",
               "title":"sighting",
               "relevancy":1
            },
            "observables":[
               "https://ic-playground.eclecticiq.com/api/v1/observables/9391529"
            ],
            "attachments":[],
            "incoming_feed":null,
            "sources":[
               "https://ic-playground.eclecticiq.com/api/v1/sources/9a479225-37d1-4dae-9554-172eeccea193"
            ],
            "type":"eclecticiq-sighting",
            "id":"453d1fb2-d654-4a7a-9654-40556a893640",
            "datasets":[]
         }
      }
   }
}
Human Readable Output

!sighting created for- 001.001.001.001

confidence description
Type ipv4
confidence_level low
description sighting creation
tags Alert
title sighting
value 001.001.001.001

EclecticIQ_create_observable


create observable in the EclecticIQ Intelligence Center Platform

Base Command

EclecticIQ_create_observable

Input

Argument Name Description Required
type Type of the observable. Possible values are: ipv4, ipv6, domain, uri, email, hash-md5, hash-sha1, hash-sha256, hash-sha512. Required
value value of the type of observable. Required
maliciousness severity level of the type. Possible values are: unknown, safe, low, medium, high. Required

Context Output

Path Type Description
Observables.Data.data.type string Observable Type
Observables.Data.data.value string Observable Value
Observables.Data.data.maliciousness string Observable maliciousness

Command Example

!EclecticIQ_create_observable type="ipv4" value="001.001.001.001" maliciousness="high"

Context Example

{
   "Observables":{
      "Data":{
         "data":[
            {
               "created_at":"2022-12-26T13:16:06.757271+00:00",
               "entities":[
                  "https://ic-playground.eclecticiq.com/api/v1/entities/3a1cc90b-9cbd-437a-ab0b-7153b1bb275b"
               ],
               "id":9389500,
               "last_updated_at":"2022-12-26T13:16:06.677236+00:00",
               "meta":{
                  "maliciousness":"low"
               },
               "sources":[
                  "https://ic-playground.eclecticiq.com/api/v1/sources/9a479225-37d1-4dae-9554-172eeccea193"
               ],
               "type":"ipv4",
               "value":"001.001.001.001"
            }
         ]
      }
   }
}
Human Readable Output

Observables created successfully…

confidence description
maliciousness low
type ipv4
value 001.001.001.001

Configuration parameters

  • url — Server URL (e.g. https://ic-playground.eclecticiq.com/api/v1) (required)
  • apikey — API Key (required)
  • proxy — Use system proxy settings

Commands (3)

  • EclecticIQ_create_observable

    create observable in the EclecticIQ Intelligence Center Platform

  • EclecticIQ_create_sighting

    create sighting in the EclecticIQ Intelligence Center Platform

  • EclecticIQ_lookup_observables

    Lookup observables from EclecticIQ Intelligence Center Platform

import demistomock as demisto  # noqa: F401
from CommonServerPython import *  # noqa: F401
import json
import re
import traceback
from typing import Any, Dict, List, Mapping, Tuple
import urllib3

"""EclecticIQ Integration for Cortex XSOAR."""

# Disable insecure warnings
urllib3.disable_warnings()

''' CONSTANTS '''

DATE_FORMAT = '%Y-%m-%dT%H:%M:%SZ'

''' CLIENT CLASS '''


class Client(BaseClient):
    def sighting(self, value: str, description: str,
                 title: str, tags: str, type_eiq: str, confidence_level: str) -> Dict[str, Any]:
        """Create the sighting using the '/entities' API endpoint
        :param value: sighting value
        :type value: str
        :param description: sighting description
        :type description: str
        :param title: title for the sighting
        :type title: str
        :param tags: sighting tags
        :type tags: str
        :param type_eiq: sighting value type
        :type type_eiq: str
        :param confidence_level: maliciousness of the value
        :type confidence_level : ``str``
        :return: sighting payload
        :rtype: ``Dict[str, Any]``
        """
        sighting_schema: Mapping[str, Any] = {
            "data": {
                "data": {
                    "value": "value1",
                    "confidence": "medium",
                    "description": "test_desc",
                    "type": "eclecticiq-sighting",
                    "timestamp": "2022-03-10T05:37:42Z",
                    "title": "title1",
                    "security_control": {
                            "type": "information-source",
                            "identity": {
                                "name": "EclecticIQ Platform App for cortex XSOAR",
                                "type": "identity"
                            },
                        "time": {
                                "type": "time",
                                "start_time": "2022-03-10T05:37:42Z",
                                "start_time_precision": "second"}
                    }
                },
                "meta": {"tags": ["XSOAR Alert"], "ingest_time": "2022-03-10T05:37:42Z"}
            }
        }
        sighting_schema["data"]["data"]["value"] = value
        sighting_schema["data"]["data"]["confidence"] = confidence_level
        sighting_schema["data"]["data"]["description"] = description
        sighting_schema["data"]["data"]["title"] = title
        sighting_schema["data"]["data"]["security_control"]["type"] = type_eiq
        sighting_schema["data"]["meta"]["tags"] = tags.split(",")
        sighting_schema["data"]["data"]["timestamp"] = datetime.strftime(
            datetime.utcnow(), DATE_FORMAT)
        return self._http_request(
            method='POST',
            url_suffix='/entities',
            data=json.dumps(sighting_schema)
        )

    def lookup_obs(self, type_eiq: str, value: str) -> Dict[str, Any]:
        """Get observables using the '/observables' API endpoint.
        :param type_eiq: observable type
        :type type_eiq: str
        :param value: observable value
        :type value: str
        :return: observables
        :rtype: Dict[str, Any]
        """
        return self._http_request(
            method='GET',
            url_suffix='observables',
            params={"filter[type]": type_eiq, "filter[value]": value}
        )

    def fetch_entity(self, id: str) -> Dict[str, Any]:
        """Get entity details by id.
        :param id: entity id
        :type: str
        :return: id releted entity
        :rtype: Dict[str, Any]
        """
        return self._http_request(
            method='GET',
            url_suffix='/entities/{}'.format(id),
            params={}
        )

    def get_observable_by_id(self, id: str) -> Dict[str, Any]:
        """Get observables by id.
        :param id: observable id
        :type id: str
        :return: id related observable
        :rtype: Dict[str, Any]
        """
        return self._http_request(
            method='GET',
            url_suffix=f'observables/{id}',
            params={}
        )

    def observable(self, type_eiq: str, value: str, maliciousness: str) -> Dict[str, Any]:
        """Create the observable using the '/observables' API endpoint
        :param type_eiq: observable type
        :type type_eiq: str
        :param value: observable value
        :type value: str
        :param maliciousness: maliciousness of the value
        :type maliciousness: str
        :return: observable payload
        :rtype: ``Dict[str, Any]``
        """
        body_params: Mapping[str, Any] = {
            "data": {
                "meta": {
                    "maliciousness": "Unknown"
                },
                "type": "Unknown",
                "value": "value1"
            }
        }
        body_params["data"]["type"] = type_eiq
        body_params["data"]["value"] = value
        body_params["data"]["meta"]["maliciousness"] = maliciousness
        return self._http_request(
            method='POST',
            url_suffix='/observables',
            data=json.dumps(body_params)
        )

    def get_user_granted_permissions(self) -> Any:
        """Get user granted permissions.
        :param: self
        :type: str
        :return: user granted permissions
        :rtype: Any
        """
        response = self._http_request(
            method='GET',
            url_suffix='users/self',
            params={}
        )
        data = response.get("data")
        if data:
            return data.get("permissions")
        return {}

    def get_platform_permissions(self) -> Any:
        """Get platform permissions for user.
        :param: self
        :type: str
        :return: permissions data
        :rtype: Any
        """
        response = self._http_request(
            method='GET',
            url_suffix='permissions',
            params={}
        )
        data = response.get("data", {})
        return data or {}


def get_platform_permission_ids(permissions_data: Any) -> List[Any]:
    """Get permission ids required for user to authenticate.
    :param feeds: permissions_data
    :type response: list
        [{"id": 1, "name": "read history-events"},{"id": 2,"name": "read discovery-rules"}...]
    :return: List of permission ids
        [33, 59, 66,78]
    :rtype: list
    """
    wanted_permissions = [
        "read entitites",
        "modify entities",
        "read extracts",
        "read outgoing-feeds",
    ]
    ids_required_for_user = []
    for value in permissions_data:
        if value.get("name") in wanted_permissions:
            ids_required_for_user.append(value.get("id"))

    return ids_required_for_user


def authenticate_user(ids_of_user: list, ids_required_for_user: list) -> Tuple[bool, List[int]]:
    """Get user authentication and missing permission ids .
    :param ids_of_user: permission ids user have
    :type ids_of_user: list
    :param ids_required_for_user: permission ids required for user to authenticate
    :type ids_required_for_user: list
    :return: is user authenticated , missing permissions ids
    :rtype: boolean,list
    """
    user_authenticated = False
    value = list(set(ids_required_for_user).difference(ids_of_user))

    if not value:
        user_authenticated = True
    return user_authenticated, value


def get_permission_name_from_id(permission_data: Dict, permission_ids: list) -> Any:
    """Get permission name from permission ids.
    :param permission_data: permission data
    :type permission_data: Dict
    :param permission_ids: permission id for authenticate
    :type permission_ids: list
    :return: permissions name
    :rtype: Any
    """
    permissions_name = []
    for data in permission_data:
        for permission_id in permission_ids:
            if data.get("id") == permission_id:
                permissions_name.append(data.get("name"))
    return permissions_name


def data_ingestion(client: Client) -> Any:
    """Tests API connectivity and authentication'
    Returning 'ok' indicates that the integration works like it is supposed to.
    Connection to the service is successful.
    Raises exceptions if something goes wrong.
    :type client: ``Client``
    :param Client: EclecticIQ client to use
    :return: 'ok' if test passed, anything else will fail the test.
    :rtype: ``Any``
    """
    try:
        permissions_of_user = client.get_user_granted_permissions()
    except Exception:
        return "Please provide correct URL & API Key."

    permission_ids = []
    missing_permissions = ""
    if isinstance(permissions_of_user, list):
        for permission in permissions_of_user:
            permission_ids.append(int(permission.split("/")[-1]))
    try:
        permissions_data = client.get_platform_permissions()
    except Exception:
        return "API Key does not have access to view permissions."
    if permissions_data:
        ids_required_for_user = get_platform_permission_ids(
            permissions_data
        )
        user_authenticated, permission_ids = authenticate_user(
            permission_ids, ids_required_for_user
        )
        if not user_authenticated:
            # check for missing permissions
            permissions_data = client.get_platform_permissions()
            missing_permissions = get_permission_name_from_id(
                permissions_data, permission_ids
            )
    else:
        missing_permissions = "Read Permissions"

    if missing_permissions:
        return "API Key is missing permissions {}".format(missing_permissions)

    return 'ok'


def maliciousness_to_dbotscore(maliciousness) -> int:
    """Translates EclecticIQ obversable maliciousness confidence level to DBotScore based on given threshold
    Parameters
    ----------
    maliciousness : str
        EclecticIQ obversable maliciousness confidence level.
    threshold : str
        Minimum maliciousness confidence level to consider the IOC malicious.
    Returns
    -------
    number
        Translated DBot Score
    """
    maliciousness_Dictionary = {
        'unknown': 0,
        'safe': 1,
        'low': 2,
        'medium': 2,
        'high': 3
    }
    return maliciousness_Dictionary[maliciousness]


def prepare_observable_data(data: Any) -> Dict:
    """Prepare Observable data to show on UI.
    :param data: Observable data
    :type data: Dict
    :return: Only selected fields Dict
    :rtype: Dict
    """
    new_data = {}
    new_data["type"] = data.get("type")
    new_data["value"] = data.get("value")
    new_data["classification"] = data.get("meta", {}).get("maliciousness")
    return new_data


def get_entity_data(client, data_item: Any) -> List[Any]:
    """Get entity data to show on UI.
    :param data_item: Data from lookup obsrvables Dict
    :type data_item: Any
    :return: prepared data to show on UI
    :rtype: List
    """
    entity_data_Dict_list = []
    for item in data_item.get("entities"):
        entity_data_Dict = {}
        entity_data = client.fetch_entity(
            str(item.split("/")[-1])
        )
        entity_data = entity_data.get("data")
        observables = entity_data.get(
            "observables") if entity_data.get("observables") else []
        obs_data_list = []
        for observable in observables:
            obs_data = client.get_observable_by_id(
                str(observable.split("/")[-1])
            )
            obs_data = obs_data.get("data")
            append_data = prepare_observable_data(obs_data)

            obs_data_list.append(append_data)

        entity_data_Dict.update(
            prepare_entity_data(entity_data, obs_data_list))
        entity_data_Dict_list.append(entity_data_Dict)
    return entity_data_Dict_list


def prepare_entity_data(data: Any, obs_data: Any) -> Dict[Any, Any]:
    """Prepare entity data to show on UI.
    :param data: Entity data
    :type data: Any
    :param obs_data: Observable data
    :type data: Any
    :return: Only selected fields Dict
    :rtype: Dict
    """
    new_data = {}
    if data.get("data"):
        new_data["title"] = (
            data.get("data", {}).get("title") if data.get(
                "data", {}).get("title") else ""
        )

        new_data["description"] = (
            data.get("data", {}).get("description")
            if data.get("data", {}).get("description")
            else ""
        )
        new_data["confidence"] = (
            data.get("data", {}).get("confidence")
            if data.get("data", {}).get("confidence")
            else ""
        )
        new_data["tags"] = (
            data.get("data", {}).get("tags") if data.get(
                "data", {}).get("tags") else ""
        )
    if data.get("meta"):
        new_data["threat_start_time"] = (
            data.get("meta", {}).get("estimated_threat_start_time")
            if data.get("meta", {}).get("estimated_threat_start_time")
            else ""
        )
        if data.get("data", {}).get("producer"):
            new_data["source_name"] = (
                data.get("data", {}).get("producer", {}).get("identity")
                if data.get("data", {}).get("producer", {}).get("identity")
                else ""
            )
        else:
            new_data["source_name"] = ""
        new_data["observables"] = obs_data

    return new_data


def validate_type(s_type: str, value: Any) -> Any:  # pylint: disable=R0911
    """Get the type of the observable.
    :param s_type :observable pattern type
    :type s_type: str
    :param value: observable value
    :type value: Any
    :return: type of the observable
    :rtype: Any
    """
    if s_type == "ipv4":  # pylint: disable=R1705
        return bool(re.match(r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", value))
    elif s_type == "ipv6":
        return bool(
            re.match(
                r"^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|\
                    ([0-9a-fA-F]{1,4}:){1,7}:|\
                    ([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|\
                    ([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|\
                    ([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|\
                    ([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|\
                    ([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|\
                    [0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|\
                    :((:[0-9a-fA-F]{1,4}){1,7}|:)|\
                    fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|\
                    ::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|\
                    1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|\
                    1{0,1}[0-9]){0,1}[0-9])|\
                    ([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|\
                    1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|\
                    (2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$",
                value,   # pylint: disable=C0301
            )
        )
    elif s_type == "email":
        return bool(re.match(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]+", value))
    elif s_type == "uri":
        return bool(re.match(r"[^\:]+\:\/\/[\S]+", value))
    elif s_type == "domain":
        return bool(
            re.match(
                r"^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9](?:\.[a-zA-Z]{2,})+$",
                value,
            )
        )
    elif s_type == "hash-md5":
        return bool(re.match(r"^[a-f0-9A-F]{32}$", value))
    elif s_type == "hash-sha256":
        return bool(re.match(r"^[a-f0-9A-F]{64}$", value))
    elif s_type == "hash-sha1":
        return bool(re.match(r"\b[0-9a-f]{5,40}\b", value))
    elif s_type == "hash-sha512":
        return bool(re.match(r"^\w{128}$", value))
    else:
        return False


def EclecticIQ_lookup_observables(client: Client, args: Any) -> CommandResults:
    """lookup_observables command: Returns the observable
    :type client: ``Client``
    :param Client: EclecticIQ client to use
    :type args: ``Any``
    :param args: args {type, value}
    :return: observable data
    :rtype: ``CommandResults``
    """
    type_eiq = args.get("type")
    value_eiq = args.get("value")
    if not validate_type(type_eiq, value_eiq):
        raise ValueError("Type does not match specified value")
    response = client.lookup_obs(type_eiq, value_eiq)
    if response.get("data"):
        data_item = response["data"]
    else:
        return CommandResults(readable_output="No observable data found.")
    standard_observable_outputs = []
    final_data = []
    for observable in data_item:
        maliciousness = observable.get("meta", {}).get("maliciousness")
        score = maliciousness_to_dbotscore(maliciousness)
        standard_observable_output = {
            'data': observable
        }
        if score == 3:
            standard_observable_output['Malicious'] = {
                'Vendor': 'EclecticIQ',
                'Description': 'EclecticIQ maliciousness confidence level: ' + maliciousness
            }
            standard_observable_outputs.append(standard_observable_output)
        dbot_output = {
            'Type': observable.get("type"),
            'indicator': observable.get("type"),
            'Created': observable.get('created_at'),
            'LastUpdated': observable.get('last_updated_at'),
            'ID': observable.get('id'),
            'score': score
        }
        context = {
            'DBotScore': dbot_output
        }  # type: Dict
        if observable.get("entities"):
            entity_data = get_entity_data(client, observable)
            final_data = entity_data
    human_readable_title = 'EclecticIQ observable reputation - {}'.format(
        value_eiq)
    human_readable = tableToMarkdown(human_readable_title, final_data)
    context['Entity'] = createContext(
        data=final_data, removeNull=True)
    context[outputPaths['ip']] = standard_observable_outputs
    return CommandResults(
        readable_output=human_readable,
        outputs_prefix='EclecticIQ',
        outputs_key_field='value',
        outputs=context
    )


def EclecticIQ_create_sighting(client: Client, args: Any) -> CommandResults:
    """create_sighting command: Returns the sighting data
    :type client: ``Client``
    :param Client: EclecticIQ client to use
    :type args: ``Any``
    :param args: args {value, description, title, tags, type, confidence_level}
    :return: sighting data
    :rtype: ``CommandResults``
    """
    value = args.get("value")
    description = args.get("description")
    title = args.get("title")
    tags = args.get("tags")
    type_eiq = args.get("type")
    confidence_level = args.get("confidence_level")
    if not validate_type(type_eiq, value):
        raise ValueError("Type does not match specified value")
    response = client.sighting(
        value, description, title, tags, type_eiq, confidence_level)
    context = {}
    output = {'value': value,
              'description': description,
              'title': title,
              'tags': tags,
              'Type': type_eiq,
              'confidence_level': confidence_level}
    human_readable_title = '!sighting created for- {}'.format(
        args.get("value"))
    human_readable = tableToMarkdown(human_readable_title, t=output)
    context['Data'] = createContext(
        data=response, removeNull=True)
    return CommandResults(
        readable_output=human_readable,
        outputs_prefix='Sighting',
        outputs_key_field='value',
        outputs=context
    )


def EclecticIQ_create_observable(client: Client, args: Any) -> CommandResults:
    """create_observable command: Returns the observable data
    :type client: ``Client``
    :param Client: EclecticIQ client to use
    :type args: ``Any``
    :param args: args {type, value}
    :return: observable data
    :rtype: ``CommandResults``
    """
    type_eiq = args.get("type")
    value = args.get("value")
    maliciousness = args.get("maliciousness")
    if not validate_type(type_eiq, value):
        raise ValueError("Type does not match specified value")
    response = client.observable(type_eiq, value, maliciousness)
    context = {}
    output = {'type': type_eiq,
              'value': value,
              'maliciousness': maliciousness
              }
    human_readable_title = "Observables created successfully..!!"
    human_readable = tableToMarkdown(human_readable_title, t=output)
    context['Data'] = createContext(
        data=response, removeNull=True)
    return CommandResults(
        readable_output=human_readable,
        outputs_prefix='Observables',
        outputs_key_field='value',
        outputs=context
    )


''' MAIN FUNCTION '''


def main() -> None:
    params = demisto.params()
    api_key = params.get('apikey', {}).get('password')
    base_url = params.get('url')
    verify_certificate = not params.get('insecure', False)
    proxy = params.get('proxy', False)
    demisto.debug(f'Command being called is {demisto.command()}')
    try:
        headers = {
            'Authorization': f'Bearer {api_key}'
        }
        client = Client(
            base_url=base_url,
            verify=verify_certificate,
            headers=headers,
            proxy=proxy)

        if demisto.command() == 'test-module':
            # This is the call made when pressing the integration Test button.
            return_results(data_ingestion(client))

        elif demisto.command() == 'EclecticIQ_lookup_observables':
            return_results(EclecticIQ_lookup_observables(client, demisto.args()))

        elif demisto.command() == 'EclecticIQ_create_sighting':
            return_results(EclecticIQ_create_sighting(client, demisto.args()))

        elif demisto.command() == 'EclecticIQ_create_observable':
            return_results(EclecticIQ_create_observable(client, demisto.args()))

        else:
            raise NotImplementedError(f'{demisto.command()} command is not implemented.')

    # Log exceptions and return errors
    except Exception as e:
        demisto.error(traceback.format_exc())  # print the traceback
        return_error(
            f'Failed to execute {demisto.command()} command.\nError:\n{str(e)}')


''' ENTRY POINT '''

if __name__ in ('__main__', '__builtin__', 'builtins'):
    main()