1 line
5.1 KiB
JSON
1 line
5.1 KiB
JSON
{"repo": "chinrain/api-conversion", "files": {"src/utils/security.py": {"3eb78f5a65837cefb67b6b3cc11927ba3e58a7bd": {"t": 1785674428.3779325, "n": 4234, "h": "faea5cb1faba58ad", "c": "\"\"\"\n安全工具函数\n提供敏感信息掩码和安全日志功能\n\"\"\"\nimport json\nimport re\nfrom typing import Any, Dict, Union\nfrom copy import deepcopy\n\n\ndef mask_api_key(api_key: str, prefix_length: int = 4) -> str:\n \"\"\"\n 安全地掩码API key,只显示前几个字符,其余用星号替代\n \n Args:\n api_key: 原始API key\n prefix_length: 显示的前缀长度,默认4个字符\n \n Returns:\n 掩码后的API key,格式如: sk-1234****\n \"\"\"\n if not api_key:\n return \"***empty***\"\n \n if len(api_key) <= prefix_length:\n return \"*\" * len(api_key)\n \n # 显示前几位和足够的星号\n masked_length = max(8, len(api_key) - prefix_length) # 至少8个星号\n return f\"{api_key[:prefix_length]}{'*' * masked_length}\"\n\n\ndef mask_sensitive_data(data: Union[Dict[str, Any], str], sensitive_keys: list = None) -> Union[Dict[str, Any], str]:\n \"\"\"\n 递归地掩码数据中的敏感信息\n \n Args:\n data: 要处理的数据(字典或字符串)\n sensitive_keys: 敏感字段名列表\n \n Returns:\n 掩码后的数据副本\n \"\"\"\n if sensitive_keys is None:\n sensitive_keys = [\n 'api_key', 'apikey', 'key', 'token', 'password', 'secret', \n 'authorization', 'auth', 'x-api-key', 'x-goog-api-key',\n 'bearer', 'access_token', 'refresh_token'\n ]\n \n if isinstance(data, str):\n # 如果是字符串,尝试解析为JSON\n try:\n parsed = json.loads(data)\n masked = mask_sensitive_data(parsed, sensitive_keys)\n return json.dumps(masked, ensure_ascii=False, indent=2)\n except (json.JSONDecodeError, TypeError):\n # 如果不是JSON,检查是否包含API key模式\n return _mask_string_patterns(data)\n \n elif isinstance(data, dict):\n # 深拷贝避免修改原始数据\n masked_data = deepcopy(data)\n \n for key, value in masked_data.items():\n key_lower = key.lower()\n \n # 检查是否是敏感字段\n if any(sensitive_key in key_lower for sensitive_key in sensitive_keys):\n if isinstance(value, str):\n masked_data[key] = mask_api_key(value)\n else:\n masked_data[key] = \"***masked***\"\n elif isinstance(value, (dict, list)):\n # 递归处理嵌套结构\n masked_data[key] = mask_sensitive_data(value, sensitive_keys)\n \n return masked_data\n \n elif isinstance(data, list):\n # 处理列表\n return [mask_sensitive_data(item, sensitive_keys) for item in data]\n \n else:\n # 其他类型直接返回\n return data\n\n\ndef _mask_string_patterns(text: str) -> str:\n \"\"\"\n 掩码字符串中的API key模式\n \"\"\"\n # 常见的API key模式\n patterns = [\n # OpenAI格式: sk-开头\n (r'sk-[a-zA-Z0-9]{48}', lambda m: mask_api_key(m.group())),\n # Anthropic格式: sk-ant-开头\n (r'sk-ant-[a-zA-Z0-9\\-_]{95}', lambda m: mask_api_key(m.group())),\n # Google格式: 39字符的字母数字\n (r'AIza[a-zA-Z0-9_\\-]{35}', lambda m: mask_api_key(m.group())),\n # Bearer token\n (r'Bearer\\s+[a-zA-Z0-9\\-_\\.]{20,}', lambda m: f\"Bearer {mask_api_key(m.group()[7:])}\"),\n # 通用长字符串(可能是key)\n (r'[a-zA-Z0-9\\-_]{32,}', lambda m: mask_api_key(m.group()) if len(m.group()) > 20 else m.group()),\n ]\n \n result = text\n for pattern, replacer in patterns:\n result = re.sub(pattern, replacer, result)\n \n return result\n\n\ndef safe_log_data(data: Any, max_length: int = 1000) -> str:\n \"\"\"\n 安全地格式化数据用于日志记录\n \n Args:\n data: 要记录的数据\n max_length: 最大长度限制\n \n Returns:\n 安全的日志字符串\n \"\"\"\n try:\n # 先掩码敏感信息\n masked_data = mask_sensitive_data(data)\n \n # 转换为字符串\n if isinstance(masked_data, (dict, list)):\n log_str = json.dumps(masked_data, ensure_ascii=False, indent=2)\n else:\n log_str = str(masked_data)\n \n # 限制长度\n if len(log_str) > max_length:\n log_str = log_str[:max_length] + \"...[truncated]\"\n \n return log_str\n \n except Exception as e:\n return f\"***log_error: {str(e)}***\"\n\n\ndef safe_log_request(request_data: Dict[str, Any]) -> str:\n \"\"\"\n 安全地记录请求数据\n \"\"\"\n return safe_log_data(request_data, max_length=2000)\n\n\ndef safe_log_response(response_data: Dict[str, Any]) -> str:\n \"\"\"\n 安全地记录响应数据\n \"\"\"\n return safe_log_data(response_data, max_length=1500)"}}}} |