""" 客户端配置接口(客户端使用) 已调整为 POST,并使用与 /api/keys/public 相同的握手加密格式返回: 返回结构为 {"code":200,"msg":"成功","data":{"encrypted_key": "...", "encrypted_data": "...", "signature": "...", "timestamp": ..., "nonce": "..." }} 客户端需在请求中提供 Base64 的 aes_key(32 bytes)、timestamp、nonce。 """ from fastapi import APIRouter, Depends from pydantic import BaseModel from sqlalchemy.orm import Session import json import base64 import secrets from app.database import get_db from app.models.system_config import SystemConfig from app.utils.timestamp_validator import TimestampValidator from app.config import settings # reuse AES helper and signature generator from keys module from app.api.client.keys import _aes_encrypt, _generate_signature router = APIRouter() class ConfigsRequest(BaseModel): aes_key: str timestamp: int nonce: str @router.post("") async def get_client_configs(request: ConfigsRequest, db: Session = Depends(get_db)): """获取客户端配置(供客户端使用),使用 keys/public 相同的加密握手协议""" try: # 1. 验证时间戳 is_valid, err_msg = TimestampValidator.validate_timestamp(request.timestamp, db) if not is_valid: return { "code": 400, "msg": f"时间戳验证失败: {err_msg}", "timestamp": TimestampValidator.generate_timestamp() } # 2. 验证并解码客户端提供的 AES 密钥 try: client_aes_key = base64.b64decode(request.aes_key) if len(client_aes_key) != 32: raise ValueError("AES密钥长度无效") except Exception as e: return { "code": 400, "msg": "无效的AES密钥格式", "timestamp": TimestampValidator.generate_timestamp() } # 3. 准备要返回的客户端配置数据 client_configs = { "api_timeout_seconds": SystemConfig.get_config_value('api_timeout_seconds', 30), "client_heartbeat_interval_seconds": SystemConfig.get_config_value('client_heartbeat_interval_seconds', 30), "max_heartbeat_failures": SystemConfig.get_config_value('max_heartbeat_failures', 10), "max_network_failures": SystemConfig.get_config_value('max_network_failures', 15), } # 4. 使用随机 response AES 密钥/IV 加密实际 payload response_aes_key = secrets.token_bytes(32) response_iv = secrets.token_bytes(16) data_json = json.dumps(client_configs, ensure_ascii=False) encrypted_data = _aes_encrypt(data_json.encode('utf-8'), response_aes_key, response_iv) # 5. 使用客户端提供的 AES 密钥加密 response_aes_key + iv(便于客户端解密) key_iv_combined = response_aes_key + response_iv encrypted_key_iv = _aes_encrypt(key_iv_combined, client_aes_key, client_aes_key[16:32]) # 6. 生成签名(timestamp:nonce:base64(encrypted_data)) timestamp = TimestampValidator.generate_timestamp() signature_data = f"{timestamp}:{request.nonce}:{base64.b64encode(encrypted_data).decode()}" signature = _generate_signature(signature_data, settings.SECRET_KEY) # 7. 返回与 /api/keys/public 相同的格式 response = { "code": 200, "msg": "成功", "data": { "encrypted_key": base64.b64encode(encrypted_key_iv).decode(), "encrypted_data": base64.b64encode(encrypted_data).decode(), "signature": signature, "timestamp": timestamp, "nonce": request.nonce } } return response except Exception as e: return { "code": 500, "msg": "系统异常,请稍后重试;若持续发生请联系客服", "timestamp": TimestampValidator.generate_timestamp() }