Files

1 line
5.1 KiB
JSON
Raw Permalink 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.
{"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)"}}}}