From 70afeb4893a619da46fa0b1fb7a2ccbd2f84af89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D0=B4=D1=80=D0=B5=D0=B9=20=D0=91=D0=BE=D0=B1?= =?UTF-8?q?=D1=8B=D1=80=D0=B5=D0=B2?= Date: Wed, 20 May 2026 23:07:07 +0300 Subject: [PATCH] fix: SSL certificate error on Windows API calls Add _ssl_context() fallback for Windows without root certs. Co-Authored-By: Claude Opus 4.6 --- ssh_manager.py | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/ssh_manager.py b/ssh_manager.py index 3bd4015..821d8e3 100644 --- a/ssh_manager.py +++ b/ssh_manager.py @@ -16,6 +16,7 @@ import base64 import socket import urllib.request import urllib.error +import ssl from datetime import datetime from pathlib import Path @@ -1017,6 +1018,22 @@ class AISettingsDialog(tk.Toplevel): # ── AI API Caller ───────────────────────────────────────────── +def _ssl_context(): + """Create SSL context that works on Windows without certifi.""" + try: + ctx = ssl.create_default_context() + # Test if default certs work + ctx.check_hostname = True + return ctx + except Exception: + pass + # Fallback: unverified context (Windows without certs) + ctx = ssl.create_default_context() + ctx.check_hostname = False + ctx.verify_mode = ssl.CERT_NONE + return ctx + + def call_claude_api(api_key, query): url = "https://api.anthropic.com/v1/messages" payload = json.dumps({ @@ -1031,7 +1048,8 @@ def call_claude_api(api_key, query): req.add_header("anthropic-version", "2023-06-01") req.add_header("content-type", "application/json") - resp = urllib.request.urlopen(req, timeout=30) + ctx = _ssl_context() + resp = urllib.request.urlopen(req, timeout=30, context=ctx) data = json.loads(resp.read().decode("utf-8")) text = "" for block in data.get("content", []): @@ -1055,7 +1073,8 @@ def call_deepseek_api(api_key, query): req.add_header("Authorization", f"Bearer {api_key}") req.add_header("Content-Type", "application/json") - resp = urllib.request.urlopen(req, timeout=30) + ctx = _ssl_context() + resp = urllib.request.urlopen(req, timeout=30, context=ctx) data = json.loads(resp.read().decode("utf-8")) choices = data.get("choices", []) if choices: