新增设备身份管理、认证限流、并发通道、Webhook路由、RBAC权限控制、SSE/轮询降级等全套网关通道功能,包含: 1. 设备身份生成与签名验证 2. 设备令牌认证与速率限制 3. 内存+数据库双重设备注册表 4. 并发通道限流管理 5. Webhook安全处理与路由 6. RBAC权限校验系统 7. OpenAI API兼容适配层 8. Tailscale认证支持 9. HTTP轮询降级机制
69 lines
2.1 KiB
Python
69 lines
2.1 KiB
Python
import hashlib
|
|
import logging
|
|
|
|
from cryptography.hazmat.primitives import serialization
|
|
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
DEVICE_ID_HEX_LENGTH = 16
|
|
|
|
|
|
def generate_device_identity() -> tuple[str, str, str]:
|
|
"""生成 Ed25519 设备身份。
|
|
|
|
Returns:
|
|
(device_id, public_key_pem, private_key_pem)
|
|
"""
|
|
private_key = Ed25519PrivateKey.generate()
|
|
public_key = private_key.public_key()
|
|
|
|
public_key_pem = public_key.public_bytes(
|
|
encoding=serialization.Encoding.PEM,
|
|
format=serialization.PublicFormat.SubjectPublicKeyInfo,
|
|
).decode("utf-8")
|
|
|
|
private_key_pem = private_key.private_bytes(
|
|
encoding=serialization.Encoding.PEM,
|
|
format=serialization.PrivateFormat.PKCS8,
|
|
encryption_algorithm=serialization.BestAvailableEncryption(b"yuxi-device-key"),
|
|
).decode("utf-8")
|
|
|
|
device_id = _derive_device_id_from_key(public_key)
|
|
|
|
logger.info("Generated device identity: device_id=%s", device_id)
|
|
return device_id, public_key_pem, private_key_pem
|
|
|
|
|
|
def derive_device_id(public_key_pem: str) -> str:
|
|
public_key = serialization.load_pem_public_key(public_key_pem.encode("utf-8"))
|
|
return _derive_device_id_from_key(public_key)
|
|
|
|
|
|
_PRIVATE_KEY_PASSWORD = b"yuxi-device-key"
|
|
|
|
|
|
def sign_challenge(private_key_pem: str, challenge: bytes) -> bytes:
|
|
private_key = serialization.load_pem_private_key(
|
|
private_key_pem.encode("utf-8"),
|
|
password=_PRIVATE_KEY_PASSWORD,
|
|
)
|
|
return private_key.sign(challenge)
|
|
|
|
|
|
def verify_signature(public_key_pem: str, challenge: bytes, signature: bytes) -> bool:
|
|
try:
|
|
public_key = serialization.load_pem_public_key(public_key_pem.encode("utf-8"))
|
|
public_key.verify(signature, challenge)
|
|
return True
|
|
except Exception:
|
|
return False
|
|
|
|
|
|
def _derive_device_id_from_key(public_key) -> str:
|
|
public_key_raw = public_key.public_bytes(
|
|
encoding=serialization.Encoding.Raw,
|
|
format=serialization.PublicFormat.Raw,
|
|
)
|
|
return hashlib.sha256(public_key_raw).hexdigest()[:DEVICE_ID_HEX_LENGTH]
|