initial aubox skeleton: web-UI, kirin DLOAD, firmware library
- FastAPI Web-UI auf 127.0.0.1:8080 mit Geräte-Live-Erkennung, sandboxed File-Browser, Firmware-Library (SQLite + Auto-Identifikation) - Huawei update.app Parser: extrahiert Hardware-ID, Section-Layout, BOOT/SYSTEM-Vorhandensein direkt aus den Headern - Kirin Download-Mode: hisi-idt-Protokoll-Implementation gegen pyusb - USB-Erkennung für Huawei (DLOAD/Fastboot-D), Google, MediaTek, Qualcomm EDL - Huawei-P10-Lite-Workflow (eRecovery + Testpoint-DLOAD-Pfade) - Docker-Compose mit USB-Passthrough (Major 189) für Re-Enumeration - udev-Regeln + Setup-Script für Debian/Ubuntu/Pi-OS Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
"""Sandbox-fähiger Datei-Browser.
|
||||
|
||||
Egal welcher Pfad reinkommt — er wird gegen ein konfiguriertes Root-Verzeichnis
|
||||
geprüft. Path-Traversal (`../..`) ist damit ausgeschlossen.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
class PathEscapeError(PermissionError):
|
||||
"""Pfad würde aus dem erlaubten Root ausbrechen."""
|
||||
|
||||
|
||||
@dataclass
|
||||
class Entry:
|
||||
name: str
|
||||
rel_path: str # relativ zum Root, mit '/' Separator
|
||||
is_dir: bool
|
||||
size: int # Bytes (0 für Dirs)
|
||||
|
||||
|
||||
def safe_resolve(root: Path, rel: str) -> Path:
|
||||
"""Pfad relativ zum Root auflösen und verifizieren, dass er drin bleibt."""
|
||||
root = root.resolve()
|
||||
rel_clean = rel.lstrip("/").strip()
|
||||
target = (root / rel_clean).resolve()
|
||||
try:
|
||||
target.relative_to(root)
|
||||
except ValueError as e:
|
||||
raise PathEscapeError(f"Pfad {rel!r} verlässt Root {root}") from e
|
||||
return target
|
||||
|
||||
|
||||
def list_dir(root: Path, rel: str = "") -> tuple[Path, list[Entry]]:
|
||||
"""Inhalt eines Verzeichnisses listen, Dirs zuerst, dann Files alphabetisch."""
|
||||
target = safe_resolve(root, rel)
|
||||
if not target.exists():
|
||||
raise FileNotFoundError(target)
|
||||
if not target.is_dir():
|
||||
raise NotADirectoryError(target)
|
||||
|
||||
entries: list[Entry] = []
|
||||
for child in sorted(target.iterdir(), key=lambda p: (not p.is_dir(), p.name.lower())):
|
||||
if child.name.startswith("."):
|
||||
continue
|
||||
rel_child = str(child.relative_to(root.resolve())).replace("\\", "/")
|
||||
try:
|
||||
size = child.stat().st_size if child.is_file() else 0
|
||||
except OSError:
|
||||
size = 0
|
||||
entries.append(Entry(
|
||||
name=child.name,
|
||||
rel_path=rel_child,
|
||||
is_dir=child.is_dir(),
|
||||
size=size,
|
||||
))
|
||||
return target, entries
|
||||
|
||||
|
||||
def breadcrumbs(rel: str) -> list[tuple[str, str]]:
|
||||
"""Liste von (Label, Pfad) für die Anzeige als Breadcrumb-Navigation."""
|
||||
parts = [p for p in rel.split("/") if p]
|
||||
out = [("/", "")]
|
||||
cur = ""
|
||||
for p in parts:
|
||||
cur = f"{cur}/{p}" if cur else p
|
||||
out.append((p, cur))
|
||||
return out
|
||||
Reference in New Issue
Block a user