Skip to content

Commit 12b7cdd

Browse files
committed
fix: enable unsafe cookie jar for IP-based qBittorrent hosts
aiohttp rejects session cookies by default when the host is an IP literal. Detect whether QBITTORRENT_HOST is an IP address at startup and, if so, create the ClientSession with CookieJar(unsafe=True). Hostname-based connections are unaffected. Made-with: Cursor
1 parent ec2a2c0 commit 12b7cdd

1 file changed

Lines changed: 28 additions & 3 deletions

File tree

qsticky.py

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import logging
44
import aiohttp
55
import asyncio
6+
import ipaddress
67
import signal
78
import ssl
89
from typing import Optional, Dict, Any
@@ -98,6 +99,9 @@ def __init__(self):
9899
self.last_login_failed = False
99100
self.first_run = True
100101
self.last_known_port = None
102+
self.use_unsafe_qbit_cookie_jar = self._is_ip_address(
103+
self.settings.qbittorrent_host
104+
)
101105

102106
def _setup_logger(self) -> logging.Logger:
103107
logger = logging.getLogger("qsticky")
@@ -110,6 +114,19 @@ def _setup_logger(self) -> logging.Logger:
110114
logger.addHandler(handler)
111115
return logger
112116

117+
def _is_ip_address(self, host: str) -> bool:
118+
try:
119+
ipaddress.ip_address(host)
120+
return True
121+
except ValueError:
122+
return False
123+
124+
def _get_qbit_cookie_jar(self) -> Optional[aiohttp.CookieJar]:
125+
if not self.use_unsafe_qbit_cookie_jar:
126+
return None
127+
128+
return aiohttp.CookieJar(unsafe=True)
129+
113130
async def get_current_qbit_port(self) -> Optional[int]:
114131
self.logger.debug("Retrieving current qBittorrent port")
115132
try:
@@ -151,7 +168,11 @@ async def _init_session(self) -> None:
151168
self.logger.debug("SSL verification enabled")
152169

153170
connector = aiohttp.TCPConnector(ssl=ssl_context)
154-
self.session = aiohttp.ClientSession(timeout=timeout, connector=connector)
171+
self.session = aiohttp.ClientSession(
172+
timeout=timeout,
173+
connector=connector,
174+
cookie_jar=self._get_qbit_cookie_jar()
175+
)
155176
self.logger.debug("Session initialized with timeouts")
156177

157178
async def _login(self) -> bool:
@@ -293,7 +314,11 @@ async def handle_port_change(self) -> None:
293314
ssl_context.verify_mode = ssl.CERT_NONE
294315

295316
connector = aiohttp.TCPConnector(ssl=ssl_context)
296-
async with aiohttp.ClientSession(timeout=ClientTimeout(total=30), connector=connector) as session:
317+
async with aiohttp.ClientSession(
318+
timeout=ClientTimeout(total=30),
319+
connector=connector,
320+
cookie_jar=self._get_qbit_cookie_jar()
321+
) as session:
297322
self.session = session
298323
try:
299324
new_port = await self._get_forwarded_port()
@@ -473,4 +498,4 @@ async def main() -> None:
473498
await manager.cleanup()
474499

475500
if __name__ == "__main__":
476-
asyncio.run(main())
501+
asyncio.run(main())

0 commit comments

Comments
 (0)