EclecticIQ Intelligence Center v3

Threat Intelligence Platform that connects and interprets intelligence data from open sources, commercial suppliers and industry partnerships .

Data Enrichment & Threat Intelligence · EclecticIQ Platform · Feed

Details

IDEclecticIQ Intelligence Center v3
ProviderEclecticIQ
CategoryData Enrichment & Threat Intelligence
From Version6.6.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM

README

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 2.14 and 3.0 of EclecticIQ Intelligence Center v3.

Some changes have been made that might affect your existing content.
If you are upgrading from a previous version of this integration, see Breaking Changes.

Configure EclecticIQ Intelligence Center v3 in Cortex

Parameter Description Required
EclecticIQ Intelligence Center URL (e.g. https://eclecticiq-platform.local)   True
API user token to authenticate in EclecticIQ Intelligence Center   True
EclecticIQ Intelligence Center public API version   True
IP threshold. Minimum maliciousness confidence level to consider the IP address malicious: High, Medium, Low, Safe, Unknown   False
URL threshold. Minimum maliciousness confidence level to consider the URL malicious: High, Medium, Low, Safe, Unknown   False
File threshold. Minimum maliciousness confidence level to consider the file malicious: High, Medium, Low, Safe, Unknown   False
Email threshold. Minimum maliciousness confidence level to consider the email address malicious: High, Medium, Low, Safe, Unknown   False
Domain threshold. Minimum maliciousness confidence level to consider the domain malicious: High, Medium, Low, Safe, Unknown   False
Group name in EclecticIQ Intelligence Center to use as entities source   False
Create sightings automatically in EclecticIQ Intelligence Center when reputation check command executed.   False
Fetch indicators    
Indicator Reputation Indicators from this integration instance will be marked with this reputation False
Source Reliability Reliability of the source providing the intelligence data True
    False
    False
Feed Fetch Interval   False
Bypass exclusion list When selected, the exclusion list is ignored for indicators from this feed. This means that if an indicator from this feed is on the exclusion list, the indicator might still be added to the system. False
Feed IDs to fetch e.g. 12,14,22 False
    False
Traffic Light Protocol Color The Traffic Light Protocol (TLP) designation to apply to indicators fetched from the feed  
Trust any certificate (not secure)   False
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.

ip


Get reputation of IP address observable.

Base Command

ip

Input

Argument Name Description Required
ip IPv4 to get the reputation of. Required

Context Output

Path Type Description
EclecticIQ.IP.Created Date Observable creation time.
EclecticIQ.IP.LastUpdated Date Observable last update time.
EclecticIQ.IP.Maliciousness String Observable maliciousness.
EclecticIQ.IP.Observable String Observable value.
EclecticIQ.IP.SourceName String Observable source name.
DBotScore.Indicator String The indicator that was tested.
DBotScore.Score Number The actual score.
DBotScore.Reliability String How reliable the score is (for example, “C - fairly reliable”).
DBotScore.Type String The indicator type.
DBotScore.Vendor String The vendor used to calculate the score.
IP.Address String IP address.

Command example

!ip ip="8.8.8.8"

Context Example

{
    "DBotScore": {
        "Indicator": "8.8.8.8",
        "Score": 0,
        "Type": "ip",
        "Vendor": "EclecticIQ Intelligence Center v3"
    },
    "EclecticIQ": {
        "IP": {
            "Created": "2023-10-09T18:00",
            "LastUpdated": "2023-11-13T15:35",
            "Maliciousness": "unknown",
            "Observable": "8.8.8.8",
            "SourceName": "enricher_task: VirusTotal APIv3 File Hash (Contacted Infrastructure) Enricher; enricher_task: Recorded Future Enricher; group: Testing Group; "
        }
    },
    "IP": {
        "Address": "8.8.8.8"
    }
}

Human Readable Output

EclecticIQ IP reputation - 8.8.8.8

created id last_updated maliciousness platform_link source_name type value
2023-10-09T18:00 466127 2023-11-13T15:35 unknown https://ic-playground.eclecticiq.com/main/intel/all/browse/observable?tab=overview&id=466127 enricher_task: VirusTotal APIv3 File Hash (Contacted Infrastructure) Enricher; enricher_task: Recorded Future Enricher; group: Testing Group; ipv4 8.8.8.8

url


Gets the reputation of a URL observable.

Base Command

url

Input

Argument Name Description Required
url URL observable to get the reputation of. Required

Context Output

Path Type Description
EclecticIQ.URL.Created Date Observable creation time.
EclecticIQ.URL.LastUpdated Date Observable last update time.
EclecticIQ.URL.Maliciousness String Observable maliciousness.
EclecticIQ.URL.Observable String Observable value.
EclecticIQ.URL.SourceName String Observable source name.
DBotScore.Indicator String The indicator that was tested.
DBotScore.Score Number The actual score.
DBotScore.Reliability String How reliable the score is (for example, “C - fairly reliable”).
DBotScore.Type String The indicator type.
DBotScore.Vendor String The vendor used to calculate the score.
URL.Data String URL requested.

Command example

!url url="https://www.ultimatewindowssecurity.com/securitylog/encyclopedia/"

Context Example

{
    "DBotScore": {
        "Indicator": "https://www.ultimatewindowssecurity.com/securitylog/encyclopedia/",
        "Score": 0,
        "Type": "url",
        "Vendor": "EclecticIQ Intelligence Center v3"
    },
    "EclecticIQ": {
        "URL": {
            "Created": "2023-06-02T08:14",
            "LastUpdated": "2023-06-02T08:14",
            "Maliciousness": "unknown",
            "Observable": "https://www.ultimatewindowssecurity.com/securitylog/encyclopedia/",
            "SourceName": "incoming_feed: Elemendar; "
        }
    },
    "URL": {
        "Data": "https://www.ultimatewindowssecurity.com/securitylog/encyclopedia/"
    }
}

Human Readable Output

EclecticIQ URL reputation - https://www.ultimatewindowssecurity.com/securitylog/encyclopedia/

created id last_updated maliciousness platform_link source_name type value
2023-06-02T08:14 119519 2023-06-02T08:14 unknown https://ic-playground.eclecticiq.com/main/intel/all/browse/observable?tab=overview&id=119519 incoming_feed: Elemendar; uri https://www.ultimatewindowssecurity.com/securitylog/encyclopedia/

file


Gets the reputation of a file hash observable.

Base Command

file

Input

Argument Name Description Required
file File hash observable to get the reputation of. Required

Context Output

Path Type Description
EclecticIQ.File.Created Date Observable creation time.
EclecticIQ.File.LastUpdated Date Observable last update time.
EclecticIQ.File.Maliciousness String Observable maliciousness.
EclecticIQ.File.Observable String Observable value.
EclecticIQ.File.SourceName String Observable source name.
DBotScore.Indicator String The indicator that was tested.
DBotScore.Score Number The actual score.
DBotScore.Reliability String How reliable the score is (for example, “C - fairly reliable”).
DBotScore.Type String The indicator type.
DBotScore.Vendor String The vendor used to calculate the score.
File.MD5 String Bad MD5 hash.
File.SHA1 String Bad SHA1 hash.
File.SHA256 String Bad SHA256 hash.

Command example

!file file=ae5f156a6f5052494a295c597389dbee

Context Example

{
    "DBotScore": {
        "Indicator": "ae5f156a6f5052494a295c597389dbee",
        "Score": 0,
        "Type": "file",
        "Vendor": "EclecticIQ Intelligence Center v3"
    },
    "EclecticIQ": {
        "File": {
            "Created": "2023-05-26T09:20",
            "LastUpdated": "2023-05-26T09:20",
            "Maliciousness": "unknown",
            "Observable": "ae5f156a6f5052494a295c597389dbee",
            "SourceName": "enricher_task: Threatcrowd API V2; "
        }
    },
    "File": {
        "Hashes": [
            {
                "type": "MD5",
                "value": "ae5f156a6f5052494a295c597389dbee"
            }
        ],
        "MD5": "ae5f156a6f5052494a295c597389dbee"
    }
}

Human Readable Output

EclecticIQ File reputation - ae5f156a6f5052494a295c597389dbee

created id last_updated maliciousness platform_link source_name type value
2023-05-26T09:20 13 2023-05-26T09:20 unknown https://ic-playground.eclecticiq.com/main/intel/all/browse/observable?tab=overview&id=13 enricher_task: Threatcrowd API V2; hash-md5 ae5f156a6f5052494a295c597389dbee

eclecticiq-get-entity


Query EIC for entity.

Base Command

eclecticiq-get-entity

Input

Argument Name Description Required
observable_value Observable value to query related entities. Optional
entity_title Text to search inside entity title. Optional
entity_type Type of entity to limit query. Possible values are: all, campaign, course-of-action, exploit-target, incident, indicator, sighting, threat-actor, ttp. Default is all. Optional

Context Output

Path Type Description
EclecticIQ.Entity.confidence String Entity confidence.
EclecticIQ.Entity.created_at Date Entity creation time.
EclecticIQ.Entity.description String Entity description.
EclecticIQ.Entity.entity_title String Entity title.
EclecticIQ.Entity.entity_type String Entity type.
EclecticIQ.Entity.impact.type String Entity impact type.
EclecticIQ.Entity.impact.value String Entity impact value.
EclecticIQ.Entity.impact.value_vocab String Entity impact STIX vocabulary.
EclecticIQ.Entity.observables_list.maliciousness String Related observable maliciousness.
EclecticIQ.Entity.observables_list.type String Related observable type.
EclecticIQ.Entity.observables_list.value String Related observable value.
EclecticIQ.Entity.observables_output String Related observables string.
EclecticIQ.Entity.relationships_list Unknown Entity relationships list.
EclecticIQ.Entity.relationships_output String Entity relationships string.
EclecticIQ.Entity.source_name String Entity source.
EclecticIQ.Entity.tags_list Unknown Entity tags and taxonomies.

email


Gets the reputation of an email address observable.

Base Command

email

Input

Argument Name Description Required
email Email address observable to get the reputation of. Required

Context Output

Path Type Description
EclecticIQ.Email.Created Date Observable creation time.
EclecticIQ.Email.LastUpdated Date Observable last update time.
EclecticIQ.Email.Maliciousness String Observable maliciousness.
EclecticIQ.Email.Observable String Observable value.
EclecticIQ.Email.SourceName String Observable source name.
DBotScore.Indicator String The indicator that was tested.
DBotScore.Score Number The actual score.
DBotScore.Reliability String How reliable the score is (for example, “C - fairly reliable”).
DBotScore.Type String The indicator type.
DBotScore.Vendor String The vendor used to calculate the score.

Command example

!email email=domains@twitter.com

Context Example

{
    "DBotScore": {
        "Indicator": "domains@twitter.com",
        "Score": 0,
        "Type": "email",
        "Vendor": "EclecticIQ Intelligence Center v3"
    },
    "EclecticIQ": {
        "Email": {
            "Created": "2023-05-26T09:22",
            "LastUpdated": "2023-05-26T09:22",
            "Maliciousness": "unknown",
            "Observable": "domains@twitter.com",
            "SourceName": "enricher_task: Threatcrowd API V2; "
        }
    },
    "Email": {
        "Address": "domains@twitter.com"
    }
}

Human Readable Output

EclecticIQ Email reputation - domains@twitter.com

created id last_updated maliciousness platform_link source_name type value
2023-05-26T09:22 1028 2023-05-26T09:22 unknown https://ic-playground.eclecticiq.com/main/intel/all/browse/observable?tab=overview&id=1028 enricher_task: Threatcrowd API V2; email domains@twitter.com

domain


Gets the reputation of a domain observable.

Base Command

domain

Input

Argument Name Description Required
domain Domain observable to get the reputation of. Required

Context Output

Path Type Description
EclecticIQ.Domain.Created Date Observable creation time.
EclecticIQ.Domain.LastUpdated Date Observable last update time.
EclecticIQ.Domain.Maliciousness String Observable maliciousness.
EclecticIQ.Domain.Observable String Observable value.
EclecticIQ.Domain.SourceName String Observable source name.
DBotScore.Indicator String The indicator that was tested.
DBotScore.Score Number The actual score.
DBotScore.Reliability String How reliable the score is (for example, “C - fairly reliable”).
DBotScore.Type String The indicator type.
DBotScore.Vendor String The vendor used to calculate the score.
Domain.Name String Requested Domain.

Command example

!domain domain=urlz.fr

Context Example

{
    "DBotScore": {
        "Indicator": "urlz.fr",
        "Score": 3,
        "Type": "domain",
        "Vendor": "EclecticIQ Intelligence Center v3"
    },
    "Domain": {
        "Malicious": {
            "Description": "EclecticIQ maliciousness confidence level: low",
            "Vendor": "EclecticIQ Intelligence Center v3"
        },
        "Name": "urlz.fr"
    },
    "EclecticIQ": {
        "Domain": {
            "Created": "2023-05-26T09:20",
            "LastUpdated": "2023-05-26T09:20",
            "Maliciousness": "low",
            "Observable": "urlz.fr",
            "SourceName": ""
        }
    }
}

Human Readable Output

EclecticIQ Domain reputation - urlz.fr

created id last_updated maliciousness platform_link source_name type value
2023-05-26T09:20 43 2023-05-26T09:20 low https://ic-playground.eclecticiq.com/main/intel/all/browse/observable?tab=overview&id=43   domain urlz.fr

eclecticiq-create-sighting


Create a sighting entity on EIC.
Must contain at least one observable.

Base Command

eclecticiq-create-sighting

Input

Argument Name Description Required
observable_value Observable value to connect to Sighting. Required
observable_type Observable type. Possible values are: domain, email, email-subject, file, hash, hash-md5, hash-sha1, hash-sha256, hash-sha512, host, ipv4, ipv6, mutex, port, process, uri, winregistry. Required
observable_maliciousness Observable maliciousness. Possible values are: Malicious (High confidence), Malicious (Medium confidence), Malicious (Low confidence), Safe, Unknown. Required
sighting_title Sighting title. Required
sighting_description Sighting description. Optional
sighting_confidence Sighting confidence. Possible values are: None, Unknown, Low, Medium, High. Required
sighting_impact Sighting impact. Possible values are: None, Unknown, Low, Medium, High. Required
sighting_tag Sighting tags, use comma (“,”) as delimeter between tags. Optional

Context Output

Path Type Description
EclecticIQ.Sightings.SightingDetails.ObservableMaliciousness String Sighting related observable maliciousness.
EclecticIQ.Sightings.SightingDetails.ObservableType String Sighting related observable type.
EclecticIQ.Sightings.SightingDetails.ObservableValue String Sighting related observable value.
EclecticIQ.Sightings.SightingDetails.SightingTitle String Sighting title.
EclecticIQ.Sightings.SightingId String Sighting entity ID.

eclecticiq-create-indicator


Create an indicator entity on EIC.
Must contain at least one observable.

Base Command

eclecticiq-create-indicator

Input

Argument Name Description Required
indicator_title Indicator title. Required
indicator_description Indicator description. Optional
indicator_confidence Indicator confidence. Possible values are: None, Unknown, Low, Medium, High. Required
indicator_impact Indicator impact. Possible values are: None, Unknown, Low, Medium, High. Required
indicator_tag Indicator tags, use comma (“,”) as delimeter between tags. Optional
observable_value Observable value to connect to Indicator. Required
observable_type Observable type. Possible values are: domain, email, email-subject, file, hash, hash-md5, hash-sha1, hash-sha256, hash-sha512, host, ipv4, ipv6, mutex, port, process, uri, winregistry. Required
observable_maliciousness Observable maliciousness. Possible values are: Malicious (High confidence), Malicious (Medium confidence), Malicious (Low confidence), Safe, Unknown. Required
observable_dictionary Any amount observables in format: [{“value”:”192.168.0.192”, “type”:”ipv4”, “maliciousness”:”medium”}]. Observable types use as in EclecticIQ. Observable maliciousness could be: high, medium, low, safe, unknown. Optional

Context Output

Path Type Description
EclecticIQ.Indicators.IndicatorId String Indicator entity ID.
EclecticIQ.Indicators.IndicatorTitle String Indicator entity title.
EclecticIQ.Indicators.ObservablesList.observable_classification String Indicator related observable classification.
EclecticIQ.Indicators.ObservablesList.observable_maliciousness String Indicator related observable maliciousness.
EclecticIQ.Indicators.ObservablesList.observable_type String Indicator related observable type.
EclecticIQ.Indicators.ObservablesList.observable_value String Indicator related observable value.

eclecticiq-get-entity-by-id


Query EclecticIQ Intelligence Center for entity by its ID.

Base Command

eclecticiq-get-entity-by-id

Input

Argument Name Description Required
entity_id Entity ID in EclecticIQ format, for example: a86f8393-eff6-4b31-b203-f63152be5a43. Required

Context Output

Path Type Description
EclecticIQ.EntityById.confidence String Entity confidence.
EclecticIQ.EntityById.created_at Date Entity creation time.
EclecticIQ.EntityById.description String Entity description.
EclecticIQ.EntityById.entity_title String Entity title.
EclecticIQ.EntityById.entity_type String Entity type.
EclecticIQ.EntityById.impact String Entity impact.
EclecticIQ.EntityById.observables_list.maliciousness String Related observable maliciousness.
EclecticIQ.EntityById.observables_list.type String Related observable type.
EclecticIQ.EntityById.observables_list.value String Related observable value.
EclecticIQ.EntityById.relationships_list Unknown Entity relationships list.
EclecticIQ.EntityById.source_name String Entity source.
EclecticIQ.EntityById.tags_list Unknown Entity tags and taxonomies.

eclecticiq-request-get


Make HTTP GET request to EclecticIQ Intelligence Center.

Base Command

eclecticiq-request-get

Input

Argument Name Description Required
uri EclecticIQ URI excluding Intelligence Cetner address but including API version and params if needed. e.g. /private/status. Required

Context Output

Path Type Description
EclecticIQ.GET.ReplyBody Unknown GET reply body.
EclecticIQ.GET.ReplyStatus String GET reply status code.
EclecticIQ.GET.URI String GET reply requested URI.

Command example

!eclecticiq-request-get uri=/api/v2/datasets

Context Example

{
    "EclecticIQ": {
        "GET": {
            "ReplyBody": {
                "count": 100,
                "data": [...],
                "limit": 100,
                "offset": 0,
                "total_count": 113
            },
            "ReplyStatus": "200",
            "URI": "/api/v2/datasets"
        }
    }
}

Human Readable Output

EclecticIQ GET action to endpoint /api/v2/datasets exectued. Reply status: 200

eclecticiq-request-post


Make HTTP POST request to EclecticIQ Intelligence Center.

Base Command

eclecticiq-request-post

Input

Argument Name Description Required
uri EclecticIQ URI excluding Intelligence Cetner address but including API version and params if needed. Required
body JSON payload. Optional

Context Output

Path Type Description
EclecticIQ.POST.ReplyBody String POST reply body.
EclecticIQ.POST.ReplyStatus String POST reply status code.
EclecticIQ.POST.URI String POST reply requested URI.

Command example

!eclecticiq-request-post uri=/api/v2/datasets body=`{"data": {"workspaces": "1", "name": "test11112"}}

Context Example

{
    "EclecticIQ": {
        "POST": {
            "ReplyBody": {
                "data": {...}
            },
            "ReplyStatus": "201",
            "URI": "/api/v2/datasets"
        }
    }
}

Human Readable Output

EclecticIQ POST action to endpoint /api/v2/datasets exectued. Reply status: 201

eclecticiq-request-put


Make HTTP PUT request to EclecticIQ Intelligence Center.

Base Command

eclecticiq-request-put

Input

Argument Name Description Required
uri EclecticIQ URI excluding Intelligence Cetner address but including API version and params if needed. Required
body JSON payload. Optional

Context Output

Path Type Description
EclecticIQ.PUT.ReplyBody String PUT reply body.
EclecticIQ.PUT.ReplyStatus String PUT reply status code.
EclecticIQ.PUT.URI String PUT reply requested URI.

Command example

!eclecticiq-request-put uri=/api/v2/datasets body=`{"data": {"workspaces": "1", "name": "test11112"}}

Context Example

{
    "EclecticIQ": {
        "PUT": {
            "ReplyBody": {
                "data": {...}
            },
            "ReplyStatus": "200",
            "URI": "/api/v2/datasets"
        }
    }
}

Human Readable Output

EclecticIQ PUT action to endpoint /api/v2/datasets exectued. Reply status: 200

eclecticiq-request-patch


Make HTTP PATCH request to EclecticIQ Intelligence Center.

Base Command

eclecticiq-request-patch

Input

Argument Name Description Required
uri EclecticIQ URI excluding Intelligence Cetner address but including API version and params if needed. Required
body JSON payload. Optional

Context Output

Path Type Description
EclecticIQ.PATCH.ReplyBody String PATCH reply body.
EclecticIQ.PATCH.ReplyStatus String PATCH reply status code.
EclecticIQ.PATCH.URI String PATCH reply requested URI.

Command example

!eclecticiq-request-patch uri=/api/v2/datasets/1 body=`{"data": {"workspaces": "1", "name": "test11112"}}

Context Example

{
    "EclecticIQ": {
        "PATCH": {
            "ReplyBody": {
                "data": {...}
            },
            "ReplyStatus": "200",
            "URI": "/api/v2/datasets/1"
        }
    }
}

Human Readable Output

EclecticIQ PATCH action to endpoint /api/v2/datasets/1 exectued. Reply status: 200

eclecticiq-request-delete


Make HTTP DELETE request to EclecticIQ Intelligence Center.

Base Command

eclecticiq-request-delete

Input

Argument Name Description Required
uri EclecticIQ URI excluding Intelligence Cetner address but including API version and params if needed. Required

Context Output

Path Type Description
EclecticIQ.DELETE.ReplyStatus String DELETE reply status code.
EclecticIQ.DELETE.URI String DELETE reply requested URI.

eclecticiq-get-indicators


Get last block of Indicators from configured to fetch Outgoing feed.

Base Command

eclecticiq-get-indicators

Input

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

Context Output

There is no context output for this command.

Command example

!eclecticiq-get-indicators

Human Readable Output

Indicators collected from first block of feed:[{‘id’: ‘11’, ‘created_at’: ‘2023-06-26T15:23:19.737166+00:00’, ‘update_strategy’: ‘REPLACE’, ‘packaging_status’: ‘SUCCESS’, ‘name’: ‘splunk-test’}]

No entries.

Breaking changes from the previous version of this integration - EclecticIQ Intelligence Center v3

Integration rebuild with added functionality to fetch indicators from outgoing feeds and with many new commands. Integration is not compatible with EclecticIQ integration v2.

Configuration parameters

  • url — EclecticIQ Intelligence Center URL (e.g. https://eclecticiq-platform.local) (required)
  • eiq_token — API user token to authenticate in EclecticIQ Intelligence Center (required)
  • eiq_api_version — EclecticIQ Intelligence Center public API version (required)
  • ip_threshold — IP threshold. Minimum maliciousness confidence level to consider the IP address malicious: High, Medium, Low, Safe, Unknown
  • url_threshold — URL threshold. Minimum maliciousness confidence level to consider the URL malicious: High, Medium, Low, Safe, Unknown
  • file_threshold — File threshold. Minimum maliciousness confidence level to consider the file malicious: High, Medium, Low, Safe, Unknown
  • email_threshold — Email threshold. Minimum maliciousness confidence level to consider the email address malicious: High, Medium, Low, Safe, Unknown
  • domain_threshold — Domain threshold. Minimum maliciousness confidence level to consider the domain malicious: High, Medium, Low, Safe, Unknown
  • group_name — Group name in EclecticIQ Intelligence Center to use as entities source
  • sightings_auto_creation — Create sightings automatically in EclecticIQ Intelligence Center when reputation check command executed.
  • feed — Fetch indicators
  • feedReputation — Indicator Reputation
  • feedReliability — Source Reliability (required)
  • feedExpirationPolicy
  • feedExpirationInterval
  • feedFetchInterval — Feed Fetch Interval
  • feedBypassExclusionList — Bypass exclusion list
  • feedId — Feed IDs to fetch
  • feedIncremental
  • feedTags — Tags
  • tlp_color — Traffic Light Protocol Color
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings

Commands (15)

  • domain

    Gets the reputation of a domain observable.

  • eclecticiq-create-indicator

    Creates Indicator Entity in EclecticIQ IC.

  • eclecticiq-create-sighting

    Creates Sighting in EclecticIQ IC.

  • eclecticiq-get-entity

    Query EclecticIQ Intelligence Center for entities.

  • eclecticiq-get-entity-by-id

    Query EclecticIQ Intelligence Center for entity by its ID.

  • eclecticiq-get-indicators

    Get last block of Indicators from configured to fetch Outgoing feed.

  • eclecticiq-request-delete

    Make HTTP DELETE request to EclecticIQ Intelligence Center.

  • eclecticiq-request-get

    Make HTTP GET request to EclecticIQ Intelligence Center.

  • eclecticiq-request-patch

    Make HTTP PATCH request to EclecticIQ Intelligence Center.

  • eclecticiq-request-post

    Make HTTP POST request to EclecticIQ Intelligence Center.

  • eclecticiq-request-put

    Make HTTP PUT request to EclecticIQ Intelligence Center.

  • email

    Gets the reputation of an email address observable.

  • file

    Gets the reputation of a file hash observable.

  • ip

    Get reputation of IP address observable.

  • url

    Gets the reputation of a URL observable.

import json
import re
from datetime import datetime

import demistomock as demisto  # noqa: F401
import EclecticIQIntelligenceCenterv3
import pytest  # noqa: F401
from EclecticIQIntelligenceCenterv3 import (
    EclecticIQ_api,
    create_indicator,
    create_sighting,
    domain_command,
    email_command,
    extract_uuid_from_url,
    fetch_indicators,
    file_command,
    format_ts,
    format_ts_human,
    get_entity,
    get_entity_by_id,
    get_indicators,
    ip_command,
    observable_id_from_url,
    parse_reputation_results,
    prepare_entity_observables,
    request_delete,
    request_get,
    request_patch,
    request_post,
    request_put,
    taxonomie_id_from_url,
    url_command,
)

SERVER = "https://test.eclecticiq.com"
EIQ_USER = "test@test.test"
PASSWORD = "123"
EIQ_FEED_IDs = "12"
USE_SSL = "false"
API_VERSION = "v2"

EclecticIQIntelligenceCenterv3.DOMAIN_THRESHOLD = "low"
EclecticIQIntelligenceCenterv3.IP_THRESHOLD = "low"
EclecticIQIntelligenceCenterv3.URL_THRESHOLD = "low"
EclecticIQIntelligenceCenterv3.FILE_THRESHOLD = "low"
EclecticIQIntelligenceCenterv3.EMAIL_THRESHOLD = "low"


def platform_auth_mock_response(*args, **kwargs):
    return_value = "test OK"
    return return_value


def test_get_outh_token_success(requests_mock):
    requests_mock.get("https://test.eclecticiq.com/private", json={"message": "Auth"}, status_code=201)

    client = EclecticIQ_api(
        baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL, init_cred_test=False
    )

    try:
        client.get_outh_token()
    except Exception as excinfo:
        pytest.fail(f"Unexpected exception raised: {excinfo}")


def test_send_api_request_good(requests_mock):
    requests_mock.get("https://test.eclecticiq.com/test", json={"message": "ok"}, status_code=201)

    client = EclecticIQ_api(
        baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL, init_cred_test=False
    )

    try:
        client.send_api_request(method="get", path="/test")
    except Exception as excinfo:
        pytest.fail(f"Unexpected exception raised: {excinfo}")


def entity_create_response(*args, **kwargs):
    return_value = "123-123-123"
    return return_value


def test_entity(mocker):
    """Test for sighting."""
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.create_entity", entity_create_response)
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)
    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    response = client.create_entity(
        observable_dict={
            "classification": "bad",
            "confidence": "medium",
            "observable_type": "ipv4",
            "observable_value": "1.1.1.1",
        },
        source_group_name="test",
        entity_title="Sighting",
        entity_description="description",
        entity_confidence="medium",
        entity_tags=[],
        entity_impact_value="medium",
    )

    assert isinstance(response, str)


def sighting_mock_response(*args, **kwargs):
    return_value = {
        "data": {
            "data": {
                "confidence": "medium",
                "description": "test_desc",
                "type": " EclecticIQ-sighting",
                "timestamp": "2022-03-10T05:37:42Z",
                "title": "EIQ-title",
                "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"},
        }
    }
    return return_value


def test_create_sighting(mocker):
    """Test for sighting."""
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.create_entity", entity_create_response)
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)
    mocker.patch.object(
        demisto,
        "args",
        return_value={
            "observable_type": "ipv4",
            "observable_value": "1.1.1.1",
            "sighting_title": "EIQ-title",
            "sighting_description": "sighting",
            "observable_maliciousness": "Malicious (Medium confidence)",
        },
    )

    client = EclecticIQ_api(
        baseurl=SERVER,
        eiq_api_version=API_VERSION,
        username="",
        password=PASSWORD,
        verify_ssl=USE_SSL,
    )

    response = create_sighting(client)

    assert isinstance(response.raw_response, dict)
    assert response.outputs_prefix == "EclecticIQ.Sightings"
    assert response.raw_response["sighting_details"]["observable_maliciousness"] == "Malicious (Medium confidence)"
    assert response.outputs["SightingId"] == "123-123-123"
    assert response.raw_response["sighting_details"]["sighting_title"] == sighting_mock_response()["data"]["data"]["title"]


def test_create_indicator(mocker):
    """Test for sighting."""
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.create_entity", entity_create_response)
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)
    mocker.patch.object(
        demisto,
        "args",
        return_value={
            "observable_type": "ipv4",
            "observable_value": "1.1.1.1",
            "indicator_title": "EIQ-title",
            "indicator_description": "indicator",
            "observable_maliciousness": "Malicious (Medium confidence)",
        },
    )

    client = EclecticIQ_api(
        baseurl=SERVER,
        eiq_api_version=API_VERSION,
        username="",
        password=PASSWORD,
        verify_ssl=USE_SSL,
    )

    response = create_indicator(client)

    assert isinstance(response.raw_response, dict)
    assert response.outputs_prefix == "EclecticIQ.Indicators"
    assert response.raw_response["indicator_title"] == "EIQ-title"
    assert response.outputs["IndicatorId"] == "123-123-123"


def test_prepare_entity_observables(mocker):
    response = prepare_entity_observables(
        "1.1.1.1", "ipv4", "Malicious (High confidence)", '[{"type":"ipv4", "value": "2.2.2.2", "maliciousness": "medium"}]'
    )
    assert isinstance(response, list)
    assert isinstance(response[0], dict)
    assert response[1]["observable_classification"] == "bad"


def observable_mock_response_domain(*args, **kwargs):
    result = {
        "created": "01-01-1900",
        "last_updated": "01-01-1910",
        "maliciousness": "low",
        "type": "domain",
        "value": "test.com",
        "id": "123",
        "source_name": "testing group",
        "platform_link": "eclecticiq.test/main/intel/all/browse/observable?tab=overview&id=",
    }

    return result


def observable_mock_response_ip(*args, **kwargs):
    result = {
        "created": "01-01-1900",
        "last_updated": "01-01-1910",
        "maliciousness": "medium",
        "type": "ip",
        "value": "1.1.1.1",
        "id": "123",
        "source_name": "testing group",
        "platform_link": "eclecticiq.test/main/intel/all/browse/observable?tab=overview&id=",
    }

    return result


def observable_mock_response_email(*args, **kwargs):
    result = {
        "created": "01-01-1900",
        "last_updated": "01-01-1910",
        "maliciousness": "medium",
        "type": "email",
        "value": "test@test.test",
        "id": "123",
        "source_name": "testing group",
        "platform_link": "eclecticiq.test/main/intel/all/browse/observable?tab=overview&id=",
    }

    return result


def observable_mock_response_url(*args, **kwargs):
    result = {
        "created": "01-01-1900",
        "last_updated": "01-01-1910",
        "maliciousness": "medium",
        "type": "url",
        "value": "http://test.test",
        "id": "123",
        "source_name": "testing group",
        "platform_link": "eclecticiq.test/main/intel/all/browse/observable?tab=overview&id=",
    }

    return result


def observable_mock_response_file(*args, **kwargs):
    result = {
        "created": "01-01-1900",
        "last_updated": "01-01-1910",
        "maliciousness": "medium",
        "type": "file",
        "value": "e489ed8f638df3faa75ef9b76fa68ef9",
        "id": "123",
        "source_name": "testing group",
        "platform_link": "eclecticiq.test/main/intel/all/browse/observable?tab=overview&id=",
    }

    return result


def test_parse_reputation_results(mocker):
    response_domain = parse_reputation_results(observable_mock_response_domain(), "test.com", "domain", "low", "Domain")
    response_ip = parse_reputation_results(observable_mock_response_ip(), "1.1.1.1", "ip", "low", "ipv4")

    assert isinstance(response_domain, list)
    assert response_domain[0].raw_response["maliciousness"] == "low"
    assert response_domain[0].outputs_prefix == "EclecticIQ.Domain"
    assert isinstance(response_ip, list)
    assert response_ip[0].raw_response["maliciousness"] == "medium"
    assert response_ip[0].outputs_prefix == "EclecticIQ.IP"


def test_parse_reputation_results_empty_reply(mocker):
    response = parse_reputation_results(None, "test.com", "domain", "low", "Domain")
    assert response[0].raw_response["result"] == "Observable not found in EclecticIQ IC."


def test_domain_command(mocker):
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.lookup_observable", observable_mock_response_domain)
    mocker.patch.object(demisto, "args", return_value={"domain": "test.com"})

    client = EclecticIQ_api(
        baseurl=SERVER,
        eiq_api_version=API_VERSION,
        username="",
        password=PASSWORD,
        verify_ssl=USE_SSL,
    )

    response = domain_command(client)

    assert response[0].raw_response["maliciousness"] == "low"
    assert response[0].outputs_prefix == "EclecticIQ.Domain"


def test_url_command(mocker):
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.lookup_observable", observable_mock_response_url)
    mocker.patch.object(demisto, "args", return_value={"url": "http://test.test"})

    client = EclecticIQ_api(
        baseurl=SERVER,
        eiq_api_version=API_VERSION,
        username="",
        password=PASSWORD,
        verify_ssl=USE_SSL,
    )

    response = url_command(client)

    assert response[0].raw_response["maliciousness"] == "medium"
    assert response[0].outputs_prefix == "EclecticIQ.URL"


def test_file_command(mocker):
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.lookup_observable", observable_mock_response_file)
    mocker.patch.object(demisto, "args", return_value={"file": "e489ed8f638df3faa75ef9b76fa68ef9"})

    client = EclecticIQ_api(
        baseurl=SERVER,
        eiq_api_version=API_VERSION,
        username="",
        password=PASSWORD,
        verify_ssl=USE_SSL,
    )

    response = file_command(client)

    assert response[0].raw_response["maliciousness"] == "medium"
    assert response[0].outputs_prefix == "EclecticIQ.File"


def test_email_command(mocker):
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.lookup_observable", observable_mock_response_email)
    mocker.patch.object(demisto, "args", return_value={"email": "test@test.test"})

    client = EclecticIQ_api(
        baseurl=SERVER,
        eiq_api_version=API_VERSION,
        username="",
        password=PASSWORD,
        verify_ssl=USE_SSL,
    )

    response = email_command(client)

    assert response[0].raw_response["maliciousness"] == "medium"
    assert response[0].outputs_prefix == "EclecticIQ.Email"


def test_ip_command(mocker):
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.lookup_observable", observable_mock_response_ip)
    mocker.patch.object(demisto, "args", return_value={"ip": "1.1.1.1"})

    client = EclecticIQ_api(
        baseurl=SERVER,
        eiq_api_version=API_VERSION,
        username="",
        password=PASSWORD,
        verify_ssl=USE_SSL,
    )

    response = ip_command(client)

    assert response[0].raw_response["maliciousness"] == "medium"
    assert response[0].outputs_prefix == "EclecticIQ.IP"


def test_get_source_group_uid(mocker):
    mock_response = mocker.Mock()
    mock_response.json.return_value = {
        "data": [
            {
                "created_at": "2023-05-08T11:23:13.870452+00:00",
                "description": "",
                "id": 1,
                "last_updated_at": "2023-05-08T11:23:13.870452+00:00",
                "name": "Testing Group",
                "source": ["https://ic-playground.eclecticiq.com/api/v2/sources/95c654c9-e1de-4639-9d17-b12a883164b6"],
                "users": [
                    "https://ic-playground.eclecticiq.com/api/v2/users/48?role=member",
                    "https://ic-playground.eclecticiq.com/api/v2/users/63?role=member",
                    "https://ic-playground.eclecticiq.com/api/v2/users/9?role=admin",
                ],
            }
        ]
    }

    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = client.get_source_group_uid("testing_group")

    assert isinstance(response, list)
    assert response[0] == "https://ic-playground.eclecticiq.com/api/v2/sources/95c654c9-e1de-4639-9d17-b12a883164b6"


def test_get_source_group_order_id(mocker):
    mock_response = mocker.Mock()
    mock_response.json.return_value = {"data": [{"id": "order_id"}]}
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = client.get_source_group_order_id("example_group")

    assert response == "order_id"
    assert isinstance(response, str)


def test_get_enrichers_list(mocker):
    mock_response = mocker.Mock()
    mock_response.json.return_value = {"data": ["enricher1", "enricher2"]}
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = client.get_enrichers_list()

    assert response == ["enricher1", "enricher2"]


def test_extract_uuid_from_url():
    url = "https://example.com/123-def456-ghi789-jkl012-ghi789-jkl0"
    assert extract_uuid_from_url(url) == "123-def456-ghi789-jkl012-ghi789-jkl0"


def test_extract_uuid_from_url_empty():
    invalid_url = "https://example.com/no-uuid-here"
    assert extract_uuid_from_url(invalid_url) is None


def test_observable_id_from_url():
    url = "https://example.com/observables/42"
    assert observable_id_from_url(url) == "42"

    invalid_url = "https://example.com/no-id-here"
    assert observable_id_from_url(invalid_url) is None


def test_taxonomie_id_from_url():
    url = "https://example.com/taxonomies/123"
    assert taxonomie_id_from_url(url) == "123"

    invalid_url = "https://example.com/no-id-here"
    assert taxonomie_id_from_url(invalid_url) is None


def test_format_ts():
    dt = datetime(2024, 2, 6, 12, 34, 56)
    expected_result = "2024-02-06T12:34:56Z"
    assert format_ts(dt) == expected_result


def test_format_ts_human():
    dt = datetime(2024, 2, 6, 12, 34, 56)
    expected_result = "2024-02-06T12:34:56Z"
    assert format_ts_human(dt) == expected_result


def test_create_outgoing_feed(mocker):
    mock_response = mocker.Mock()
    mock_response.json.return_value = {"data": "123321"}
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "get_source_group_order_id", return_value="123-123-123")
    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = client.create_outgoing_feed("CSV Observables", "8", "New Feed", "http download", "REPLACE", "testing Group")

    assert response == "123321"


def test_lookup_observable(mocker):
    mock_response = mocker.Mock()
    mock_response.text = json.dumps(
        {
            "count": 1,
            "data": [
                {
                    "created_at": "2023-05-24T16:52:29.715750+00:00",
                    "entities": [
                        "https://ic-playground.eclecticiq.com/api/v2/entities/4de74eae-68fd-427b-808c-45dc7fb8c650",
                        "https://ic-playground.eclecticiq.com/api/v2/entities/dfd0d6ae-7dd6-435f-ab73-66088b46ea7c",
                    ],
                    "id": 2,
                    "last_updated_at": "2024-01-29T07:42:07.059329+00:00",
                    "meta": {"maliciousness": "low"},
                    "sources": [
                        "https://ic-playground.eclecticiq.com/api/v2/sources/5601ee2a-f85a-4b14-a626-00052600b313",
                        "https://ic-playground.eclecticiq.com/api/v2/sources/0ce29afd-bdac-47bd-9f11-f6a4f479bc1c",
                    ],
                    "type": "ipv4",
                    "value": "1.1.1.1",
                }
            ],
            "limit": 100,
            "offset": 0,
            "total_count": 1,
        }
    )

    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "get_group_name", return_value={"name": "Testing", "type": "user"})
    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = client.lookup_observable("1.1.1.1", "ipv4")

    assert response["type"] == "ipv4"
    assert response["source_name"] == "user: Testing; user: Testing; "


def test_get_feed_content_blocks(mocker):
    mock_response = mocker.Mock()
    mock_response.json.return_value = {
        "count": 2,
        "data": {
            "content_blocks": "urn:eclecticiq.com:csv-extracts:1.0",
            "created_at": "2023-06-20T18:06:08.632279",
            "delivery_status": "null",
            "filename": "qradarfeedtest2-5d6c9551-1.csv",
            "id": 11,
            "items_count": 25,
            "meta": {"destination": "a80e31f1-3123-4f96-a15c-944e5f72f302"},
            "outgoing_feed": "https://ic-playground.eclecticiq.com/api/v2/outgoing-feeds/10",
            "run_id": "5d6c9551-9ad4-4c88-9936-01620a2fe5e7",
            "size": 12991,
        },
        "limit": 100,
        "offset": 0,
        "total_count": 2,
    }

    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    feed_to_request = {
        "packaging_status": "SUCCESS",
        "update_strategy": "REPLACE",
        "id": "10",
        "created_at": "2023-06-20T18:06:08.632279",
    }
    feed_last_run = {"last_ingested": "2023-06-20T18:06:08.632279", "created_at": "2023-06-20T18:06:08.632279"}

    response = client.get_feed_content_blocks(feed_to_request, feed_last_run)

    assert response == "urn:eclecticiq.com:csv-extracts:1.0"
    assert isinstance(response, str)


def test_get_feed_content_blocks_append(mocker):
    mock_response = mocker.Mock()
    mock_response.json.return_value = {
        "count": 2,
        "data": {
            "content_blocks": "urn:eclecticiq.com:csv-extracts:1.0",
            "created_at": "2023-06-20T18:06:08.632279",
            "delivery_status": "null",
            "filename": "qradarfeedtest2-5d6c9551-1.csv",
            "id": 11,
            "items_count": 25,
            "meta": {"destination": "a80e31f1-3123-4f96-a15c-944e5f72f302"},
            "outgoing_feed": "https://ic-playground.eclecticiq.com/api/v2/outgoing-feeds/10",
            "run_id": "5d6c9551-9ad4-4c88-9936-01620a2fe5e7",
            "size": 12991,
        },
        "limit": 100,
        "offset": 0,
        "total_count": 2,
    }

    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    feed_to_request = {
        "packaging_status": "SUCCESS",
        "update_strategy": "APPEND",
        "id": "10",
        "created_at": "2023-06-20T18:06:08.632279",
    }
    feed_last_run = {"last_ingested": "2023-06-20T18:06:08.632279", "created_at": "2023-06-20T18:06:08.632271"}

    response = client.get_feed_content_blocks(feed_to_request, feed_last_run)

    assert response == "urn:eclecticiq.com:csv-extracts:1.0"
    assert isinstance(response, str)


def test_request_get(mocker):
    mock_response = mocker.Mock()
    mock_response.json.return_value = {"status": "OK"}
    mock_response.status_code = "200"
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)
    mocker.patch.object(demisto, "args", return_value={"uri": "test"})

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = request_get(client)

    assert response.outputs["ReplyStatus"] == "200"
    assert response.outputs_prefix == "EclecticIQ.GET"


def test_request_post(mocker):
    mock_response = mocker.Mock()
    mock_response.json.return_value = {"status": "OK"}
    mock_response.status_code = "200"
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)
    mocker.patch.object(demisto, "args", return_value={"uri": "test"})

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = request_post(client)

    assert response.outputs["ReplyStatus"] == "200"
    assert response.outputs_prefix == "EclecticIQ.POST"


def test_request_put(mocker):
    mock_response = mocker.Mock()
    mock_response.json.return_value = {"status": "OK"}
    mock_response.status_code = "200"
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)
    mocker.patch.object(demisto, "args", return_value={"uri": "test"})

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = request_put(client)

    assert response.outputs["ReplyStatus"] == "200"
    assert response.outputs_prefix == "EclecticIQ.PUT"


def test_request_patch(mocker):
    mock_response = mocker.Mock()
    mock_response.json.return_value = {"status": "OK"}
    mock_response.status_code = "200"
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)
    mocker.patch.object(demisto, "args", return_value={"uri": "test"})

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = request_patch(client)

    assert response.outputs["ReplyStatus"] == "200"
    assert response.outputs_prefix == "EclecticIQ.PATCH"


def test_request_delete(mocker):
    mock_response = mocker.Mock()
    mock_response.json.return_value = {"status": "OK"}
    mock_response.status_code = "200"
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)
    mocker.patch.object(demisto, "args", return_value={"uri": "test"})

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = request_delete(client)

    assert response.outputs["ReplyStatus"] == "200"
    assert response.outputs_prefix == "EclecticIQ.DELETE"


def test_get_feed_info(mocker):
    mock_response = mocker.Mock()
    mock_response.json.return_value = {
        "data": {
            "content_type": "urn:eclecticiq.com:csv-extracts:1.0",
            "created_at": "2023-06-20T18:05:06.625499+00:00",
            "id": "10",
            "is_active": True,
            "last_triggered_at": "2023-11-15T17:52:24.733800+00:00",
            "last_updated_at": "2023-07-13T10:29:52.787017+00:00",
            "name": "qradarfeedtest2",
            "packaging_last_run_at": "2023-11-15T17:52:24.733800+00:00",
            "packaging_status": "SUCCESS",
            "transport_type": "eiq.outgoing-transports.http-download",
            "update_strategy": "DIFF",
            "update_task": "https://ic-playground.eclecticiq.com/api/v2/tasks/195",
        }
    }

    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = client.get_feed_info("10")

    assert response[0]["id"] == "10"
    assert isinstance(response[0], dict)


def test_eiq_get_entity_by_id(mocker):
    mock_response = mocker.Mock()
    mock_response.text = json.dumps(
        {
            "data": {
                "attachments": [],
                "created_at": "2024-02-06T15:36:35.251514+00:00",
                "data": {
                    "id": "indicator-2c082ad0-cd32-47c2-8ff1-7c6adde759d4",
                    "timestamp": "2024-02-06T15:36:35.251514+00:00",
                    "title": "test IOC",
                    "type": "indicator",
                },
                "datasets": [],
                "id": "2c082ad0-cd32-47c2-8ff1-7c6adde759d4",
                "incoming_feed": "null",
                "last_updated_at": "2024-02-06T15:36:36.805980+00:00",
                "meta": {
                    "attacks": [],
                    "estimated_observed_time": "2024-02-06T15:36:35.251514+00:00",
                    "estimated_threat_start_time": "2024-02-06T15:36:35.251514+00:00",
                    "half_life": "30",
                    "source_reliability": "C",
                    "taxonomies": [],
                    "title": "parth 6 feb test 15",
                    "tlp_color": "null",
                },
                "observables": ["https://ic-playground.eclecticiq.com/api/v2/observables/651905"],
                "outgoing_feeds": [],
                "relevancy": "1",
                "sources": ["https://ic-playground.eclecticiq.com/api/v2/sources/2411da8d-9b07-4507-8e9e-ed64abd179c8"],
            }
        }
    )

    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_taxonomy_dict", [])

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    client.taxonomie_dict = ["1", "2"]

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = client.get_entity_by_id(
        "2c082ad0-cd32-47c2-8ff1-7c6adde759d4", observables_lookup=False, relationships_lookup=False
    )

    assert response["entity_title"] == "test IOC"
    assert isinstance(response, dict)


def test_eiq_get_enrichers_list(mocker):
    mock_response = mocker.Mock()
    mock_response.json.return_value = {"data": [{"name": "enricher1", "is_active": True}]}

    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = client.get_enrichers_list()

    assert isinstance(response, list)
    assert len(response) == 1


def test_eiq_get_status(mocker):
    mock_response = mocker.Mock()
    mock_response.json.return_value = {"data": {"status": "GREEN"}}

    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = client.get_status()

    assert isinstance(response, dict)
    assert response["status"] == "GREEN"


def test_eiq_get_status_red_component(mocker):
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    service_return = {
        "health": "GREEN",
        "celery_states": [{"health": "RED", "component": "celery"}],
        "service_states": [{"health": "RED", "component": "db"}],
    }
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_status", return_value=service_return)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    response = client.get_status_red_component()

    assert isinstance(response, dict)
    assert response["components"][0]["health"] == "RED"


def test_eiq_get_active_enrichers_list(mocker):
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)
    mock_result = {"name": "enricher1", "is_active": "True"}
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_enrichers_list", return_result=mock_result)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    response = client.get_active_enrichers_list()

    assert isinstance(response, list)


def test_lookup_observable_many(mocker):
    mock_response = mocker.Mock()
    mock_response.text = json.dumps(
        {
            "count": 2,
            "data": [
                {
                    "created_at": "2023-05-24T16:52:29.715750+00:00",
                    "entities": [
                        "https://ic-playground.eclecticiq.com/api/v2/entities/4de74eae-68fd-427b-808c-45dc7fb8c650",
                        "https://ic-playground.eclecticiq.com/api/v2/entities/dfd0d6ae-7dd6-435f-ab73-66088b46ea7c",
                    ],
                    "id": 2,
                    "last_updated_at": "2024-01-29T07:42:07.059329+00:00",
                    "meta": {"maliciousness": "low"},
                    "sources": [
                        "https://ic-playground.eclecticiq.com/api/v2/sources/5601ee2a-f85a-4b14-a626-00052600b313",
                        "https://ic-playground.eclecticiq.com/api/v2/sources/0ce29afd-bdac-47bd-9f11-f6a4f479bc1c",
                    ],
                    "type": "ipv4",
                    "value": "1.1.1.1",
                }
            ],
            "limit": 100,
            "offset": 0,
            "total_count": 1,
        }
    )

    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "get_group_name", return_value={"name": "Testing", "type": "user"})
    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = client.lookup_observable("1.1.1.1", "ipv4")

    assert response["type"] == "ipv4"
    assert response["source_name"] == "user: Testing; user: Testing; "


def test_search_entity(mocker):
    mock_response = mocker.Mock()
    mock_response.text = json.dumps({"data": [{"title": "test entity", "id": "1"}]})

    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "get_entity_by_id", return_value={"title": "test entity", "id": "1"})
    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = client.search_entity('"test entity"', "Indicator")

    assert response[0]["title"] == "test entity"
    assert isinstance(response, list)


def test_eiq_enrich_observable(mocker):
    mock_response = mocker.Mock()
    mock_response.json.return_value = {"data": {"status": "done"}}

    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = client.enrich_observable(enricher_id=1, observable_id=2)

    assert isinstance(response, dict)
    assert response["status"] == "done"


def test_eiq_create_incoming_feed(mocker):
    mock_response = mocker.Mock()
    mock_response.text = json.dumps({"data": {"status": "done"}})

    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = client.create_incoming_feed(
        feed_title="new_feed", content_type="CSV Observable", password="secret", username="user"
    )

    assert isinstance(response, dict)
    assert response["status"] == "done"


def test_eiq_download_incoming_feed(mocker):
    mock_response = mocker.Mock()
    mock_response.text = json.dumps({"data": {"status": "done"}})

    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = client.download_incoming_feed(feed_id=1, feed_provider_task=2)

    assert isinstance(response, dict)
    assert response["status"] == "done"


def test_eiq_get_incoming_feed_blobs_pending(mocker):
    mock_response = mocker.Mock()
    mock_response.text = json.dumps({"data": [{"id": 1, "n_blobs_pending": ["123-123-123", "123-123-124", "123-123-125"]}]})

    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = client.get_incoming_feed_blobs_pending(feed_id=1)

    assert isinstance(response, list)
    assert len(response) == 3


def test_eiq_get_full_feed_info(mocker):
    mock_response = mocker.Mock()
    mock_response.text = json.dumps(
        {"data": [{"id": 1, "blobs": ["123-123-123", "123-123-124", "123-123-125"], "content_type": "CSV"}]}
    )

    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = client.get_full_feed_info(feed_id="*")

    assert isinstance(response, list)
    assert len(response) == 1
    assert response[0]["content_type"] == "CSV"


def test_eiq_get_incoming_feed_full_info(mocker):
    mock_response = mocker.Mock()
    mock_response.text = json.dumps(
        {"data": [{"id": 1, "blobs": ["123-123-123", "123-123-124", "123-123-125"], "content_type": "CSV"}]}
    )

    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = client.get_incoming_feed_full_info(feed_id="*")

    assert isinstance(response, list)
    assert len(response) == 1
    assert response[0]["content_type"] == "CSV"


def test_eiq_download_block_list(mocker):
    mock_response = mocker.Mock()
    mock_response.text = json.dumps({"data": "dummy_data"})

    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = client.download_block_list("feed_123_block_432.csv")

    assert isinstance(response, str)
    assert json.loads(response)["data"] == "dummy_data"


def test_eiq_get_observable_by_id(mocker):
    mock_response = mocker.Mock()
    mock_response.text = json.dumps({"data": "dummy_data"})

    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = client.get_observable_by_id(id=123)

    assert isinstance(response, dict)
    assert response["data"] == "dummy_data"


def test_eiq_get_all_observables(mocker):
    mock_response = mocker.Mock()
    mock_response.text = json.dumps({"data": "dummy_data"})

    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = client.get_all_observables()

    assert isinstance(response, dict)
    assert response["data"] == "dummy_data"


def test_eiq_get_taxonomy_dict(mocker):
    mock_response = mocker.Mock()
    mock_response.text = json.dumps({"data": [{"id": "1", "name": "Confidence High"}, {"id": "2", "name": "Confidence Low"}]})

    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", return_value=mock_response)

    response = client.get_taxonomy_dict()

    assert isinstance(response, dict)
    assert response["2"] == "Confidence Low"


def relationship_payload():
    payload = {
        "data": [
            {
                "created_at": "2024-02-08T17:02:47.539388+00:00",
                "data": {
                    "key": "related-to",
                    "source": "https://ic-playground.eclecticiq.com/api/v2/entities/379e06ed-d06f-425e-ab8d-79b157c18e48",
                    "target": "https://ic-playground.eclecticiq.com/api/v2/entities/379e8ffd-8c0c-4d1e-b17f-a29c05c49bfd",
                    "timestamp": "2024-02-08T17:02:47.539388+00:00",
                },
                "id": "379ef6bc-02ac-444d-a30a-18845c583cef",
                "last_updated_at": "2024-02-08T17:02:47.544644+00:00",
                "meta": {
                    "source_reliability": "B",
                    "stix_id": "{http://not-yet-configured.example.org/}relation-379ef6bc-02ac-444d-a30a-18845c583cef",
                    "tlp_color": "null",
                },
                "sources": ["https://ic-playground.eclecticiq.com/api/v2/sources/0a80459d-282d-40c1-8cff-e2980535283c"],
                "strict_stix_1": False,
                "strict_stix_2": True,
            }
        ]
    }

    return payload


def test_eiq_get_entity_realtionships(mocker):
    mock_response_1 = mocker.Mock()
    mock_response_2 = mocker.Mock()
    mock_response_1.text = json.dumps(relationship_payload())
    mock_response_2.text = json.dumps(
        {"data": {"data": {"type": "indicator", "title": "New Entity"}, "id": "123-12-12", "observables": []}}
    )

    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)

    client = EclecticIQ_api(baseurl=SERVER, eiq_api_version=API_VERSION, username="", password=PASSWORD, verify_ssl=USE_SSL)

    mocker.patch.object(client, "send_api_request", side_effect=[mock_response_1, mock_response_2])

    response = client.get_entity_realtionships(source_id="379ef6bc-02ac-444d-a30a-18845c583cef")

    assert isinstance(response, list)
    assert response[0]["entity_id"] == "123-12-12"
    assert response[0]["observables_count"] == 0


def entity_mock_response(*args, **kwargs):
    entity = [
        {
            "title": "test entity",
            "type": "indicator",
            "observables_list": [{"value": "1.1.1.1", "type": "ipv4"}],
            "relationships_list": [],
        }
    ]
    return entity


def test_get_entity(mocker):
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.search_entity", entity_mock_response)
    mocker.patch.object(demisto, "args", return_value={"entity_title": "test entity", "entity_type": "all"})

    client = EclecticIQ_api(
        baseurl=SERVER,
        eiq_api_version=API_VERSION,
        username="",
        password=PASSWORD,
        verify_ssl=USE_SSL,
    )

    response = get_entity(client)

    assert response.raw_response[0]["title"] == "test entity"
    assert len(response.raw_response[0]["observables_list"]) == 1


def test_get_entity_by_id(mocker):
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_entity_by_id", entity_mock_response)
    mocker.patch.object(demisto, "args", return_value={"entity_id": "123-123-123"})

    client = EclecticIQ_api(
        baseurl=SERVER,
        eiq_api_version=API_VERSION,
        username="",
        password=PASSWORD,
        verify_ssl=USE_SSL,
    )

    response = get_entity_by_id(client)

    assert response.raw_response[0]["title"] == "test entity"
    assert len(response.raw_response[0]["observables_list"]) == 1


def csv_block_mock_response(*args, **kwargs):
    csv = """value,type,entity.id,entity.title,entity.type,source.names,entity.description,meta.confidence
1.1.1.1,ipv4,123-123-123,"test Entity",test_indicator,test_source,"test description",medium
1.1.1.2,ipv4,1234-1234-1234,"test Entity2",test_indicator2,test_source2,"test description2",medium"""
    return csv


def feed_info_mock_response(*args, **kwargs):
    feedinfo = [{"id": "1", "update_strategy": "REPLACE", "created_at": "01-01-1900", "name": "test feed"}]
    return feedinfo


def feed_cb_mock_response(*args, **kwargs):
    feedcb = ["block1"]
    return feedcb


def test_get_indicators(mocker):
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_feed_info", feed_info_mock_response)
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_feed_content_blocks", feed_cb_mock_response)
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.download_block_list", csv_block_mock_response)
    mocker.patch.object(demisto, "params", return_value={"feedId": "1"})

    client = EclecticIQ_api(
        baseurl=SERVER,
        eiq_api_version=API_VERSION,
        username="",
        password=PASSWORD,
        verify_ssl=USE_SSL,
    )
    response = get_indicators(client)

    assert isinstance(response.readable_output, str)
    assert bool(re.search(r"| test description | 123-123-123 | test Entity | test_indicator |", response.readable_output))


def test_fetch_indicators(mocker):
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_outh_token", platform_auth_mock_response)
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_feed_info", feed_info_mock_response)
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.get_feed_content_blocks", feed_cb_mock_response)
    mocker.patch("EclecticIQIntelligenceCenterv3.EclecticIQ_api.download_block_list", csv_block_mock_response)
    mocker.patch.object(demisto, "params", return_value={"feedId": "1"})
    mocker.patch.object(demisto, "getLastRun", return_value={})

    client = EclecticIQ_api(
        baseurl=SERVER,
        eiq_api_version=API_VERSION,
        username="",
        password=PASSWORD,
        verify_ssl=USE_SSL,
    )

    response = fetch_indicators(client)

    assert isinstance(response, list)
    assert len(response) == 2
    assert response[0]["rawJSON"]["entity.id"] == "123-123-123"