新增独立 xiaobai-datahub 服务(SQLite WAL、Tushare 盘后发布、/v1 契约和管理后台),不改现站页面与数据链路。 Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: multica-agent <github@multica.ai>
43 lines
1.4 KiB
Python
43 lines
1.4 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
from typing import Any
|
|
|
|
from cryptography.fernet import Fernet, InvalidToken
|
|
|
|
|
|
class SecretVault:
|
|
def __init__(self, key: str) -> None:
|
|
try:
|
|
self._fernet = Fernet(key.encode("ascii"))
|
|
except (ValueError, TypeError) as exc:
|
|
raise ValueError("DATAHUB_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("凭据无法解密,请检查 DATAHUB_ENCRYPTION_KEY。") from exc
|
|
if not isinstance(payload, dict):
|
|
raise ValueError("凭据格式无效。")
|
|
return payload
|
|
|
|
|
|
def mask_secret(value: str, last_n: int = 4) -> str:
|
|
text = str(value or "")
|
|
if not text:
|
|
return ""
|
|
if len(text) <= last_n:
|
|
return "*" * len(text)
|
|
return ("*" * max(4, len(text) - last_n)) + text[-last_n:]
|