Replaces LICENSE (GPLv3 -> AGPLv3) and prepends `SPDX-License-Identifier: AGPL-3.0-or-later` to every source file across decnet/, decnet_web/, tests/, scripts/, and tools/. Rationale: closes the GPLv3 ASP loophole so any party operating a modified DECNET as a network service must offer their modified source. Personal copyright (Samuel Paschuan) + inbound=outbound contributions make a future unilateral relicense infeasible. - LICENSE: full AGPL-3.0 text (gnu.org/licenses/agpl-3.0.txt) - COPYRIGHT: project copyright notice - tools/add_spdx_headers.py: idempotent header injector (shebang- and PEP 263-aware) Touches 1565 source files (.py, .ts, .tsx, .js, .jsx, .css, .sh). No behavior change; comments only.
61 lines
2.3 KiB
Python
61 lines
2.3 KiB
Python
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
"""Stealth-egress httpx.AsyncClient factory.
|
|
|
|
Per the project's stealth posture, outbound calls to *third-party*
|
|
services (threat-intel providers, public APIs) MUST NOT advertise
|
|
"DECNET" in their User-Agent or other request fingerprints — operators
|
|
running honeypots want their reconnaissance dependencies to look like
|
|
generic infra, not like a tagged tool.
|
|
|
|
Canonical helper for any future module that needs to call a public API
|
|
without leaking the DECNET label. Internal calls (worker → operator's
|
|
own SIEM via webhook, swarm agent → master) deliberately keep
|
|
DECNET-tagged user-agents because the recipient wants the audit trail —
|
|
do NOT route those through this client.
|
|
|
|
Usage::
|
|
|
|
from decnet.net.http import stealth_client
|
|
|
|
async with stealth_client() as client:
|
|
resp = await client.get("https://api.greynoise.io/v3/community/1.2.3.4")
|
|
|
|
The chosen UA mimics ``curl`` because it's the single most common
|
|
"non-browser, non-named-tool" UA on the public internet — anti-bot
|
|
filters routinely permit it, and an attacker who got a peek at our
|
|
egress wouldn't learn anything more specific than "something used curl".
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from typing import Optional
|
|
|
|
import httpx
|
|
|
|
# Pinned to a recent-but-not-bleeding-edge curl release. Bump on the
|
|
# normal cadence; anything in-distribution is fine. Keep this string as
|
|
# the single source of truth so future stealth helpers (browser-shaped,
|
|
# Go-shaped) live as siblings, not divergent constants.
|
|
DEFAULT_STEALTH_USER_AGENT: str = "curl/7.88.1"
|
|
|
|
|
|
def stealth_client(
|
|
*,
|
|
timeout: float = 10.0,
|
|
user_agent: Optional[str] = None,
|
|
follow_redirects: bool = False,
|
|
) -> httpx.AsyncClient:
|
|
"""Return an httpx.AsyncClient with a generic stealth User-Agent.
|
|
|
|
Returns a fresh client per call — callers own the lifecycle and
|
|
SHOULD use ``async with`` to ensure connection-pool teardown.
|
|
|
|
``follow_redirects`` defaults to ``False`` because most threat-intel
|
|
APIs return canonical URLs and a redirect typically signals an auth
|
|
or path mistake we'd rather surface than chase.
|
|
"""
|
|
return httpx.AsyncClient(
|
|
headers={"User-Agent": user_agent or DEFAULT_STEALTH_USER_AGENT},
|
|
timeout=timeout,
|
|
follow_redirects=follow_redirects,
|
|
)
|