Nice Work

This commit is contained in:
2026-01-13 19:44:02 +00:00
parent b503b372b4
commit 0718377b27
144 changed files with 15587 additions and 2132 deletions
View File
+52
View File
@@ -0,0 +1,52 @@
"""Persistent storage for Box metadata and runtime state."""
from __future__ import annotations
import json
from pathlib import Path
from typing import Any
class BoxStorage:
def __init__(self, base_dir: str | None = None) -> None:
default_dir = Path(__file__).resolve().parents[1] / "data"
self._base_dir = Path(base_dir) if base_dir else default_dir
self._box_path = self._base_dir / "box.json"
self._state_path = self._base_dir / "state.json"
self._media_dir = self._base_dir / "media"
@property
def base_dir(self) -> Path:
return self._base_dir
@property
def media_dir(self) -> Path:
return self._media_dir
@property
def box_path(self) -> Path:
return self._box_path
@property
def state_path(self) -> Path:
return self._state_path
def ensure_layout(self) -> None:
self._base_dir.mkdir(parents=True, exist_ok=True)
self._media_dir.mkdir(parents=True, exist_ok=True)
def load_box_meta(self) -> dict[str, Any]:
if not self._box_path.exists():
return {}
return json.loads(self._box_path.read_text(encoding="utf-8"))
def save_box_meta(self, data: dict[str, Any]) -> None:
self._box_path.write_text(json.dumps(data, indent=2), encoding="utf-8")
def load_state(self) -> dict[str, Any]:
if not self._state_path.exists():
return {}
return json.loads(self._state_path.read_text(encoding="utf-8"))
def save_state(self, data: dict[str, Any]) -> None:
self._state_path.write_text(json.dumps(data, indent=2), encoding="utf-8")
+34
View File
@@ -0,0 +1,34 @@
"""Box metadata storage (app-level, within box/data)."""
from __future__ import annotations
import json
from pathlib import Path
from typing import Any
from core.identity import generate_box_id
class BoxStore:
def __init__(self, base_dir: Path) -> None:
self._base_dir = base_dir
self._path = self._base_dir / "box.json"
@property
def path(self) -> Path:
return self._path
def load(self) -> dict[str, Any]:
if not self._path.exists():
return {}
return json.loads(self._path.read_text(encoding="utf-8"))
def save(self, data: dict[str, Any]) -> None:
self._path.write_text(json.dumps(data, indent=2), encoding="utf-8")
def ensure_box_id(self) -> str:
data = self.load()
if "box_id" not in data:
data["box_id"] = generate_box_id()
self.save(data)
return str(data["box_id"])
+21
View File
@@ -0,0 +1,21 @@
"""JSON file storage placeholder for Phase 1a."""
from __future__ import annotations
import json
from pathlib import Path
from storage.storage import Storage
class JsonStorage(Storage):
def __init__(self, path: str) -> None:
self._path = Path(path)
def load_config(self) -> dict:
if not self._path.exists():
return {}
return json.loads(self._path.read_text(encoding="utf-8"))
def save_config(self, config: dict) -> None:
self._path.write_text(json.dumps(config, indent=2), encoding="utf-8")
+98
View File
@@ -0,0 +1,98 @@
"""Encrypted secret storage for sensitive Box data (app-level)."""
from __future__ import annotations
import base64
import json
from hashlib import pbkdf2_hmac
from pathlib import Path
from typing import Any
from cryptography.fernet import Fernet, InvalidToken
STATIC_SALT = b"klangkiste-static-salt-v1"
KDF_ITERATIONS = 200_000
class SecretStore:
def __init__(self, base_dir: Path, box_id: str) -> None:
self._path = base_dir / "secrets.enc"
self._box_id = box_id
def load_secrets(self) -> dict[str, Any]:
if not self._path.exists():
return {}
token = self._path.read_bytes()
fernet = Fernet(self._derive_key())
try:
payload = fernet.decrypt(token)
except InvalidToken:
return {}
return json.loads(payload.decode("utf-8"))
def save_secrets(self, data: dict[str, Any]) -> None:
fernet = Fernet(self._derive_key())
payload = json.dumps(data, indent=2).encode("utf-8")
token = fernet.encrypt(payload)
self._path.write_bytes(token)
def ensure_secret_seed(self) -> str:
data = self.load_secrets()
seed = data.get("secret_seed")
if isinstance(seed, str) and seed:
return seed
seed_value = self._generate_seed()
data["secret_seed"] = seed_value
self.save_secrets(data)
return seed_value
def get_secret_seed(self) -> str | None:
data = self.load_secrets()
seed = data.get("secret_seed")
if isinstance(seed, str) and seed:
return seed
return None
def save_api_token(self, token: str) -> None:
data = self.load_secrets()
data["api_token"] = token
self.save_secrets(data)
def get_api_token(self) -> str | None:
data = self.load_secrets()
token = data.get("api_token")
if isinstance(token, str) and token:
return token
return None
def clear_api_token(self) -> None:
data = self.load_secrets()
if "api_token" in data:
data.pop("api_token")
self.save_secrets(data)
def clear_wifi_secrets(self) -> None:
data = self.load_secrets()
if "wifi_profiles" in data:
data.pop("wifi_profiles")
self.save_secrets(data)
def clear_all(self) -> None:
if self._path.exists():
self._path.unlink()
def _derive_key(self) -> bytes:
raw = pbkdf2_hmac(
"sha256",
self._box_id.encode("utf-8"),
STATIC_SALT,
KDF_ITERATIONS,
dklen=32,
)
return base64.urlsafe_b64encode(raw)
@staticmethod
def _generate_seed() -> str:
import secrets
return secrets.token_hex(32)
+57
View File
@@ -0,0 +1,57 @@
"""Encrypted secret storage for sensitive Box data."""
from __future__ import annotations
import base64
import json
from hashlib import pbkdf2_hmac
from pathlib import Path
from typing import Any
from cryptography.fernet import Fernet, InvalidToken
STATIC_SALT = b"klangkiste-static-salt-v1"
KDF_ITERATIONS = 200_000
class SecretsStore:
def __init__(self, base_dir: Path, box_id: str) -> None:
self._path = base_dir / "secrets.enc"
self._box_id = box_id
def load_secrets(self) -> dict[str, Any]:
if not self._path.exists():
return {}
token = self._path.read_bytes()
fernet = Fernet(self._derive_key())
try:
payload = fernet.decrypt(token)
except InvalidToken:
return {}
return json.loads(payload.decode("utf-8"))
def save_secrets(self, data: dict[str, Any]) -> None:
fernet = Fernet(self._derive_key())
payload = json.dumps(data, indent=2).encode("utf-8")
token = fernet.encrypt(payload)
self._path.write_bytes(token)
def clear_wifi_secrets(self) -> None:
data = self.load_secrets()
if "wifi" in data:
data.pop("wifi")
self.save_secrets(data)
def clear_all(self) -> None:
if self._path.exists():
self._path.unlink()
def _derive_key(self) -> bytes:
raw = pbkdf2_hmac(
"sha256",
self._box_id.encode("utf-8"),
STATIC_SALT,
KDF_ITERATIONS,
dklen=32,
)
return base64.urlsafe_b64encode(raw)
+24
View File
@@ -0,0 +1,24 @@
"""Runtime state storage (resume, wifi state)."""
from __future__ import annotations
import json
from pathlib import Path
from typing import Any
class StateStore:
def __init__(self, base_dir: Path) -> None:
self._path = base_dir / "state.json"
@property
def path(self) -> Path:
return self._path
def load(self) -> dict[str, Any]:
if not self._path.exists():
return {}
return json.loads(self._path.read_text(encoding="utf-8"))
def save(self, data: dict[str, Any]) -> None:
self._path.write_text(json.dumps(data, indent=2), encoding="utf-8")
+13
View File
@@ -0,0 +1,13 @@
"""Storage interface for Box configuration and state."""
from __future__ import annotations
from typing import Protocol
class Storage(Protocol):
def load_config(self) -> dict:
raise NotImplementedError
def save_config(self, config: dict) -> None:
raise NotImplementedError