52 lines
1.5 KiB
Python
52 lines
1.5 KiB
Python
"""Factory signing public key loader (single source of truth)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import sys
|
|
from pathlib import Path
|
|
from typing import Iterable
|
|
|
|
|
|
_DEFAULT_RELATIVE_PATH = Path("keys") / "factory_signing" / "factory_signing_pubkey.pem"
|
|
|
|
def _iter_runtime_roots() -> Iterable[Path]:
|
|
exe_path = Path(sys.executable).resolve()
|
|
yield exe_path.parent
|
|
for parent in exe_path.parents:
|
|
if parent.suffix.lower() == ".app":
|
|
yield parent.parent
|
|
break
|
|
|
|
|
|
def _candidate_paths() -> Iterable[Path]:
|
|
env_path = os.getenv("FACTORY_SIGNING_PUBKEY_PATH")
|
|
if env_path:
|
|
yield Path(env_path).expanduser()
|
|
|
|
if getattr(sys, "frozen", False):
|
|
for root in _iter_runtime_roots():
|
|
yield root / _DEFAULT_RELATIVE_PATH
|
|
|
|
for parent in Path(__file__).resolve().parents:
|
|
yield parent / _DEFAULT_RELATIVE_PATH
|
|
|
|
|
|
def _load_public_key_pem() -> bytes:
|
|
for path in _candidate_paths():
|
|
if path.exists():
|
|
data = path.read_bytes()
|
|
try:
|
|
data.decode("ascii")
|
|
except UnicodeDecodeError as exc:
|
|
raise RuntimeError(f"Signing public key must be ASCII PEM: {path}") from exc
|
|
return data
|
|
raise RuntimeError(
|
|
"Factory signing public key not found. "
|
|
"Set FACTORY_SIGNING_PUBKEY_PATH or place "
|
|
f"{_DEFAULT_RELATIVE_PATH} next to the executable."
|
|
)
|
|
|
|
|
|
PUBLIC_KEY_PEM = _load_public_key_pem()
|