mirror of
https://github.com/laramies/theHarvester.git
synced 2026-08-23 06:12:22 +02:00
* fix: call Censys Platform API directly (#295) (cherry picked from commit 7ce361413ad35471ab0b6878382f3548b0918dbe) * docs: clarify Censys global search entitlement
210 lines
6.4 KiB
Python
210 lines
6.4 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import textwrap
|
|
from pathlib import Path
|
|
from typing import TYPE_CHECKING, NamedTuple
|
|
|
|
import pytest
|
|
import yaml
|
|
|
|
from theHarvester.lib.configuration import FileSystemCredentialAdapter
|
|
|
|
if TYPE_CHECKING:
|
|
from collections.abc import Callable
|
|
from types import ModuleType
|
|
|
|
from theHarvester.lib.core import Core
|
|
|
|
|
|
class ConfigurationEnvironment(NamedTuple):
|
|
core: type[Core]
|
|
module: ModuleType
|
|
directories: list[Path]
|
|
|
|
|
|
def test_importing_core_does_not_access_configuration_files(tmp_path: Path) -> None:
|
|
script = textwrap.dedent(
|
|
"""
|
|
import sys
|
|
|
|
configuration_accesses: list[str] = []
|
|
|
|
def record_configuration_access(event: str, arguments: tuple[object, ...]) -> None:
|
|
if event != 'open':
|
|
return
|
|
path = arguments[0]
|
|
if isinstance(path, str) and path.endswith(('api-keys.yaml', 'proxies.yaml')):
|
|
configuration_accesses.append(path)
|
|
|
|
sys.addaudithook(record_configuration_access)
|
|
|
|
import theHarvester.lib.core
|
|
|
|
assert configuration_accesses == [], configuration_accesses
|
|
|
|
first_proxy_list = theHarvester.lib.core.AsyncFetcher().proxy_list
|
|
access_count = len(configuration_accesses)
|
|
second_proxy_list = theHarvester.lib.core.AsyncFetcher().proxy_list
|
|
|
|
assert second_proxy_list is first_proxy_list
|
|
assert len(configuration_accesses) == access_count
|
|
"""
|
|
)
|
|
environment = os.environ.copy()
|
|
environment['HOME'] = str(tmp_path)
|
|
|
|
result = subprocess.run(
|
|
[sys.executable, '-c', script],
|
|
capture_output=True,
|
|
check=False,
|
|
cwd=Path(__file__).parents[2],
|
|
env=environment,
|
|
text=True,
|
|
)
|
|
|
|
assert result.returncode == 0, result.stderr
|
|
|
|
|
|
@pytest.fixture
|
|
def configuration_environment(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
tmp_path: Path,
|
|
) -> ConfigurationEnvironment:
|
|
monkeypatch.setenv('HOME', str(tmp_path))
|
|
import theHarvester.lib.core as core_module
|
|
|
|
directories = [tmp_path / name for name in ('user', 'system', 'local')]
|
|
for directory in directories:
|
|
directory.mkdir()
|
|
monkeypatch.setattr(core_module, 'CONFIG_DIRS', directories)
|
|
return ConfigurationEnvironment(core_module.Core, core_module, directories)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
('present_indexes', 'expected_key'),
|
|
[
|
|
((0, 1, 2), 'user-key'),
|
|
((1, 2), 'system-key'),
|
|
((2,), 'local-key'),
|
|
],
|
|
)
|
|
def test_api_keys_and_filesystem_credentials_use_first_available_configuration(
|
|
configuration_environment: ConfigurationEnvironment,
|
|
present_indexes: tuple[int, ...],
|
|
expected_key: str,
|
|
) -> None:
|
|
core = configuration_environment.core
|
|
configuration_dirs = configuration_environment.directories
|
|
keys = ('user-key', 'system-key', 'local-key')
|
|
for index in present_indexes:
|
|
(configuration_dirs[index] / 'api-keys.yaml').write_text(
|
|
f'apikeys:\n brave:\n key: {keys[index]}\n',
|
|
encoding='utf-8',
|
|
)
|
|
|
|
assert (core.api_keys(), FileSystemCredentialAdapter().get('brave')) == (
|
|
{'brave': {'key': expected_key}},
|
|
expected_key,
|
|
)
|
|
|
|
|
|
def test_missing_api_keys_uses_and_creates_bundled_default(
|
|
monkeypatch: pytest.MonkeyPatch,
|
|
tmp_path: Path,
|
|
configuration_environment: ConfigurationEnvironment,
|
|
) -> None:
|
|
core = configuration_environment.core
|
|
core_module = configuration_environment.module
|
|
configuration_dirs = configuration_environment.directories
|
|
bundled_directory = tmp_path / 'bundled'
|
|
bundled_directory.mkdir()
|
|
bundled_content = 'apikeys:\n brave:\n key: bundled-key\n'
|
|
(bundled_directory / 'api-keys.yaml').write_text(bundled_content, encoding='utf-8')
|
|
monkeypatch.setattr(core_module, 'DATA_DIR', bundled_directory)
|
|
|
|
assert (
|
|
core.api_keys(),
|
|
(configuration_dirs[0] / 'api-keys.yaml').read_text(encoding='utf-8'),
|
|
) == (
|
|
{'brave': {'key': 'bundled-key'}},
|
|
bundled_content,
|
|
)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
('filename', 'configuration_reader'),
|
|
[
|
|
('api-keys.yaml', 'api_keys'),
|
|
('proxies.yaml', 'proxy_list'),
|
|
],
|
|
)
|
|
def test_malformed_configuration_raises_yaml_error(
|
|
configuration_environment: ConfigurationEnvironment,
|
|
filename: str,
|
|
configuration_reader: str,
|
|
) -> None:
|
|
core = configuration_environment.core
|
|
configuration_dirs = configuration_environment.directories
|
|
(configuration_dirs[0] / filename).write_text('key: [unterminated\n', encoding='utf-8')
|
|
reader: Callable[[], dict[str, object]] = getattr(core, configuration_reader)
|
|
|
|
with pytest.raises(yaml.YAMLError):
|
|
reader()
|
|
|
|
|
|
def test_provider_accessors_return_single_and_multi_field_credentials(
|
|
configuration_environment: ConfigurationEnvironment,
|
|
) -> None:
|
|
core = configuration_environment.core
|
|
configuration_dirs = configuration_environment.directories
|
|
(configuration_dirs[0] / 'api-keys.yaml').write_text(
|
|
'apikeys:\n bevigil:\n key: bevigil-key\n censys:\n token: censys-token\n organization_id: censys-org\n',
|
|
encoding='utf-8',
|
|
)
|
|
|
|
assert (core.bevigil_key(), core.censys_key()) == (
|
|
'bevigil-key',
|
|
('censys-token', 'censys-org'),
|
|
)
|
|
|
|
|
|
def test_brave_key_returns_configured_value(
|
|
configuration_environment: ConfigurationEnvironment,
|
|
) -> None:
|
|
core = configuration_environment.core
|
|
configuration_dirs = configuration_environment.directories
|
|
(configuration_dirs[0] / 'api-keys.yaml').write_text(
|
|
'apikeys:\n brave:\n key: brave-key\n',
|
|
encoding='utf-8',
|
|
)
|
|
|
|
assert core.brave_key() == 'brave-key'
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
('contents', 'expected'),
|
|
[
|
|
(
|
|
'http: [proxy.local:8080]\nsocks5: [socks.local:1080]\n',
|
|
{
|
|
'http': ['http://proxy.local:8080'],
|
|
'socks5': ['socks5://socks.local:1080'],
|
|
},
|
|
),
|
|
('http:\n', {'http': [], 'socks5': []}),
|
|
],
|
|
)
|
|
def test_proxy_lookup_normalizes_configured_addresses(
|
|
configuration_environment: ConfigurationEnvironment,
|
|
contents: str,
|
|
expected: dict[str, list[str]],
|
|
) -> None:
|
|
core = configuration_environment.core
|
|
configuration_dirs = configuration_environment.directories
|
|
(configuration_dirs[0] / 'proxies.yaml').write_text(contents, encoding='utf-8')
|
|
|
|
assert core.proxy_list() == expected
|