espilon-source/tools/C3PO/tui/widgets/log_pane.py
Eun0us 8b6c1cd53d ε - ChaCha20-Poly1305 AEAD + HKDF crypto upgrade + C3PO rewrite + docs
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
2026-02-10 21:28:45 +01:00

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)