URLhaus

URLhaus has the goal of sharing malicious URLs that are being used for malware distribution.

Data Enrichment & Threat Intelligence · URLhaus

Details

IDURLhaus
ProviderOpen Source
CategoryData Enrichment & Threat Intelligence
From Version5.0.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM

README

URLhaus leverages abuse.ch and shares malicious URLs that are being used for malware distribution.
This integration was integrated and tested with version v1 of URLhaus.

Configure URLhaus in Cortex

Parameter Description Required
Server URL (e.g. https://192.168.0.1)   False
Auth Key Auth Key for authentication with abuse.ch True
Source Reliability Reliability of the source providing the intelligence data. True
Trust any certificate (not secure)   False
Use system proxy settings   False
Create relationships   False
Maximum number of relationships to fetch per indicator Maximal value is 1000. False
Blacklists appearances threshold   False
Compromised (is malicious)   False
Number of retries Determines how many times a command should be retried before raising an error. False

Create a required Auth Key for abuse.ch

Note: If you already have a profile, you can skip steps 1 and 2.

  1. Sign up for an abuse.ch account. You can do this easily by using an existing account that you may already have on X, LinkedIn, Google or Github. Just log in with the authentication provider of your choice here: https://auth.abuse.ch/

  2. Once you are authenticated on abuse.ch, ensure that you connect at least one additional authentication provider. This will ensure that you have access to abuse.ch platforms, even if one of the authentication providers you use shuts down (yes, it happened with Twitter!)

  3. Ensure that you hit the “Save profile” button. In the “Optional” section, you can now generate an “Auth-Key”. This is your personal Auth-Key that you can now use in the integration.

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.

url


Retrieves URL information from URLhaus.

Notice: Submitting indicators using this command might make the indicator data publicly available. See the vendor’s documentation for more details.

Base Command

url

Input

Argument Name Description Required
url A comma-separated list of URLs to query. Required

Context Output

Path Type Description
URL.Data string The URL.
URL.Malicious.Vendor string Vendor that reported the URL as malicious.
URL.Malicious.Description string Description of the malicious URL.
URL.Tags string A list of tags associated with the queried malware URL.
URL.Relationships.EntityA String The source of the relationship.
URL.Relationships.EntityB String The destination of the relationship.
URL.Relationships.Relationship String The name of the relationship.
URL.Relationships.EntityAType String The type of the source of the relationship.
URL.Relationships.EntityBType String The type of the destination of the relationship.
URLhaus.URL.ID String Unique identifier of the URLhaus database entry.
URLhaus.URL.Status String The current status of the URL.
URLhaus.URL.Host String The extracted host of the malware URL (IP address or domain name/FQDN).
URLhaus.URL.DateAdded date Date the URL was added to URLhaus.
URLhaus.URL.Threat String The threat corresponding to this malware URL.
URLhaus.URL.Blacklist.Name String Name of the block list.
URLhaus.URL.Tags String A list of tags associated with the queried malware URL.
URLhaus.URL.Payload.Name String Payload file name.
URLhaus.URL.Payload.Type String Payload file type.
URLhaus.URL.Payload.MD5 String MD5 hash of the HTTP response body (payload).
URLhaus.URL.Payload.VT.Result Number VirusTotal results for the payload.
DBotScore.Indicator String The indicator that was tested.
DBotScore.Type String The indicator type.
DBotScore.Vendor String The vendor used to calculate the score.
DBotScore.Score Number The actual score.
DBotScore.Reliability String Reliability of the source providing the intelligence data.
URLhaus.URL.Blacklist.Status String Status of the URL in the block list.
URLhaus.URL.Payload.VT.Link String Link to the VirusTotal report.

Command example

!url using-brand=URLhaus url=http://example.com/anklet/WQG1/?i=1

Context Example

{
    "DBotScore": {
        "Indicator": "http://example.com/anklet/WQG1/?i=1",
        "Reliability": "C - Fairly reliable",
        "Score": 2,
        "Type": "url",
        "Vendor": "URLhaus"
    },
    "URL": {
        "Data": "http://example.com/anklet/WQG1/?i=1",
        "Relationships": [
            {
                "EntityA": "http://example.com/anklet/WQG1/?i=1",
                "EntityAType": "URL",
                "EntityB": "example.com",
                "EntityBType": "Domain",
                "Relationship": "hosted-on"
            }
        ],
        "Tags": [
            "doc",
            "emotet",
            "epoch5",
            "heodo",
            "malware_download"
        ]
    },
    "URLhaus": {
        "URL": {
            "Blacklist": [
                {
                    "Name": "spamhaus_dbl",
                    "Status": "not listed"
                },
                {
                    "Name": "surbl",
                    "Status": "not listed"
                }
            ],
            "DateAdded": "2022-01-20T14:11:09",
            "Host": "example.com",
            "ID": "1992762",
            "Payload": [
                {
                    "MD5": "716c3aa1e0da98b6e99cadd60363ae7e",
                    "Name": "BC-77388.xlsm",
                    "SHA256": "64c6ba33444e5db3cc9c99613d04fd163ec1971ee5eb90041a17068e37578fc0",
                    "Type": "xls",
                    "VT": null
              }
            ],
            "Status": "offline",
            "Tags": [
                "doc",
                "emotet",
                "epoch5",
                "heodo",
                "malware_download"
            ],
            "Threat": "malware_download"
        }
    }
}

Human Readable Output

URLhaus reputation for http://example.com/anklet/WQG1/?i=1

Date added Description Status Threat URLhaus ID URLhaus link
2022-01-20T14:11:09 The URL is inactive (offline) and serving no payload offline malware_download 1992762 https://urlhaus.abuse.ch/url/1992762/

domain


Retrieves domain information from URLhaus.

Notice: Submitting indicators using this command might make the indicator data publicly available. See the vendor’s documentation for more details.

Base Command

domain

Input

Argument Name Description Required
domain A comma-separated list of domains to query. Required

Context Output

Path Type Description
Domain.Name String The domain name, for example, google.com.
Domain.Tags string A list of tags associated with the queried malware Domain.
Domain.Relationships.EntityA String The source of the relationship.
Domain.Relationships.EntityB String The destination of the relationship.
Domain.Relationships.Relationship String The name of the relationship.
Domain.Relationships.EntityAType String The type of the source of the relationship.
Domain.Relationships.EntityBType String The type of the destination of the relationship.
DBotScore.Indicator String The indicator that was tested.
DBotScore.Type String The indicator type.
DBotScore.Vendor String The vendor used to calculate the score.
DBotScore.Score Number The actual score.
DBotScore.Reliability String Reliability of the source providing the intelligence data.
URLhaus.Domain.FirstSeen Date Date that the IP was seen for the first time (UTC).
URLhaus.Domain.Blacklist.Name String The status of the domain in different block lists.
URLhaus.Domain.URL String URLs observed on this domain.
Domain.Malicious.Vendor String Vendor that reported the domain as malicious.
Domain.Malicious.Description String Description of the malicious domain.
URLhaus.Domain.Blacklist.Status String Status of the URL in the block list.

Command example

!domain using-brand=URLhaus domain=example.com

Context Example

{
    "DBotScore": {
        "Indicator": "example.com",
        "Reliability": "C - Fairly reliable",
        "Score": 1,
        "Type": "domain",
        "Vendor": "URLhaus"
    },
    "Domain": {
        "Name": "example.com",
        "Relationships": [
            {
                "EntityA": "example.com",
                "EntityAType": "Domain",
                "EntityB": "http://example.com:443/wp-content/plugins/wp-roilbask/includes/",
                "EntityBType": "URL",
                "Relationship": "hosts"
            }
        ],
        "Tags": [
            "abused_legit_malware"
        ]
    },
    "URLhaus": {
        "Domain": {
            "Blacklist": {
                "spamhaus_dbl": "abused_legit_malware",
                "surbl": "not listed"
            },
            "FirstSeen": "2022-01-27T12:51:03",
            "URL": [
                {
                    "date_added": "2022-01-28 04:41:03 UTC",
                    "id": "2010874",
                    "larted": "false",
                    "reporter": "Cryptolaemus1",
                    "tags": [
                        "IcedID"
                    ],
                    "takedown_time_seconds": null,
                    "threat": "malware_download",
                    "url": "http://example.com:443/wp-content/plugins/wp-roilbask/includes/",
                    "url_status": "offline",
                    "urlhaus_reference": "https://urlhaus.abuse.ch/url/2010874/"
                }
            ]
        }
    }
}

Human Readable Output

URLhaus reputation for example.com

Description First seen URLhaus link
There is no information about Domain in the blacklist 2022-01-27T12:51:03 https://urlhaus.abuse.ch/host/example.com/

file


Retrieves file information from URLhaus.

Base Command

file

Input

Argument Name Description Required
file A comma-separated list of MD5 or SHA256 hashes of the file to query. Required

Context Output

Path Type Description
File.Size Number File size (in bytes).
File.MD5 String MD5 hash of the file.
File.SHA256 String SHA256 hash of the file.
File.SSDeep String SSDeep of the file.
File.Type String Type of the file.
File.Relationships.EntityA String The source of the relationship.
File.Relationships.EntityB String The destination of the relationship.
File.Relationships.Relationship String The name of the relationship.
File.Relationships.EntityAType String The type of the source of the relationship.
File.Relationships.EntityBType String The type of the destination of the relationship.
URLhaus.File.MD5 String MD5 hash of the file.
URLhaus.File.SHA256 String SHA256 hash of the file.
URLhaus.File.Type String File type guessed by URLhaus, for example: .exe, .doc.
URLhaus.File.Size Number File size (in bytes).
URLhaus.File.Signature String Malware family.
URLhaus.File.FirstSeen Date Date and time (UTC) that URLhaus first saw this file (payload).
URLhaus.File.LastSeen Date Date and time (UTC) that URLhaus last saw this file (payload).
URLhaus.File.DownloadLink String Location (URL) where you can download a copy of this file.
URLhaus.File.VirusTotal.Percent Number AV detection (percentage), for example: 24.14.
URLhaus.File.VirusTotal.Link String Link to the VirusTotal report.
URLhaus.File.URL Unknown A list of malware URLs associated with this payload (max. 100).
DBotScore.Indicator String The indicator that was tested.
DBotScore.Type String The indicator type.
DBotScore.Vendor String The vendor used to calculate the score.
DBotScore.Score Number The actual score.
DBotScore.Reliability String Reliability of the source providing the intelligence data.

Command example

!file using-brand=URLhaus file=7855068e0cfb093ab9be9ec172676e3c119e16511f3d631d715a4e77ddad9d89

Context Example

{
    "DBotScore": {
        "Indicator": "7855068e0cfb093ab9be9ec172676e3c119e16511f3d631d715a4e77ddad9d89",
        "Reliability": "C - Fairly reliable",
        "Score": 3,
        "Type": "file",
        "Vendor": "URLhaus"
    },
    "File": {
        "Malicious": {
            "Description": "This file is malicious",
            "Vendor": "URLhaus"
        },
        "Relationships": [
            {
                "EntityA": "7855068e0cfb093ab9be9ec172676e3c119e16511f3d631d715a4e77ddad9d89",
                "EntityAType": "File",
                "EntityB": "BazaLoader",
                "EntityBType": "Malware",
                "Relationship": "indicator-of"
            }
        ],
        "SHA256": "7855068e0cfb093ab9be9ec172676e3c119e16511f3d631d715a4e77ddad9d89",
        "SSDeep": "24576:la1QHwgJMrQqj/wAc6QORNx2nAjwkaMm0GV9igWwlnwXQBwfalj21X4GtZ+FdnZ8:vH5qloBMd8A",
        "Type": "dll"
    },
    "URLhaus": {
        "File": {
            "DownloadLink": "https://urlhaus-api.abuse.ch/v1/download/7855068e0cfb093ab9be9ec172676e3c119e16511f3d631d715a4e77ddad9d89/",
            "FirstSeen": "2022-01-18T11:18:31",
            "LastSeen": "2022-01-28T09:36:21",
            "MD5": "2ff9cce7a08215ded0945de5965d2a0a",
            "SHA256": "7855068e0cfb093ab9be9ec172676e3c119e16511f3d631d715a4e77ddad9d89",
            "Signature": "BazaLoader",
            "Size": 1816064,
            "Type": "dll",
            "URL": [
                {
                    "filename": "DH-1643319814.xll",
                    "firstseen": "2022-01-27",
                    "lastseen": null,
                    "url": "http://www.example.com/wp-content/plugins/wp-roilbask/includes/",
                    "url_id": "2009726",
                    "url_status": "online",
                    "urlhaus_reference": "https://urlhaus.abuse.ch/url/2009726/"
                }
            ]
        }
    }
}

Human Readable Output

URLhaus reputation for SHA256 : 7855068e0cfb093ab9be9ec172676e3c119e16511f3d631d715a4e77ddad9d89

First seen Last seen MD5 SHA256 Signature URLhaus link
2022-01-18T11:18:31 2022-01-28T09:36:21 2ff9cce7a08215ded0945de5965d2a0a 7855068e0cfb093ab9be9ec172676e3c119e16511f3d631d715a4e77ddad9d89 BazaLoader https://urlhaus-api.abuse.ch/v1/download/7855068e0cfb093ab9be9ec172676e3c119e16511f3d631d715a4e77ddad9d89/

urlhaus-download-sample


Downloads a malware sample from URLhaus.

Base Command

urlhaus-download-sample

Input

Argument Name Description Required
file SHA256 hash of the file to download. Required

Context Output

Path Type Description
File.Size number File size.
File.SHA1 string SHA1 hash of the file.
File.SHA256 string SHA256 hash of the file.
File.Name string File name.
File.SSDeep string SSDeep hash of the file.
File.EntryID string File entry ID.
File.Info string File information.
File.Type string File type.
File.MD5 string MD5 hash of the file.
File.Extension string File extension.

Command example

!urlhaus-download-sample file=254ca6a7a7ef7f17d9884c4a86f88b5d5fd8fe5341c0996eaaf1d4bcb3b2337b

Human Readable Output

{
   "HumanReadable": "No results for SHA256: 254ca6a7a7ef7f17d9884c4a86f88b5d5fd8fe5341c0996eaaf1d4bcb3b2337b",
   "HumanReadableFormat": "markdown",
   "Type": 1
}

Configuration parameters

  • url — Server URL (e.g. https://192.168.0.1)
  • credentials
  • integrationReliability — Source Reliability (required)
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings
  • create_relationships — Create relationships
  • max_num_of_relationships — Maximum number of relationships to fetch per indicator
  • threshold — Blacklists appearances threshold
  • compromised_is_malicious — Compromised (is malicious)
  • retry — Number of retries
  • should_error — Return Error

Commands (4)

  • domain

    Retrieves domain information from URLhaus.

  • file

    Retrieves file information from URLhaus.

  • url

    Retrieves URL information from URLhaus.

  • urlhaus-download-sample

    Downloads a malware sample from URLhaus.

import json
from typing import *

import pytest
from CommonServerPython import Common

params = {
    "api_url": "http://test.com/api/v1",
    "use_ssl": "True",
    "reliability": "C - Fairly reliable",
    "create_relationships": True,
    "max_num_of_relationships": 1,
}


def util_load_json(path: str) -> Any:
    with open(path, encoding="utf-8") as f:
        return json.loads(f.read())


url_command_test = [
    ("http://gfrewdfsersfsfersfgergre.com", "no_results", []),
    ("www.test_url.com", "ok", ["test_tag1", "test_tag2"]),
    ("www.test_url.com", "ok", []),
    ("www.test_url.com", "no_results", ["test_tag1", "test_tag2"]),
    ("www.test_url.com", "no_results", []),
    ("www.testurl.com", "invalid_url", ["test_tag1", "test_tag2"]),
]


@pytest.mark.parametrize("url_to_check, query_status,tags", url_command_test)
def test_url_command(requests_mock, url_to_check, query_status: str, tags: List[str]):
    """
    Given
    - A URL.

    When
    - Calling run_url_command() methood.

    Then
    - Validate that the Tags were created.
    - Validate that the URL and DBotScore entry context have the proper values.
    - Validate that the relationships were created.

    """
    from URLHaus import run_url_command

    mock_response = util_load_json("test_data/url_command.json")
    mock_response["query_status"] = query_status
    mock_response["tags"] = tags
    requests_mock.post("http://test.com/api/v1/url/", json=mock_response)
    results = run_url_command(url_to_check, params)

    url_indicator = results.indicator
    if url_indicator:
        assert url_indicator.url == url_to_check
        if query_status == "ok":
            assert all(elem in url_indicator.tags for elem in tags)
            assert url_indicator.relationships
        else:
            assert not url_indicator.tags
            assert not url_indicator.relationships


url_command_test_reliability_dbot_score = [
    ("online", (3, "The URL is active (online) and currently serving a payload")),
    ("offline", (2, "The URL is inadctive (offline) and serving no payload")),
    ("unknown", (0, "The URL status could not be determined")),
]


@pytest.mark.parametrize("status,excepted_output", url_command_test_reliability_dbot_score)
def test_url_reliability_dbot_score(status: str, excepted_output: Tuple[int, str]):
    """

    Given:
        - A URL status.

    When:
        - Calling calculate_dbot_score() method.

    Then:
        - Make sure the DBot Score is calculated correctly.

    """
    from URLHaus import url_calculate_score

    output = url_calculate_score(status)
    for i in range(len(excepted_output)):
        assert output[i] == excepted_output[i]


url_command_test_create_payloads = [
    (
        {
            "payloads": [
                {
                    "virustotal": {"percent": 1.23, "link": "test_link"},
                    "filename": "test_file",
                    "file_type": "test_type",
                    "response_md5": "test_md5",
                    "response_sha256": "test_sha256",
                }
            ]
        },
        [
            {
                "Name": "test_file",
                "Type": "test_type",
                "MD5": "test_md5",
                "SHA256": "test_sha256",
                "VT": {"Result": 1.23, "Link": "test_link"},
            }
        ],
    ),
    ({"payloads": []}, []),
    ({}, []),
]


@pytest.mark.parametrize("test_data,excepted_output", url_command_test_create_payloads)
def test_url_create_payloads(test_data: dict, excepted_output: List[dict]):
    """

    Given:
        - A URL information including payloads which contain files info.

    When:
        - Calling url_create_payloads() method.

    Then:
        - Make sure the payload lists is created correctly.

    """
    from URLHaus import url_create_payloads

    assert url_create_payloads(url_information=test_data) == excepted_output


url_command_test_create_blacklists = [
    (
        {"blacklists": {"test_name_0": "test_status", "test_name_1": "test_status"}},
        [{"Name": "test_name_0", "Status": "test_status"}, {"Name": "test_name_1", "Status": "test_status"}],
    ),
    ({"blacklists": {}}, []),
    ({}, []),
]


@pytest.mark.parametrize("test_data,excepted_output", url_command_test_create_blacklists)
def test_url_create_blacklists(test_data: dict, excepted_output: List[dict]):
    """

    Given:
        - A URL information including blacklists which contain name,status.

    When:
        - Calling url_create_blacklist() method.

    Then:
        - Make sure the blacklist is created correctly.

    """
    from URLHaus import url_create_blacklist

    assert url_create_blacklist(url_information=test_data) == excepted_output


url_command_test_create_relationships = [
    ("127.0.0.1", "IP", True, 1),
    ("127.0.0.1", "IP", False, 1),
    ("127.0.0.1", "IP", True, 22),
    ("127.0.0.1", "IP", False, 22),
    ("127.0.0.1", "IP", True, 1000),
    ("127.0.0.1", "IP", False, 1000),
    ("test_domain.com", "Domain", True, 1),
    ("test_domain.com", "Domain", False, 1),
    ("test_domain.com", "Domain", True, 22),
    ("test_domain.com", "Domain", False, 22),
    ("test_domain.com", "Domain", True, 1000),
    ("test_domain.com", "Domain", False, 1000),
]


@pytest.mark.parametrize("host,host_type,create_relationships,max_num_relationships", url_command_test_create_relationships)
def test_url_command_create_relationships(host: str, host_type: str, create_relationships: bool, max_num_relationships: int):
    """

    Given:
        - A URL host, file list, Create relationship table(T/F), max number of relationships(Limited to 1000).

    When:
        - Calling url_create_relationships() method.

    Then:
        - Make sure the relationships list is created correctly.

    """
    from URLHaus import url_create_relationships

    files = [
        {
            "Name": f"test_file{i}",
            "Type": f"test_type{i}",
            "MD5": f"test_md5{i}",
            "SHA256": f"test_sha256{i}",
            "VT": {"Result": float(i), "Link": f"test_link{i}"},
        }
        for i in range(10000)
    ]
    uri = "test_uri"
    excepted_output = []
    if create_relationships:
        excepted_output = [
            {
                "Relationship": "related-to" if host_type == "IP" else "hosted-on",
                "EntityA": uri,
                "EntityAType": "URL",
                "EntityB": host,
                "EntityBType": host_type,
            }
        ]
        excepted_output.extend(
            [
                {
                    "Relationship": "related-to",
                    "EntityA": uri,
                    "EntityAType": "URL",
                    "EntityB": files[i].get("SHA256"),
                    "EntityBType": "File",
                }
                for i in range(max_num_relationships - 1)
            ]
        )
    results = url_create_relationships(uri, host, files, create_relationships, max_num_relationships)
    assert len(results) == len(excepted_output)
    for i in range(len(results)):
        assert results[i].to_context() == excepted_output[i]


domain_command_test = [
    ("ok", "spammer_domain", "spammer"),
    ("ok", "phishing_domain", "phishing"),
    ("ok", "botnet_cc_domain", "botnet_cc"),
    ("ok", "abused_legit_spam", "abused_legit_spam"),
    ("ok", "abused_legit_malware", "abused_legit_malware"),
    ("ok", "abused_legit_phishing", "abused_legit_phishing"),
    ("ok", "not listed", ""),
    ("no_results", "not listed", ""),
    ("invalid_host", "spammer_domain", "spammer"),
]


@pytest.mark.parametrize("query_status,spamhaus_dbl,expected_tag", domain_command_test)
def test_domain_command(requests_mock, mocker, query_status: str, spamhaus_dbl: str, expected_tag: str):
    """
    Given
    - A Domain.

    When
    - Calling run_domain_command() method.

    Then
    - Validate that the Tags were created correctly.
    - Validate that the relationships were created correctly.

    """
    from URLHaus import run_domain_command

    domain_to_check = "test.com"
    mock_response = util_load_json("test_data/domain_command.json")
    mock_response["query_status"] = query_status
    mock_response["blacklists"]["spamhaus_dbl"] = spamhaus_dbl
    requests_mock.post("http://test.com/api/v1/host/", json=mock_response)
    results = run_domain_command(domain_to_check, params)

    Domain = results.indicator
    if Domain:
        assert Domain.domain == domain_to_check
        if expected_tag:
            assert Domain.tags[0] == expected_tag if query_status == "ok" else not Domain.tags
        assert len(Domain.relationships) == 1 if query_status == "ok" else not Domain.relationships


domain_command_test_reliability_dbot_score = [
    ({"spamhaus_dbl": "spammer_domain", "surbl": "test"}, (Common.DBotScore.BAD, "The queried Domain is a known spammer domain")),
    (
        {"spamhaus_dbl": "phishing_domain", "surbl": "test"},
        (Common.DBotScore.BAD, "The queried Domain is a known phishing domain"),
    ),
    (
        {"spamhaus_dbl": "botnet_cc_domain", "surbl": "test"},
        (Common.DBotScore.BAD, "The queried Domain is a known botnet C&C domain"),
    ),
    ({"spamhaus_dbl": "test", "surbl": "listed"}, (Common.DBotScore.BAD, "The queried Domain is listed on SURBL")),
    (
        {"spamhaus_dbl": "not listed", "surbl": "test"},
        (Common.DBotScore.NONE, "The queried Domain is not listed on Spamhaus DBL"),
    ),
    ({"spamhaus_dbl": "test", "surbl": "not listed"}, (Common.DBotScore.NONE, "The queried Domain is not listed on SURBL")),
    ({"spamhaus_dbl": "test", "surbl": "test"}, (Common.DBotScore.GOOD, "There is no information about Domain in the blacklist")),
    (
        {"spamhaus_dbl": "botnet_cc_domain", "surbl": "not listed"},
        (Common.DBotScore.BAD, "The queried Domain is a known botnet C&C domain"),
    ),
    ({"spamhaus_dbl": "not listed", "surbl": "listed"}, (Common.DBotScore.BAD, "The queried Domain is listed on SURBL")),
    ({"surbl": "not listed"}, (Common.DBotScore.NONE, "The queried Domain is not listed on SURBL")),
    ({"surbl": "listed"}, (Common.DBotScore.BAD, "The queried Domain is listed on SURBL")),
    ({"spamhaus_dbl": "spammer_domain"}, (Common.DBotScore.BAD, "The queried Domain is a known spammer domain")),
    ({"spamhaus_dbl": "not listed"}, (Common.DBotScore.NONE, "The queried Domain is not listed on Spamhaus DBL")),
    ({}, (Common.DBotScore.GOOD, "There is no information about Domain in the blacklist")),
]


@pytest.mark.parametrize("blacklist,excepted_output", domain_command_test_reliability_dbot_score)
def test_domain_reliability_dbot_score(blacklist: dict, excepted_output: Tuple[int, str]):
    """

    Given:
        - A Domain blacklist from URLhaus database.

    When:
        - Calling calculate_dbot_score() method.

    Then:
        - Make sure the DBot Score is calculated correctly.

    """
    from URLHaus import domain_calculate_score

    output = domain_calculate_score(blacklist)
    for i in range(len(excepted_output)):
        assert output[i] == excepted_output[i]


domain_command_test_create_relationships = [
    (True, 1),
    (False, 1),
    (True, 22),
    (False, 22),
    (True, 1000),
    (False, 1000),
    (True, 1),
    (False, 1),
    (True, 22),
    (False, 22),
    (True, 1000),
    (False, 1000),
]


@pytest.mark.parametrize("create_relationships,max_num_relationships", domain_command_test_create_relationships)
def test_domain_command_test_create_relationships(create_relationships: bool, max_num_relationships: int):
    """

    Given:
        - A Domain, urls list, Create relationship table(T/F), max number of relationships(Limited to 1000).

    When:
        - Calling domain_create_relationships() method.

    Then:
        - Make sure the relationships list is created correctly.

    """
    from URLHaus import domain_create_relationships

    urls = [
        {
            "url": f"test_url{i}",
        }
        for i in range(10000)
    ]  # Large amounts of urls
    domain = "test_domain"
    excepted_output = []
    if create_relationships:
        excepted_output.extend(
            [
                {
                    "Relationship": "hosts",
                    "EntityA": domain,
                    "EntityAType": "Domain",
                    "EntityB": urls[i].get("url"),
                    "EntityBType": "URL",
                }
                for i in range(max_num_relationships)
            ]
        )
    results = domain_create_relationships(urls, domain, create_relationships, max_num_relationships)
    assert len(results) == len(excepted_output)
    for i in range(len(results)):
        assert results[i].to_context() == excepted_output[i]


domain_add_tags = [
    ("spammer_domain", ["spammer"]),
    ("phishing_domain", ["phishing"]),
    ("botnet_cc_domain", ["botnet_cc"]),
    ("listed", []),
    ("not listed", []),
    ("", []),
    (None, []),
]


@pytest.mark.parametrize("blacklist_status,excepted_output", domain_add_tags)
def test_domain_add_tags(blacklist_status: str, excepted_output: List[str]):
    """

    Given:
        - A Blacklist status, tags.

    When:
        - Calling domain_add_tags() method.

    Then:
        - Make sure tags are added correctly.

    """
    from URLHaus import domain_add_tags

    tags = []
    domain_add_tags(blacklist_status, tags)
    assert tags == excepted_output


file_command_test = [
    ("ok", "test_ssdeep_1", "test_ssdeep_1"),
    ("ok", "test_ssdeep_2", "test_ssdeep_2"),
    ("no_results", "test_ssdeep_1", ""),
    ("invalid_md5", "test_ssdeep_1", ""),
    ("invalid_sha256", "test_ssdeep_1", ""),
]


@pytest.mark.parametrize("query_status,ssdeep,expected_ssdeep", file_command_test)
def test_file_command(mocker, requests_mock, query_status: str, ssdeep: str, expected_ssdeep: str):
    """
    Given
    - A file.

    When
    - Calling file_command() method.

    Then
    - Validate that the Tags were created.
    - Validate that the relationships were created.

    """
    from URLHaus import run_file_command

    file_to_check = "a" * 32
    mock_response = util_load_json("test_data/file_command.json")
    mock_response["query_status"] = query_status
    mock_response["ssdeep"] = ssdeep
    requests_mock.post("http://test.com/api/v1/payload/", json=mock_response)
    results = run_file_command(file_to_check, params)

    File = "" if not results.outputs else results.outputs.get("File", "")
    if File:
        assert "SHA256" in File
        if expected_ssdeep:
            assert File["SSDeep"] == expected_ssdeep if query_status == "ok" else "SSDeep" not in File
        assert len(File["Relationships"]) == 1 if query_status == "ok" else "Relationships" not in File


def test_file_reliability_dbot_score():
    """

    Given:
        - A file.

    When:
        - calling calculate_dbot_score() method.

    Then:
        - Make sure the DBot Score is calculated correctly.
    """
    from URLHaus import file_calculate_score

    dbot_score = file_calculate_score()[0]
    assert dbot_score == Common.DBotScore.BAD


file_command_test_create_relationships = [
    (True, 1, "test_signature"),
    (True, 22, "test_signature"),
    (False, 22, "test_signature"),
    (True, 1000, "test_signature"),
    (False, 1000, "test_signature"),
    (False, 22, ""),
    (True, 1000, ""),
    (False, 1000, ""),
]


@pytest.mark.parametrize("create_relationships,max_num_relationships,sig", file_command_test_create_relationships)
def test_file_create_relationships(create_relationships: bool, max_num_relationships: int, sig: str):
    """

    Given:
        - Create relationship table(T/F), max number of relationships(Limited to 1000), file signature.

    When:
        - Calling file_create_relationships() method.

    Then:
        - Make sure the relationships list is created correctly.

    """
    from URLHaus import file_create_relationships

    urls = [
        {
            "url": f"test_url{i}",
        }
        for i in range(10000)
    ]  # Large amounts of urls
    file = "123123123123123123123"
    excepted_output = []
    if create_relationships:
        if sig:
            excepted_output = [
                {
                    "Relationship": "indicator-of",
                    "EntityA": file,
                    "EntityAType": "File",
                    "EntityB": sig,
                    "EntityBType": "Malware",
                }
            ]
        excepted_output.extend(
            [
                {
                    "Relationship": "related-to",
                    "EntityA": file,
                    "EntityAType": "File",
                    "EntityB": urls[i].get("url"),
                    "EntityBType": "URL",
                }
                for i in range(max_num_relationships - len(excepted_output))
            ]
        )
    results = file_create_relationships(
        file=file, urls=urls, sig=sig, create_relationships=create_relationships, max_num_of_relationships=max_num_relationships
    )
    assert len(results) == len(excepted_output)
    for i in range(len(results)):
        assert results[i].to_context() == excepted_output[i]


def test_unsupported_file_return_error(mocker):
    from URLHaus import run_file_command

    params = {"should_error": True}
    hash = "11111111"
    mock_return_error = mocker.patch("URLHaus.return_error", side_effect=Exception())
    with pytest.raises(Exception):
        run_file_command(hash, params)
    mock_return_error.assert_called_once_with("Only accepting MD5 (32 bytes) or SHA256 (64 bytes) hash types")


def test_unsupported_file_return_warning(mocker):
    from URLHaus import run_file_command

    params = {"should_error": False}
    hash = "11111111"
    mock_return_warning = mocker.patch("URLHaus.return_warning", side_effect=Exception())
    with pytest.raises(Exception):
        run_file_command(hash, params)
    mock_return_warning.assert_called_once_with("Only accepting MD5 (32 bytes) or SHA256 (64 bytes) hash types", exit=True)