Files
dsh/server/dsh_sync/util.py
T

49 lines
1.4 KiB
Python

"""Small shared helpers: timestamps, hashing, semver, input validation."""
from __future__ import annotations
import hashlib
import re
from datetime import datetime, timezone
from pathlib import Path
PLUGIN_ID_RE = re.compile(r"^[a-z0-9][a-z0-9._-]{0,63}$")
VERSION_RE = re.compile(r"^[0-9A-Za-z][0-9A-Za-z.+-]{0,31}$")
SETTING_KEY_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$")
USERNAME_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$")
def now_iso() -> str:
return datetime.now(timezone.utc).isoformat(timespec="seconds")
def sha256_bytes(data: bytes) -> str:
return hashlib.sha256(data).hexdigest()
def sha256_text(text: str) -> str:
return hashlib.sha256(text.encode("utf-8")).hexdigest()
def sha256_file(path: Path) -> str:
h = hashlib.sha256()
with open(path, "rb") as f:
for chunk in iter(lambda: f.read(1 << 20), b""):
h.update(chunk)
return h.hexdigest()
def semver_tuple(version: str) -> tuple[int, int, int]:
"""Best-effort numeric compare key: '1.10.0-beta' -> (1, 10, 0)."""
parts: list[int] = []
for p in version.split("."):
digits = ""
for ch in p:
if ch.isdigit():
digits += ch
else:
break
parts.append(int(digits) if digits else 0)
while len(parts) < 3:
parts.append(0)
return tuple(parts[:3])