diff --git a/package.v2.json b/package.v2.json index 6ab3147..29edbc2 100644 --- a/package.v2.json +++ b/package.v2.json @@ -541,11 +541,12 @@ "name": "Bug反馈", "description": "自动上报异常,协助开发者发现和解决问题。", "labels": "开发", - "version": "1.1", + "version": "1.2", "icon": "Alist_encrypt_A.png", "author": "jxxghp", "level": 1, "history": { + "v1.2": "优化上报信息量", "v1.1": "加强脱敏处理" } } diff --git a/plugins.v2/bugreporter/__init__.py b/plugins.v2/bugreporter/__init__.py index b21c371..1f72c8d 100644 --- a/plugins.v2/bugreporter/__init__.py +++ b/plugins.v2/bugreporter/__init__.py @@ -1,10 +1,13 @@ import re +import socket +import ssl from typing import Any, Dict from typing import List, Tuple from urllib.parse import urlparse, parse_qs, urlencode, urlunparse import sentry_sdk from app.plugins import _PluginBase +from version import APP_VERSION class SentrySanitizer: @@ -13,7 +16,9 @@ class SentrySanitizer: "password", "passwd", "pwd", "secret", "token", "access_token", "refresh_token", "authorization", "api_key", "apikey", - "cookie", "set-cookie", "passkey" + "cookie", "set-cookie", "passkey", + "key", "credential", "auth", "login", "user", "username", + "email", "phone", "address", "ip", "host", "domain" } # 匹配包含敏感关键词的正则 @@ -21,6 +26,26 @@ class SentrySanitizer: "|".join(re.escape(key) for key in SENSITIVE_KEYS), re.IGNORECASE ) + # 网络连接错误类异常(不上报) + NETWORK_ERRORS = { + "ConnectionError", "ConnectionRefusedError", "ConnectionAbortedError", + "ConnectionResetError", "TimeoutError", "socket.timeout", "socket.error", + "ssl.SSLError", "ssl.SSLCertVerificationError", "ssl.SSLWantReadError", + "ssl.SSLWantWriteError", "ssl.SSLZeroReturnError", "ssl.SSLSyscallError", + "urllib.error.URLError", "urllib.error.HTTPError", "requests.exceptions.ConnectionError", + "requests.exceptions.Timeout", "requests.exceptions.ConnectTimeout", + "requests.exceptions.ReadTimeout", "requests.exceptions.SSLError", + "aiohttp.ClientConnectionError", "aiohttp.ClientTimeout", "aiohttp.ServerTimeoutError", + "aiohttp.ServerDisconnectedError", "aiohttp.ClientOSError" + } + + # 网络连接错误关键词 + NETWORK_ERROR_KEYWORDS = [ + "connection", "timeout", "network", "dns", "ssl", "certificate", + "refused", "reset", "aborted", "unreachable", "no route to host", + "name or service not known", "temporary failure", "network is unreachable" + ] + @classmethod def scrub_dict(cls, data: Dict[str, Any]) -> Dict[str, Any]: """ @@ -59,11 +84,44 @@ class SentrySanitizer: print(str(err)) return url + @classmethod + def is_network_error(cls, event) -> bool: + """ + 判断是否为网络连接错误类异常 + """ + # 检查异常类型 + if "exception" in event: + for exc in event["exception"].get("values", []): + if "type" in exc: + exc_type = exc["type"] + if exc_type in cls.NETWORK_ERRORS: + return True + + # 检查异常消息是否包含网络错误关键词 + if "value" in exc: + exc_value = exc["value"].lower() + for keyword in cls.NETWORK_ERROR_KEYWORDS: + if keyword in exc_value: + return True + + # 检查日志消息 + if "message" in event: + message = event["message"].lower() + for keyword in cls.NETWORK_ERROR_KEYWORDS: + if keyword in message: + return True + + return False + @classmethod def before_send(cls, event, hint): """ - 在发送到 Sentry 之前脱敏 + 在发送到 Sentry 之前脱敏和过滤 """ + # 如果是网络连接错误,直接返回 None 不上报 + if cls.is_network_error(event): + return None + # 处理 request 数据 request = event.get("request", {}) if "url" in request: @@ -88,6 +146,18 @@ class SentrySanitizer: for exc in event["exception"].get("values", []): if "value" in exc and cls.SENSITIVE_PATTERN.search(exc["value"]): exc["value"] = "[Filtered Exception Message]" + + # 清理异常堆栈中的敏感信息 + if "stacktrace" in exc and "frames" in exc["stacktrace"]: + for frame in exc["stacktrace"]["frames"]: + if "vars" in frame: + frame["vars"] = cls.scrub_dict(frame["vars"]) + if "context_line" in frame and cls.SENSITIVE_PATTERN.search(frame["context_line"]): + frame["context_line"] = "[Filtered]" + + # 清理消息中的敏感信息 + if "message" in event and cls.SENSITIVE_PATTERN.search(event["message"]): + event["message"] = "[Filtered Message]" return event @@ -100,7 +170,7 @@ class BugReporter(_PluginBase): # 插件图标 plugin_icon = "Alist_encrypt_A.png" # 插件版本 - plugin_version = "1.1" + plugin_version = "1.2" # 插件作者 plugin_author = "jxxghp" # 作者主页 @@ -119,6 +189,7 @@ class BugReporter(_PluginBase): if self._enable: sentry_sdk.init("https://88da01ad33b4423cb0380620de53efa8@glitchtip.movie-pilot.org/1", before_send=SentrySanitizer.before_send, + release=APP_VERSION, send_default_pii=False) @staticmethod @@ -168,7 +239,7 @@ class BugReporter(_PluginBase): 'props': { 'type': 'warning', 'variant': 'tonal', - 'text': '注意:开启插件即代表你同意将部分异常信息自动发送给开发者,以帮助改进软件;如果你不希望自动发送任何数据,请关闭或卸载此插件;仅上报系统异常信息,不会包含任何个人隐私信息或敏感数据;异常信息采集为使用开源项目解决方案:GlitchTip。', + 'text': '注意:开启插件即代表你同意将部分异常信息自动发送给开发者,以帮助改进软件;如果你不希望自动发送任何数据,请关闭或卸载此插件;仅上报系统异常信息,不会包含任何个人隐私信息或敏感数据;网络连接错误类异常不会上报;异常信息采集为使用开源项目解决方案:GlitchTip。', } } ]