zcbot/core/external_systems/crypto.py

53 lines
1.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""外部系统凭据列加密。
与早期微信绑定不同,这里没有明文降级:未配置 master key 时拒绝创建和调用。
"""
from __future__ import annotations
import base64
import hashlib
import os
from cryptography.fernet import Fernet, InvalidToken
_PREFIX = "v1:"
_ENV = "ZCBOT_CREDENTIAL_MASTER_KEY"
def configured() -> bool:
return len(os.getenv(_ENV, "").strip()) >= 32
def _fernet() -> Fernet:
raw = os.getenv(_ENV, "").strip()
if not raw:
raise RuntimeError(f"{_ENV} 未配置,不能保存或使用外部系统凭据")
if len(raw) < 32:
raise RuntimeError(f"{_ENV} 至少需要 32 个字符")
digest = hashlib.sha256(raw.encode("utf-8")).digest()
return Fernet(base64.urlsafe_b64encode(digest))
def encrypt_secret(value: str) -> str:
if not isinstance(value, str) or not value:
raise ValueError("credential value must be a non-empty string")
return _PREFIX + _fernet().encrypt(value.encode("utf-8")).decode("ascii")
def decrypt_secret(value: str) -> str:
if not isinstance(value, str) or not value.startswith(_PREFIX):
raise RuntimeError("外部系统凭据格式无效")
try:
return _fernet().decrypt(value[len(_PREFIX):].encode("ascii")).decode("utf-8")
except InvalidToken as exc:
raise RuntimeError("外部系统凭据无法解密master key 可能已变化") from exc
def mask_username(username: str) -> str:
username = (username or "").strip()
if not username:
return "***"
if len(username) <= 2:
return username[0] + "*"
return username[:2] + "***" + username[-1:]