Skip to content

Commit

Permalink
Avoid infinite recursion when client is banned
Browse files Browse the repository at this point in the history
  • Loading branch information
rmartin16 committed Nov 16, 2024
1 parent 60b4914 commit 29c7be6
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 5 deletions.
13 changes: 10 additions & 3 deletions src/qbittorrentapi/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@

from requests import Response

from qbittorrentapi import Version
from qbittorrentapi._version_support import Version
from qbittorrentapi.definitions import APIKwargsT, APINames, ClientCache
from qbittorrentapi.exceptions import LoginFailed, UnsupportedQbittorrentVersion
from qbittorrentapi.exceptions import (
LoginFailed,
UnsupportedQbittorrentVersion,
)
from qbittorrentapi.request import Request

if TYPE_CHECKING:
Expand Down Expand Up @@ -132,7 +135,11 @@ def _session_cookie(self, cookie_name: str = "SID") -> str | None:

def auth_log_out(self, **kwargs: APIKwargsT) -> None:
"""End session with qBittorrent."""
self._post(_name=APINames.Authorization, _method="logout", **kwargs)
# Originally, if log out failed authentication, the client would re-authenticate
# and then log out of that session. With the change to avoid retrying failed
# auth calls, only attempt to log out if the current authentication is valid.
if self.is_logged_in:
self._post(_name=APINames.Authorization, _method="logout", **kwargs)

def __enter__(self) -> Client:
self.auth_log_in()
Expand Down
5 changes: 5 additions & 0 deletions src/qbittorrentapi/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,11 @@ def _auth_request(
**kwargs,
)
except HTTP403Error:
# Do not retry auth endpoints for 403. If an auth endpoint is returning
# 403, then trying again won't work because it is likely the credentials
# are no longer valid. Furthermore, it leads to infinite recursion.
if api_namespace == APINames.Authorization:
raise
logger.debug("Login may have expired...attempting new login")
self.auth_log_in( # type: ignore[attr-defined]
requests_args=requests_args,
Expand Down
3 changes: 1 addition & 2 deletions tests/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,8 @@ def test_is_logged_in_bad_client():
client.auth_log_in()
assert client.is_logged_in is False

with pytest.raises(APIConnectionError):
client.auth_log_out()
assert client.is_logged_in is False
client.auth_log_out() # does nothing if not logged in


def test_session_cookie(app_version):
Expand Down
18 changes: 18 additions & 0 deletions tests/test_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from qbittorrentapi import APINames, Client, exceptions
from qbittorrentapi._version_support import v
from qbittorrentapi.definitions import Dictionary, List
from qbittorrentapi.exceptions import Forbidden403Error
from qbittorrentapi.request import Request
from qbittorrentapi.torrents import TorrentDictionary, TorrentInfoList
from tests.conftest import IS_QBT_DEV
Expand Down Expand Up @@ -65,6 +66,23 @@ def test_log_in_via_auth():
client_bad.auth_log_in(username="asdf", password="asdfasdf")


def test_forbidden_when_banned(client, monkeypatch):
monkeypatch.setattr(
client,
"_request_manager",
MagicMock(
side_effect=Forbidden403Error,
spec=client._request_manager,
),
)

with pytest.raises(Forbidden403Error):
client.auth.log_in()

with pytest.raises(Forbidden403Error):
_ = client.app.version


@pytest.mark.parametrize(
"hostname",
(
Expand Down

0 comments on commit 29c7be6

Please sign in to comment.