migration: preserve startup accounts and system slice

This commit is contained in:
leefer
2026-07-31 00:42:06 +08:00
parent e4a9b2e647
commit 982af4ba92
32 changed files with 6675 additions and 6321 deletions
+2 -70
View File
@@ -1,71 +1,3 @@
from __future__ import annotations
"""Compatibility imports for the preserved account security API."""
import base64
import hashlib
import hmac
import json
import os
from typing import Any
from cryptography.fernet import Fernet, InvalidToken
PASSWORD_SCRYPT_N = 2**14
PASSWORD_SCRYPT_R = 8
PASSWORD_SCRYPT_P = 1
class SecretVault:
def __init__(self, key: str) -> None:
try:
self._fernet = Fernet(key.encode("ascii"))
except (ValueError, TypeError) as exc:
raise ValueError("APP_ENCRYPTION_KEY 格式无效。") from exc
@staticmethod
def generate_key() -> str:
return Fernet.generate_key().decode("ascii")
def encrypt_json(self, payload: dict[str, Any]) -> str:
raw = json.dumps(payload, ensure_ascii=False, separators=(",", ":")).encode("utf-8")
return self._fernet.encrypt(raw).decode("ascii")
def decrypt_json(self, token: str) -> dict[str, Any]:
if not token:
return {}
try:
payload = json.loads(self._fernet.decrypt(token.encode("ascii")).decode("utf-8"))
except (InvalidToken, UnicodeDecodeError, json.JSONDecodeError) as exc:
raise ValueError("账号加密数据无法解密,请检查 APP_ENCRYPTION_KEY。") from exc
if not isinstance(payload, dict):
raise ValueError("账号加密数据格式无效。")
return payload
def hash_password(password: str, salt: bytes | None = None) -> tuple[str, str]:
raw_salt = salt or os.urandom(16)
digest = hashlib.scrypt(
password.encode("utf-8"),
salt=raw_salt,
n=PASSWORD_SCRYPT_N,
r=PASSWORD_SCRYPT_R,
p=PASSWORD_SCRYPT_P,
dklen=32,
)
return (
base64.urlsafe_b64encode(raw_salt).decode("ascii"),
base64.urlsafe_b64encode(digest).decode("ascii"),
)
def verify_password(password: str, salt_text: str, expected_hash: str) -> bool:
try:
salt = base64.urlsafe_b64decode(salt_text.encode("ascii"))
_, actual_hash = hash_password(password, salt)
except (ValueError, TypeError):
return False
return hmac.compare_digest(actual_hash, expected_hash)
def token_hash(token: str) -> str:
return hashlib.sha256(token.encode("utf-8")).hexdigest()
from backend.features.accounts.security import * # noqa: F401,F403