Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions mithwire/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from mithwire.core.tab import Tab
from mithwire.core.util import loop, start
from mithwire.stealth import FingerprintConfig, Stealth, compute_launch_args
from mithwire.stealth_diagnostic import run_stealth_diagnostic, stealth_diagnostic
from mithwire.stealth_diagnostic import diagnose_stealth, run_stealth_diagnostic

__all__ = [
"loop",
Expand All @@ -32,7 +32,7 @@
"FingerprintConfig",
"Stealth",
"compute_launch_args",
"stealth_diagnostic",
"diagnose_stealth",
"run_stealth_diagnostic",
]

Expand Down
8 changes: 4 additions & 4 deletions mithwire/stealth_diagnostic/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
public bot-detection sites and reports how it looks, so anyone who installs
mithwire can check their machine, adjust their client, and re-run to verify.

from mithwire import stealth_diagnostic
report = stealth_diagnostic() # headful, all sites
from mithwire import diagnose_stealth
report = diagnose_stealth() # headful, all sites (sync)
print(report.verdict) # PASS / WARN / FAIL

Or from the shell::
Expand All @@ -23,10 +23,10 @@
build_report,
format_report,
)
from .runner import run_stealth_diagnostic, stealth_diagnostic
from .runner import diagnose_stealth, run_stealth_diagnostic

__all__ = [
"stealth_diagnostic",
"diagnose_stealth",
"run_stealth_diagnostic",
"build_report",
"format_report",
Expand Down
12 changes: 9 additions & 3 deletions mithwire/stealth_diagnostic/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from .probes import NAV_PROBE, SITES, WEBRTC_PROBE, parse, wrap
from .report import StealthDiagnosticReport, build_report

__all__ = ["run_stealth_diagnostic", "stealth_diagnostic"]
__all__ = ["run_stealth_diagnostic", "diagnose_stealth"]


async def _guard(coro, timeout: float, name: str) -> Any:
Expand Down Expand Up @@ -102,6 +102,12 @@ async def run_stealth_diagnostic(
return build_report(raw, headless=headless)


def stealth_diagnostic(**kwargs: Any) -> StealthDiagnosticReport:
"""Synchronous wrapper around :func:`run_stealth_diagnostic` (engine loop)."""
def diagnose_stealth(**kwargs: Any) -> StealthDiagnosticReport:
"""Synchronous wrapper around :func:`run_stealth_diagnostic` (engine loop).

Named ``diagnose_stealth`` (not ``stealth_diagnostic``) on purpose: the
package is ``mithwire.stealth_diagnostic``, so a same-named callable would
shadow the subpackage on the ``mithwire`` namespace and break
``import mithwire.stealth_diagnostic.<x>``.
"""
return _loop().run_until_complete(run_stealth_diagnostic(**kwargs))
18 changes: 17 additions & 1 deletion tests/test_stealth_diagnostic_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"""
from __future__ import annotations

import types
import unittest

import mithwire
Expand All @@ -20,7 +21,7 @@

class PublicApiTests(unittest.TestCase):
def test_package_exports_are_callable(self):
for name in ("stealth_diagnostic", "run_stealth_diagnostic"):
for name in ("diagnose_stealth", "run_stealth_diagnostic"):
self.assertIn(name, mithwire.__all__)
self.assertTrue(callable(getattr(mithwire, name)))

Expand All @@ -29,6 +30,21 @@ def test_old_selftest_name_is_gone(self):
self.assertFalse(hasattr(mithwire, "selftest"))
self.assertFalse(hasattr(mithwire, "run_selftest"))

def test_subpackage_attribute_is_the_module_not_a_function(self):
# Regression: the sync wrapper used to be exported as ``stealth_diagnostic``,
# which shadowed the ``mithwire.stealth_diagnostic`` subpackage on the
# ``mithwire`` namespace and broke dotted submodule imports below.
self.assertIsInstance(mithwire.stealth_diagnostic, types.ModuleType)

def test_dotted_submodule_import_resolves(self):
# ``import mithwire.stealth_diagnostic.probes as p`` compiles to IMPORT_FROM,
# which walks the (formerly shadowed) ``stealth_diagnostic`` attribute. This
# is the exact form that regressed; assert it resolves to the real module.
import mithwire.stealth_diagnostic.probes as p

self.assertIs(p, mithwire.stealth_diagnostic.probes)
self.assertTrue(p.SITES)


class CliParserTests(unittest.TestCase):
def setUp(self):
Expand Down
Loading