Reject revokes the node's MQTT login and API key (server-26#195)

reject_node only set approval_status, so an approved-then-rejected node kept
its dynsec login, its /upload key and /systems read access.

- reject_node: status -> rejected first (fail-closed), then
  dynsec.delete_node_client, then delete node_keys. dynsec failure -> 502,
  key kept, retry is idempotent. Re-approve mints a fresh key.
- upload.py: valid key alone is not enough; node must be approved (403),
  uncached read so revocation bites immediately.
- dynsec.reconcile_all: deletes rejected nodes' logins on startup, healing
  nodes rejected before this change or whose revoke failed.
- Reject confirm text says it revokes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Logan Cusano
2026-10-04 17:58:51 -04:00
co-authored by Claude Opus 5.5
parent d57738a8f6
commit 73147803ea
5 changed files with 262 additions and 7 deletions
+1 -1
View File
@@ -197,7 +197,7 @@ export default function NodeDetailPage() {
}
async function handleReject() {
if (!confirm("Reject this node? It will not be able to upload recordings.")) return;
if (!confirm("Reject this node? Any MQTT login and API key it holds are revoked, so it cannot connect or upload. Re-approving later issues a new key.")) return;
setApproving(true);
try {
await c2api.rejectNode(id);