+ {% if request.state.single_user %} + {# COOKIE_SECURE=single_user: one shared store, no cookie, no isolation. #} +
+ {{ ico.i('key', 16) }} +

Single-user mode: everything is stored on the server without a session cookie, and anyone who can reach this app sees the same printers.

+
+ {% endif %} {% if request.state.ephemeral_session %} {# COOKIE_SECURE=false: the owner key is memory-only, so the session dies with the browser window. Say it before work is lost. #} diff --git a/tests/test_session.py b/tests/test_session.py index 7fbbc51..bc91277 100644 --- a/tests/test_session.py +++ b/tests/test_session.py @@ -268,3 +268,96 @@ def test_restore_also_issues_a_session_cookie_when_insecure(tmp_data_dir, monkey assert resp.status_code == 303 header = _set_cookie_header(resp) assert "Max-Age" not in header and "Expires" not in header + + +# --------------------------------------------------------------------------- +# COOKIE_SECURE=single_user — no cookie at all, one shared Owner +# --------------------------------------------------------------------------- + + +def test_parse_cookie_mode_reads_three_modes(): + from imptune.config import parse_cookie_mode + + assert parse_cookie_mode("true") == (True, False) + assert parse_cookie_mode("") == (True, False) # unset-ish → secure default + assert parse_cookie_mode("False") == (False, False) + for spelling in ("single_user", "single-user", "SingleUser", " single "): + assert parse_cookie_mode(spelling) == (False, True) + + +def _single_user(monkeypatch): + import imptune.config as cfg + + monkeypatch.setattr(cfg, "SINGLE_USER", True) + monkeypatch.setattr(cfg, "COOKIE_SECURE", False) + + +def test_single_user_mode_sets_no_cookie_and_skips_onboarding(tmp_data_dir, monkeypatch): + from imptune.main import app + + _single_user(monkeypatch) + with TestClient(app) as fresh: + resp = fresh.get("/") + assert resp.status_code == 200 + assert COOKIE_NAME not in fresh.cookies + assert not [v for k, v in resp.headers.multi_items() if k.lower() == "set-cookie"] + assert "session-choice-modal" not in resp.text + assert "ephemeral-session-warning" not in resp.text + assert "single-user-notice" in resp.text + + +def test_single_user_mode_shares_data_across_browsers(tmp_data_dir, monkeypatch): + """The point of the mode: a cookie-less client sees the same printers.""" + from imptune.main import app + + _single_user(monkeypatch) + with TestClient(app) as client_a, TestClient(app) as client_b: + client_a.post( + "/printers", + data={"name": "Shared Printer", "ip_address": "10.0.7.1", "port_name": "IP_S"}, + follow_redirects=False, + ) + assert "Shared Printer" in client_b.get("/printers").text + + +def test_single_user_mode_creates_exactly_one_owner(tmp_data_dir, monkeypatch): + from imptune.db.models import Owner + from imptune.main import app + + _single_user(monkeypatch) + with TestClient(app) as fresh: + for _ in range(4): + assert fresh.get("/printers").status_code == 200 + assert Owner.select().count() == 1 + + +def test_single_user_mode_adopts_the_existing_owner(tmp_data_dir, monkeypatch): + """Switching a cookie-scoped deployment over must not hide its printers.""" + from imptune.main import app + + with TestClient(app) as cookie_client: + cookie_client.post( + "/printers", + data={"name": "Pre-switch Printer", "ip_address": "10.0.7.2", "port_name": "IP_T"}, + follow_redirects=False, + ) + + _single_user(monkeypatch) + with TestClient(app) as after_switch: + assert "Pre-switch Printer" in after_switch.get("/printers").text + + +def test_single_user_mode_disables_session_key_routes(tmp_data_dir, monkeypatch): + """No cookie to re-point, and the shared owner's key must not leak.""" + from imptune.main import app + + _single_user(monkeypatch) + with TestClient(app) as fresh: + assert fresh.get("/session/key/download").status_code == 404 + assert fresh.get("/session/restore").status_code == 404 + assert fresh.post( + "/session/restore", + data={"key": "anything"}, + headers={"origin": "http://testserver"}, + ).status_code == 404 + assert "/session/key/download" not in fresh.get("/printers").text