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.
58 lines
2.0 KiB
Python
58 lines
2.0 KiB
Python
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
"""Fake ``.env`` with embedded callback URLs.
|
|
|
|
Modern web stacks read environment variables for everything from
|
|
database DSNs to webhook URLs, so dropping a few realistic-looking
|
|
``KEY=value`` pairs alongside the canary URL is unremarkable. The
|
|
slug appears in two fields:
|
|
|
|
* ``API_BASE_URL`` — the obvious one; an attacker scripting against
|
|
the credentials hits the worker on first invocation.
|
|
* ``WEBHOOK_NOTIFY_URL`` — secondary, in case the attacker greps for
|
|
``WEBHOOK`` and pivots there.
|
|
|
|
Other fields (``DB_PASSWORD``, ``REDIS_URL``, ``JWT_SECRET``) are
|
|
plausible but inert — they're realism filler, not detection
|
|
mechanisms.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
|
|
from decnet.canary.base import CanaryArtifact, CanaryContext, CanaryGenerator
|
|
|
|
|
|
def _stable_token(seed: str, prefix: str = "") -> str:
|
|
h = hashlib.sha256((prefix + seed).encode()).hexdigest()
|
|
return h[:32]
|
|
|
|
|
|
class EnvFileGenerator(CanaryGenerator):
|
|
name = "env_file"
|
|
|
|
def generate(self, ctx: CanaryContext) -> CanaryArtifact:
|
|
base = ctx.http_base.rstrip("/")
|
|
slug = ctx.callback_token
|
|
api_url = f"{base}/c/{slug}"
|
|
body = (
|
|
"# Production environment — DO NOT COMMIT\n"
|
|
f"API_BASE_URL={api_url}\n"
|
|
f"WEBHOOK_NOTIFY_URL={api_url}/webhook\n"
|
|
f"DB_PASSWORD={_stable_token(slug, 'db:')}\n"
|
|
f"REDIS_URL=redis://:{_stable_token(slug, 'redis:')[:16]}@redis.internal:6379/0\n"
|
|
f"JWT_SECRET={_stable_token(slug, 'jwt:')}\n"
|
|
"LOG_LEVEL=info\n"
|
|
"ENVIRONMENT=production\n"
|
|
)
|
|
return CanaryArtifact(
|
|
path="",
|
|
content=body.encode("utf-8"),
|
|
mode=0o600,
|
|
mtime_offset=-86400 * 7, # last edited a week ago
|
|
generator=self.name,
|
|
notes=[
|
|
f"API_BASE_URL embeds {api_url}",
|
|
f"WEBHOOK_NOTIFY_URL embeds {api_url}/webhook",
|
|
],
|
|
)
|