mirror of
https://github.com/BigBodyCobain/Shadowbroker.git
synced 2026-10-11 01:18:45 +02:00
Fix Docker OpenClaw HMAC persistence and privacy-core build warnings.
Persist OPENCLAW_HMAC_SECRET to data/openclaw.env so empty Docker env vars no longer block auth after UI bootstrap. Add verify_hmac.py, silence Rust warnings (#423), and document Docker signing (#424). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
1 parent
47faa1e488
commit
c45b91c06c
7 files changed
+221
-5
No files matched your search
@@ -88,6 +88,19 @@ For compatibility with older snippets, `SHADOWBROKER_KEY` is also accepted by
|
||||
the client as the same HMAC signing secret. Prefer `SHADOWBROKER_HMAC_SECRET`
|
||||
for new setups.
|
||||
|
||||
**Docker Compose:** host-side agents (`localhost:8000` from the Kali/macOS host)
|
||||
are not loopback inside the backend container — HMAC is required. After
|
||||
**Connect OpenClaw → Bootstrap → Reveal**, the secret is persisted under
|
||||
`data/openclaw.env` on the `backend_data` volume. Restart the backend once,
|
||||
then verify with:
|
||||
|
||||
```bash
|
||||
python openclaw-skills/shadowbroker/verify_hmac.py
|
||||
```
|
||||
|
||||
Hand-rolled signers must hash the **exact** POST bytes. Use compact JSON:
|
||||
`json.dumps(payload, separators=(",", ":"), sort_keys=True)`.
|
||||
|
||||
### SSE Stream (Preferred — Low-Latency Push)
|
||||
|
||||
Open the SSE stream **first** and keep it open for the session. The server pushes
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Verify OpenClaw HMAC auth against a running ShadowBroker backend.
|
||||
|
||||
Usage:
|
||||
export SHADOWBROKER_URL=http://127.0.0.1:8000
|
||||
export SHADOWBROKER_HMAC_SECRET=<from Connect OpenClaw modal>
|
||||
python verify_hmac.py
|
||||
|
||||
Signs the same canonical JSON body as openclaw-skills/shadowbroker/sb_query.py.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import hmac
|
||||
import json
|
||||
import os
|
||||
import secrets
|
||||
import sys
|
||||
import time
|
||||
import urllib.error
|
||||
import urllib.request
|
||||
|
||||
|
||||
def sign(method: str, path: str, body: bytes, secret: str) -> dict[str, str]:
|
||||
ts = str(int(time.time()))
|
||||
nonce = secrets.token_hex(16)
|
||||
digest = hashlib.sha256(body).hexdigest()
|
||||
message = f"{method.upper()}|{path}|{ts}|{nonce}|{digest}"
|
||||
signature = hmac.new(secret.encode(), message.encode(), hashlib.sha256).hexdigest()
|
||||
return {
|
||||
"X-SB-Timestamp": ts,
|
||||
"X-SB-Nonce": nonce,
|
||||
"X-SB-Signature": signature,
|
||||
"Content-Type": "application/json",
|
||||
}
|
||||
|
||||
|
||||
def main() -> int:
|
||||
base = os.environ.get("SHADOWBROKER_URL", "http://127.0.0.1:8000").rstrip("/")
|
||||
secret = os.environ.get("SHADOWBROKER_HMAC_SECRET", "").strip()
|
||||
if not secret:
|
||||
print("Set SHADOWBROKER_HMAC_SECRET to the value from Connect OpenClaw.", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
path = "/api/ai/channel/command"
|
||||
payload = {"cmd": "channel_status", "args": {}}
|
||||
body = json.dumps(payload, separators=(",", ":"), sort_keys=True).encode("utf-8")
|
||||
headers = sign("POST", path, body, secret)
|
||||
req = urllib.request.Request(
|
||||
f"{base}{path}",
|
||||
data=body,
|
||||
headers=headers,
|
||||
method="POST",
|
||||
)
|
||||
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=15) as resp:
|
||||
text = resp.read().decode("utf-8", errors="replace")
|
||||
print(f"HTTP {resp.status}")
|
||||
print(text)
|
||||
return 0
|
||||
except urllib.error.HTTPError as exc:
|
||||
detail = exc.read().decode("utf-8", errors="replace")
|
||||
print(f"HTTP {exc.code}")
|
||||
print(detail)
|
||||
if exc.code == 403:
|
||||
print(
|
||||
"\nTips:\n"
|
||||
"- Bootstrap + Reveal the HMAC secret in AI Intel → Connect OpenClaw\n"
|
||||
"- Use the exact secret (no extra whitespace)\n"
|
||||
"- Sign compact JSON: json.dumps(..., separators=(',', ':'), sort_keys=True)\n"
|
||||
"- Hit the backend port directly (e.g. :8000), not the Next.js :3000 proxy\n"
|
||||
"- After upgrading, restart the backend so data/openclaw.env is loaded",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in new issue
Block a user