oauth-cli-kit 0.1.5__tar.gz → 0.1.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oauth-cli-kit
3
- Version: 0.1.5
3
+ Version: 0.1.6
4
4
  Summary: Reusable OAuth 2.0 + PKCE helpers for CLI applications
5
5
  Author: nanobot contributors
6
6
  License: MIT
@@ -5,7 +5,7 @@ from __future__ import annotations
5
5
  import socket
6
6
  import threading
7
7
  import urllib.parse
8
- from http.server import BaseHTTPRequestHandler, HTTPServer
8
+ from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
9
9
  from typing import Any, Callable
10
10
 
11
11
  from oauth_cli_kit.constants import SUCCESS_HTML
@@ -17,13 +17,24 @@ class _OAuthHandler(BaseHTTPRequestHandler):
17
17
  server_version = "OAuthCliKit/1.0"
18
18
  protocol_version = "HTTP/1.1"
19
19
 
20
+ def _send_body(self, status: int, body: bytes, content_type: str = "text/plain; charset=utf-8") -> None:
21
+ self.close_connection = True
22
+ self.send_response(status)
23
+ self.send_header("Content-Type", content_type)
24
+ self.send_header("Content-Length", str(len(body)))
25
+ self.send_header("Connection", "close")
26
+ self.end_headers()
27
+ self.wfile.write(body)
28
+ try:
29
+ self.wfile.flush()
30
+ except Exception:
31
+ pass
32
+
20
33
  def do_GET(self) -> None: # noqa: N802
21
34
  try:
22
35
  url = urllib.parse.urlparse(self.path)
23
36
  if url.path != "/auth/callback":
24
- self.send_response(404)
25
- self.end_headers()
26
- self.wfile.write(b"Not found")
37
+ self._send_body(404, b"Not found")
27
38
  return
28
39
 
29
40
  qs = urllib.parse.parse_qs(url.query)
@@ -31,15 +42,11 @@ class _OAuthHandler(BaseHTTPRequestHandler):
31
42
  state = qs.get("state", [None])[0]
32
43
 
33
44
  if state != self.server.expected_state:
34
- self.send_response(400)
35
- self.end_headers()
36
- self.wfile.write(b"State mismatch")
45
+ self._send_body(400, b"State mismatch")
37
46
  return
38
47
 
39
48
  if not code:
40
- self.send_response(400)
41
- self.end_headers()
42
- self.wfile.write(b"Missing code")
49
+ self._send_body(400, b"Missing code")
43
50
  return
44
51
 
45
52
  self.server.code = code
@@ -49,30 +56,21 @@ class _OAuthHandler(BaseHTTPRequestHandler):
49
56
  except Exception:
50
57
  pass
51
58
  body = SUCCESS_HTML.encode("utf-8")
52
- self.send_response(200)
53
- self.send_header("Content-Type", "text/html; charset=utf-8")
54
- self.send_header("Content-Length", str(len(body)))
55
- self.send_header("Connection", "close")
56
- self.end_headers()
57
- self.wfile.write(body)
58
- try:
59
- self.wfile.flush()
60
- except Exception:
61
- pass
62
- self.close_connection = True
59
+ self._send_body(200, body, "text/html; charset=utf-8")
63
60
  except Exception:
64
- self.send_response(500)
65
- self.end_headers()
66
- self.wfile.write(b"Internal error")
61
+ self._send_body(500, b"Internal error")
67
62
 
68
63
  def log_message(self, format: str, *args: Any) -> None: # noqa: A003
69
64
  # Suppress default logs to avoid noisy output.
70
65
  return
71
66
 
72
67
 
73
- class _OAuthServer(HTTPServer):
68
+ class _OAuthServer(ThreadingHTTPServer):
74
69
  """OAuth callback server with state."""
75
70
 
71
+ daemon_threads = True
72
+ block_on_close = False
73
+
76
74
  def __init__(
77
75
  self,
78
76
  server_address: tuple[str, int],
File without changes
File without changes
File without changes