mail: robustes Decoding gegen unbekannte Charsets (x-unknown); OAuth-Token 30 Tage
- _safe_decode() faengt LookupError bei unbekannten/kaputten Mail-Charsets (z.B. 'x-unknown') ab, Fallback utf-8 -> latin-1. Verhindert Crash der Mail-Suche/Read bei einzelnen kaputt-kodierten Mails. - common.py: OAuth access_token Lifetime 24h -> 30 Tage (weniger Re-Auth in claude.ai) - .gitignore: *.before-* Backups ausschliessen Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,3 +4,4 @@ __pycache__/
|
||||
tokens.json
|
||||
config.json
|
||||
.active_tokens.json
|
||||
*.before-*
|
||||
|
||||
@@ -193,7 +193,7 @@ async def oauth_token(request: Request):
|
||||
return JSONResponse({"error": "unsupported_grant_type"}, status_code=400)
|
||||
|
||||
access_token = secrets.token_urlsafe(48)
|
||||
expires_in = 86400
|
||||
expires_in = 2592000 # 30 days
|
||||
tokens = _load_access_tokens()
|
||||
# Cleanup expired
|
||||
now = time.time()
|
||||
|
||||
+19
-4
@@ -46,6 +46,21 @@ mcp = FastMCP("Mail", stateless_http=True,
|
||||
transport_security={"enable_dns_rebinding_protection": False})
|
||||
|
||||
|
||||
def _safe_decode(payload, charset):
|
||||
"""Decode bytes robust gegen unbekannte/kaputte Charsets (z.B. 'x-unknown')."""
|
||||
if not isinstance(payload, bytes):
|
||||
return str(payload)
|
||||
for cs in (charset, "utf-8", "latin-1"):
|
||||
if not cs:
|
||||
continue
|
||||
try:
|
||||
return payload.decode(cs, errors="replace")
|
||||
except (LookupError, TypeError):
|
||||
continue
|
||||
# Letzter Fallback: latin-1 akzeptiert jedes Byte
|
||||
return payload.decode("latin-1", errors="replace")
|
||||
|
||||
|
||||
def _decode_hdr(raw):
|
||||
if not raw:
|
||||
return ""
|
||||
@@ -53,7 +68,7 @@ def _decode_hdr(raw):
|
||||
decoded = []
|
||||
for data, charset in parts:
|
||||
if isinstance(data, bytes):
|
||||
decoded.append(data.decode(charset or "utf-8", errors="replace"))
|
||||
decoded.append(_safe_decode(data, charset))
|
||||
else:
|
||||
decoded.append(str(data))
|
||||
return " ".join(decoded)
|
||||
@@ -65,16 +80,16 @@ def _get_body(msg):
|
||||
if part.get_content_type() == "text/plain":
|
||||
payload = part.get_payload(decode=True)
|
||||
if payload:
|
||||
return payload.decode(part.get_content_charset() or "utf-8", errors="replace")
|
||||
return _safe_decode(payload, part.get_content_charset())
|
||||
for part in msg.walk():
|
||||
if part.get_content_type() == "text/html":
|
||||
payload = part.get_payload(decode=True)
|
||||
if payload:
|
||||
return "[HTML] " + payload.decode(part.get_content_charset() or "utf-8", errors="replace")
|
||||
return "[HTML] " + _safe_decode(payload, part.get_content_charset())
|
||||
else:
|
||||
payload = msg.get_payload(decode=True)
|
||||
if payload:
|
||||
return payload.decode(msg.get_content_charset() or "utf-8", errors="replace")
|
||||
return _safe_decode(payload, msg.get_content_charset())
|
||||
return ""
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user