Refuse OPDS logins when CWA accepts every password

A CWA with anonymous browsing can answer an OPDS request whatever the
password, so each password logged a user in to Bindery. Bindery now
tests CWA with a login that cannot exist, and refuses OPDS logins if
CWA accepts it. A login check no longer shares the session of the
account of Bindery. The CWA account stays optional for a CWA that asks
for no login, and a missing account now gets its own message.
This commit is contained in:
tim
2026-10-02 23:37:33 +02:00
parent 869e56eaf0
commit 9196dd75a8
8 changed files with 96 additions and 8 deletions
+32 -1
View File
@@ -1,13 +1,15 @@
"""The OPDS client, the book finder, the login check, the ingest folder and the epub reader."""
import json
import time
from unittest.mock import Mock
import pytest
from fake_cwa import FakeBook, FakeCwa
from test_build import URL, chapters, metahtml
from bindery import fff
from bindery.cwa import BookFinder, CwaClient, CwaError, plain_title, search_text, title_rank
from bindery.cwa import LOGIN_TEST_SECONDS, BookFinder, CwaClient, CwaError, plain_title, search_text, title_rank
from bindery.epub import epub_metadata, epub_urls
from bindery.ingest import MAX_NAME_LENGTH, IngestError, IngestFolder
@@ -63,6 +65,35 @@ def test_wrong_password_and_missing_address(fake):
CwaClient("").search("x")
def test_cwa_that_needs_no_login_works_without_an_account(fake):
fake.anonymous = True
open_client = CwaClient(fake.url)
assert [b.id for b in open_client.search("Another")] == [3]
assert open_client.get_book("uuid-2")["id"] == 2
fake.anonymous = False
with pytest.raises(CwaError, match="CWA asks for a login. Set CWA_USERNAME and CWA_PASSWORD."):
open_client.search("Test Story")
def test_a_login_check_does_not_use_the_session_of_the_account(fake, monkeypatch):
c = client(fake)
monkeypatch.setattr(c.session, "get", Mock(side_effect=AssertionError("The login check used the session")))
assert c.login_ok("bindery", "secret")
assert not c.login_ok("bindery", "wrong")
def test_the_test_of_the_logins_of_cwa_is_kept_for_a_time(fake, monkeypatch):
c = client(fake)
assert not c.accepts_any_login()
fake.anonymous = True
assert not c.accepts_any_login() # the last test still counts
assert len([r for r in fake.requests if r == "/opds"]) == 1
clock = time.monotonic()
monkeypatch.setattr(time, "monotonic", lambda: clock + LOGIN_TEST_SECONDS + 1)
assert c.accepts_any_login()
assert CwaClient(fake.url).accepts_any_login()
def test_get_book(fake):
c = client(fake)
assert c.get_book("uuid-2") == {