Crypto: - Replace broken ChaCha20 (static nonce) with ChaCha20-Poly1305 AEAD - HKDF-SHA256 key derivation from per-device factory NVS master keys - Random 12-byte nonce per message (ESP32 hardware RNG) - crypto_init/encrypt/decrypt API with mbedtls legacy (ESP-IDF v5.3.2) - Custom partition table with factory NVS (fctry at 0x10000) Firmware: - crypto.c full rewrite, messages.c device_id prefix + AEAD encrypt - crypto_init() at boot with esp_restart() on failure - Fix command_t initializations across all modules (sub/help fields) - Clean CMakeLists dependencies for ESP-IDF v5.3.2 C3PO (C2): - Rename tools/c2 + tools/c3po -> tools/C3PO - Per-device CryptoContext with HKDF key derivation - KeyStore (keys.json) for master key management - Transport parses device_id:base64(...) wire format Tools: - New tools/provisioning/provision.py for factory NVS key generation - Updated flasher with mbedtls config for v5.3.2 Docs: - Update all READMEs for new crypto, C3PO paths, provisioning - Update roadmap, architecture diagrams, security sections - Update CONTRIBUTING.md project structure
118 lines
3.3 KiB
Python
118 lines
3.3 KiB
Python
"""
|
|
Log pane widgets for displaying device and global logs.
|
|
"""
|
|
from textual.widgets import RichLog
|
|
from rich.text import Text
|
|
|
|
|
|
class GlobalLogPane(RichLog):
|
|
"""Combined log view for all devices and system messages."""
|
|
|
|
DEFAULT_CSS = """
|
|
GlobalLogPane {
|
|
border: solid $primary;
|
|
height: 100%;
|
|
scrollbar-size: 1 1;
|
|
}
|
|
"""
|
|
|
|
def __init__(self, **kwargs):
|
|
super().__init__(
|
|
highlight=True,
|
|
markup=True,
|
|
wrap=True,
|
|
max_lines=5000,
|
|
**kwargs
|
|
)
|
|
|
|
def add_system(self, timestamp: str, message: str):
|
|
"""Add a system message."""
|
|
text = Text()
|
|
text.append(f"{timestamp} ", style="dim")
|
|
text.append("[SYS] ", style="cyan bold")
|
|
text.append(message)
|
|
self.write(text)
|
|
|
|
def add_device_event(self, timestamp: str, device_id: str, event: str):
|
|
"""Add a device event."""
|
|
text = Text()
|
|
text.append(f"{timestamp} ", style="dim")
|
|
text.append(f"[{device_id}] ", style="yellow")
|
|
text.append(event)
|
|
self.write(text)
|
|
|
|
def add_command_sent(self, timestamp: str, device_id: str, command: str, request_id: str):
|
|
"""Add a command sent message."""
|
|
text = Text()
|
|
text.append(f"{timestamp} ", style="dim")
|
|
text.append("[CMD] ", style="blue bold")
|
|
text.append(f"{command} ", style="blue")
|
|
text.append(f"-> {device_id}", style="dim")
|
|
self.write(text)
|
|
|
|
def add_command_response(self, timestamp: str, device_id: str, response: str, request_id: str):
|
|
"""Add a command response."""
|
|
text = Text()
|
|
text.append(f"{timestamp} ", style="dim")
|
|
text.append(f"[{device_id}] ", style="green")
|
|
text.append(response, style="green")
|
|
self.write(text)
|
|
|
|
def add_error(self, timestamp: str, message: str):
|
|
"""Add an error message."""
|
|
text = Text()
|
|
text.append(f"{timestamp} ", style="dim")
|
|
text.append("[ERR] ", style="red bold")
|
|
text.append(message, style="red")
|
|
self.write(text)
|
|
|
|
|
|
class DeviceLogPane(RichLog):
|
|
"""Per-device log display with filtering."""
|
|
|
|
DEFAULT_CSS = """
|
|
DeviceLogPane {
|
|
height: 100%;
|
|
scrollbar-size: 1 1;
|
|
}
|
|
"""
|
|
|
|
def __init__(self, device_id: str, **kwargs):
|
|
super().__init__(
|
|
highlight=True,
|
|
markup=True,
|
|
wrap=True,
|
|
max_lines=2000,
|
|
**kwargs
|
|
)
|
|
self.device_id = device_id
|
|
|
|
def add_event(self, timestamp: str, event: str, event_type: str = "info"):
|
|
"""Add an event to this device's log."""
|
|
text = Text()
|
|
text.append(f"{timestamp} ", style="dim")
|
|
|
|
style_map = {
|
|
"info": "yellow",
|
|
"log": "white",
|
|
"error": "red",
|
|
"cmd_sent": "blue",
|
|
"cmd_resp": "green",
|
|
"data": "magenta",
|
|
}
|
|
style = style_map.get(event_type, "white")
|
|
|
|
prefix_map = {
|
|
"info": "> INFO: ",
|
|
"log": "> LOG: ",
|
|
"error": "> ERROR: ",
|
|
"cmd_sent": "> CMD: ",
|
|
"cmd_resp": "> RESP: ",
|
|
"data": "> DATA: ",
|
|
}
|
|
prefix = prefix_map.get(event_type, "> ")
|
|
|
|
text.append(prefix, style=f"{style} bold")
|
|
text.append(event, style=style)
|
|
self.write(text)
|