mirror of
https://github.com/BigBodyCobain/Shadowbroker.git
synced 2026-06-01 12:01:44 +02:00
Clarify OpenClaw HMAC agent credentials
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
"""Regression coverage for OpenClaw skill HMAC environment names."""
|
||||
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def _load_sb_query(monkeypatch):
|
||||
module_path = Path(__file__).resolve().parents[2] / "openclaw-skills" / "shadowbroker" / "sb_query.py"
|
||||
spec = importlib.util.spec_from_file_location("shadowbroker_skill_sb_query_test", module_path)
|
||||
assert spec and spec.loader
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
def test_openclaw_skill_prefers_hmac_secret_env(monkeypatch):
|
||||
monkeypatch.setenv("SHADOWBROKER_HMAC_SECRET", "preferred-hmac-secret")
|
||||
monkeypatch.setenv("SHADOWBROKER_KEY", "legacy-hmac-secret")
|
||||
|
||||
module = _load_sb_query(monkeypatch)
|
||||
|
||||
assert module.ShadowBrokerClient()._hmac_secret == "preferred-hmac-secret"
|
||||
|
||||
|
||||
def test_openclaw_skill_accepts_legacy_key_as_hmac_secret_alias(monkeypatch):
|
||||
monkeypatch.delenv("SHADOWBROKER_HMAC_SECRET", raising=False)
|
||||
monkeypatch.setenv("SHADOWBROKER_KEY", "legacy-hmac-secret")
|
||||
|
||||
module = _load_sb_query(monkeypatch)
|
||||
client = module.ShadowBrokerClient()
|
||||
headers = client._sign_headers("GET", "/api/ai/tools")
|
||||
|
||||
assert client._hmac_secret == "legacy-hmac-secret"
|
||||
assert "X-SB-Timestamp" in headers
|
||||
assert "X-SB-Nonce" in headers
|
||||
assert "X-SB-Signature" in headers
|
||||
assert "Authorization" not in headers
|
||||
assert "X-Admin-Key" not in headers
|
||||
@@ -632,10 +632,18 @@ function ConnectModalBody({ apiEndpoint, handleCopy, copied }: ConnectModalBodyP
|
||||
const buildSnippet = (key: string) => {
|
||||
const lines: string[] = [];
|
||||
if (resolvedUrl) lines.push(`SHADOWBROKER_URL=${resolvedUrl}`);
|
||||
lines.push(`SHADOWBROKER_KEY=${key}`);
|
||||
lines.push(`SHADOWBROKER_HMAC_SECRET=${key}`);
|
||||
lines.push(`SHADOWBROKER_ACCESS=${accessTier}`);
|
||||
if (connectionMode === 'remote' && nodeId) lines.push(`SHADOWBROKER_NODE_ID=${nodeId}`);
|
||||
lines.push('');
|
||||
lines.push('# AUTH DIRECTIVE:');
|
||||
lines.push('# SHADOWBROKER_HMAC_SECRET is a shared HMAC signing secret, not a raw API key.');
|
||||
lines.push('# Never send it as X-Admin-Key, Authorization: Bearer, a query parameter, or a plain request header.');
|
||||
lines.push('# Every direct ShadowBroker API request must be HMAC-SHA256 signed with:');
|
||||
lines.push('# X-SB-Timestamp, X-SB-Nonce, X-SB-Signature');
|
||||
lines.push('# Signature input: METHOD|path|timestamp|nonce|sha256(body)');
|
||||
lines.push('# Use the ShadowBrokerClient/openclaw skill helper so requests are signed automatically.');
|
||||
lines.push('');
|
||||
lines.push('# OPERATING DIRECTIVE:');
|
||||
lines.push('# You are a remote OpenClaw agent connected to ShadowBroker.');
|
||||
lines.push('# ShadowBroker is a live intelligence and telemetry platform, not a narrow single-purpose API.');
|
||||
|
||||
@@ -129,13 +129,16 @@ const OnboardingModal = React.memo(function OnboardingModal({
|
||||
|
||||
const agentSnippet = [
|
||||
`SHADOWBROKER_URL=${agentEndpoint}`,
|
||||
agentSecret ? `SHADOWBROKER_KEY=${agentSecret}` : 'SHADOWBROKER_KEY=<generate in ShadowBroker>',
|
||||
agentSecret ? `SHADOWBROKER_HMAC_SECRET=${agentSecret}` : 'SHADOWBROKER_HMAC_SECRET=<generate in ShadowBroker>',
|
||||
`SHADOWBROKER_ACCESS=${agentTier}`,
|
||||
'',
|
||||
'# FIRST: load available tools',
|
||||
`GET ${agentEndpoint}/api/ai/tools`,
|
||||
'',
|
||||
'# Auth: HMAC-SHA256 signed requests.',
|
||||
'# Auth: SHADOWBROKER_HMAC_SECRET is not a raw API key.',
|
||||
'# Sign every direct request with X-SB-Timestamp, X-SB-Nonce, and X-SB-Signature.',
|
||||
'# Signature input: METHOD|path|timestamp|nonce|sha256(body).',
|
||||
'# Do not send the secret as X-Admin-Key, Authorization, or a query parameter.',
|
||||
'# Restricted = read-only telemetry. Full = can write when asked.',
|
||||
].join('\n');
|
||||
const remoteAgentNeedsTor = agentMode === 'remote' && !torAddress;
|
||||
|
||||
@@ -37,7 +37,18 @@ SHADOWBROKER_HMAC_SECRET=your-hmac-secret-here
|
||||
```
|
||||
|
||||
The HMAC secret is found in ShadowBroker's **Connect OpenClaw** modal (AI Intel panel).
|
||||
All requests are automatically signed with HMAC-SHA256 (timestamp + nonce + body digest) for replay protection and request-body integrity binding.
|
||||
`SHADOWBROKER_HMAC_SECRET` is a shared signing secret, not a raw API key. Do not
|
||||
send it as `X-Admin-Key`, `Authorization: Bearer`, a query parameter, or any
|
||||
plain request header. The `ShadowBrokerClient` signs every direct request with
|
||||
`X-SB-Timestamp`, `X-SB-Nonce`, and `X-SB-Signature` using:
|
||||
|
||||
```text
|
||||
HMAC-SHA256(secret, METHOD|path|timestamp|nonce|sha256(body))
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
### SSE Stream (Preferred — Low-Latency Push)
|
||||
|
||||
|
||||
@@ -5,6 +5,9 @@ the ShadowBroker OSINT platform.
|
||||
|
||||
For local access (same machine), no authentication is needed.
|
||||
For remote access, set SHADOWBROKER_HMAC_SECRET to enable HMAC-signed requests.
|
||||
Older ShadowBroker UI snippets used SHADOWBROKER_KEY; this client still accepts
|
||||
that value as an HMAC signing secret for compatibility. Never send either value
|
||||
as a raw bearer token, X-Admin-Key, query parameter, or unsigned header.
|
||||
|
||||
Usage (inside an OpenClaw skill):
|
||||
from sb_query import ShadowBrokerClient
|
||||
@@ -43,11 +46,17 @@ class ShadowBrokerClient:
|
||||
|
||||
Supports both local (no auth) and remote (HMAC-signed) connections.
|
||||
Set SHADOWBROKER_HMAC_SECRET env var to enable remote authentication.
|
||||
SHADOWBROKER_KEY is accepted only as a backwards-compatible HMAC-secret
|
||||
alias for older copy snippets.
|
||||
"""
|
||||
|
||||
def __init__(self, base_url: str = SB_BASE, hmac_secret: str = ""):
|
||||
self.base = base_url.rstrip("/")
|
||||
self._hmac_secret = hmac_secret or os.environ.get("SHADOWBROKER_HMAC_SECRET", "")
|
||||
self._hmac_secret = (
|
||||
hmac_secret
|
||||
or os.environ.get("SHADOWBROKER_HMAC_SECRET", "")
|
||||
or os.environ.get("SHADOWBROKER_KEY", "")
|
||||
)
|
||||
self._client = None
|
||||
# Version tracking for incremental updates
|
||||
self._last_data_version: int | None = None
|
||||
|
||||
Reference in New Issue
Block a user