Add sbx-mesh-invite and sbx-mesh-join CLI tools to secubox-master-link: - sbx-mesh-invite: Generate invite tokens with URL output (for masters) - sbx-mesh-join: Join mesh with token (for peers), uses HTTPS Add .claude/prompts/secubox-deb-masterlink.md: - API specification for implementing master-link on secubox-deb (VM) - Endpoints: status, invite, join, peers, approve, cleanup - Data structures for tokens.json and peers.json - Integration notes for existing LuCI UI Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
5.3 KiB
SecuBox-Deb Master-Link API Implementation
Overview
Implement the Master-Link mesh enrollment API for SecuBox-Deb (Debian/Ubuntu VM version). This allows the VM to act as a master node that can onboard OpenWrt peer nodes into the mesh network.
The API should be added to the existing P2P FastAPI service running at /run/secubox/p2p.sock and exposed via nginx at https://<host>/api/v1/p2p/master-link/*.
Current State
- P2P service:
/usr/bin/uvicorn api.main:app --uds /run/secubox/p2p.sock - Token storage:
/var/lib/secubox/p2p/master-link/tokens.json - Peer storage:
/var/lib/secubox/p2p/master-link/peers.json - The existing VM already has partial master-link support
Required API Endpoints
1. Status Endpoint
GET /master-link/status
Returns mesh status:
{
"enabled": true,
"role": "master",
"depth": 0,
"max_depth": 3,
"upstream": null,
"fingerprint": "sb-<unique-id>",
"hostname": "secubox-vm-x64",
"auto_approve": false,
"peers": {
"pending": 0,
"approved": 3,
"rejected": 0,
"total": 3
},
"active_tokens": 1
}
2. Generate Invite Token
POST /master-link/invite
Content-Type: application/json
{
"auto_approve": true,
"ttl": 3600
}
Returns:
{
"token": "abc123def456...",
"hash": "sha256-hash-of-token",
"expires": "2026-03-26T16:00:00Z",
"expires_ts": 1774540800,
"ttl": 3600,
"auto_approve": true,
"url": "https://192.168.255.200/master-link/?token=abc123def456..."
}
Token Generation Logic:
import secrets
import hashlib
from datetime import datetime, timedelta
token = secrets.token_hex(16) # 32 char hex string
token_hash = hashlib.sha256(token.encode()).hexdigest()
expires = datetime.now() + timedelta(seconds=ttl)
3. Join Endpoint (for peers)
POST /master-link/join
Content-Type: application/json
{
"token": "abc123def456...",
"fingerprint": "owrt-0050430d1918",
"hostname": "C3BOX",
"address": "192.168.255.1",
"model": "Globalscale MOCHAbin"
}
Validation Flow:
- Hash incoming token:
sha256(token) - Find matching token in
tokens.jsonby hash - Check token status is "active" and not expired
- If
auto_approveis true, immediately approve - Otherwise, queue for manual approval
Success Response (auto-approved):
{
"status": "approved",
"fingerprint": "owrt-0050430d1918",
"message": "Welcome to the mesh",
"master_fingerprint": "sb-test123456",
"depth": 1
}
Success Response (pending):
{
"status": "pending",
"fingerprint": "owrt-0050430d1918",
"message": "Awaiting master approval"
}
Error Responses:
{"status": "error", "message": "Invalid or expired token"}
{"status": "error", "message": "Token already used"}
4. List Peers
GET /master-link/peers
Returns:
{
"peers": [
{
"fingerprint": "owrt-0050430d1918",
"hostname": "C3BOX",
"address": "192.168.255.1",
"model": "Globalscale MOCHAbin",
"status": "approved",
"joined_at": "2026-03-26T14:00:32.721532",
"depth": 1
}
]
}
5. Approve/Reject Peer
POST /master-link/approve
Content-Type: application/json
{
"fingerprint": "owrt-0050430d1918",
"action": "approve" // or "reject"
}
6. Cleanup Tokens
POST /master-link/cleanup
Removes expired and used tokens.
Data Structures
tokens.json
[
{
"hash": "sha256-of-token",
"type": "join",
"created": "2026-03-26T11:44:54.033842",
"expires": "2026-03-26T12:44:54.033842",
"expires_ts": 1774529094,
"ttl": 3600,
"status": "active", // active, used, expired
"auto_approve": true,
"peer_fp": null, // filled when used
"used_by": null,
"used_at": null
}
]
peers.json
[
{
"fingerprint": "owrt-0050430d1918",
"hostname": "C3BOX",
"address": "192.168.255.1",
"model": "Globalscale MOCHAbin",
"status": "approved",
"token_hash": "abc123...",
"joined_at": "2026-03-26T14:00:32.721532",
"depth": 1,
"last_seen": "2026-03-26T15:30:00.000000"
}
]
CLI Tools (for reference)
The OpenWrt side has these CLI tools that interact with this API:
sbx-mesh-invite (on master)
Generates invite token and outputs join URL/command.
sbx-mesh-join (on peer)
Joins a mesh by sending join request with token.
# On master (VM)
sbx-mesh-invite --ip 192.168.255.200
# Output: Token and join URL
# On peer (OpenWrt)
sbx-mesh-join 192.168.255.200 <token>
Implementation Notes
- HTTPS Required: The join endpoint uses HTTPS (port 443), not HTTP port 7331
- Self-signed Certs: Peers use
--no-check-certificate(wget) or-k(curl) - Token Security: Tokens are one-time use; mark as "used" immediately upon successful join
- Auto-approve: When
auto_approve=true, skip manual approval step - Fingerprint: Use unique device identifier (MAC-based for OpenWrt, random for VMs)
Integration with Existing UI
The existing LuCI UI at /admin/services/secubox-mesh shows:
- Node status (Role, Fingerprint, Peers, Chain)
- ZKP Authentication section
- Generate Token / Cleanup Tokens buttons
These buttons should call the API endpoints above.
File Locations (secubox-deb)
- API source:
/srv/secubox/api/routers/master_link.py(to create) - Data dir:
/var/lib/secubox/p2p/master-link/ - Config:
/etc/secubox/master-link.yaml