Once set, device_token_ack permanently locks out id-only requests (auth.require_device) -- fine for a device that still has its token, but a reprovisioned device has wiped its own token locally and had no way back in short of a manual DB edit. The device's captive portal always redirects the phone to /claim?device_id=... after (re)provisioning, so reopen the handshake window there instead, scoped to a logged-in owner/linked user of that frame.
83 lines
2.9 KiB
Python
83 lines
2.9 KiB
Python
"""A physical frame's device_token_ack becomes permanently sticky once
|
|
set (see app/auth.py's require_device) -- if the device is reset/
|
|
reprovisioned, it loses its access token and gets locked out with a 401
|
|
forever unless something reopens that handshake window. The device's
|
|
own captive portal redirects the phone's browser to /claim?device_id=
|
|
on every (re)provisioning cycle (see firmware/main/wifi_provisioning.c),
|
|
so pages.py's _render_claim uses that as the hook to auto-reset the ack
|
|
flag for a logged-in owner/linked user -- see routers/pages.py."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from app.models import Frame
|
|
|
|
from .conftest import link_user, login, make_user
|
|
|
|
|
|
def test_claim_page_resets_device_token_ack_for_owner(client, db_session):
|
|
client.post("/setup", data={"username": "alice", "password": "hunter22"})
|
|
frame = db_session.get(Frame, 1)
|
|
frame.device_id = "a0f262865898"
|
|
frame.device_token_ack = True
|
|
db_session.commit()
|
|
|
|
resp = client.get(f"/claim?device_id={frame.device_id}")
|
|
assert resp.status_code == 200
|
|
|
|
db_session.refresh(frame)
|
|
assert frame.device_token_ack is False
|
|
|
|
|
|
def test_claim_page_resets_device_token_ack_for_linked_user(client, db_session):
|
|
client.post("/setup", data={"username": "alice", "password": "hunter22"})
|
|
bob = make_user(db_session, "bob")
|
|
frame = db_session.get(Frame, 1)
|
|
link_user(db_session, bob, frame)
|
|
frame.device_id = "a0f262865898"
|
|
frame.device_token_ack = True
|
|
db_session.commit()
|
|
|
|
client.cookies.clear()
|
|
login(client, "bob")
|
|
|
|
resp = client.get(f"/claim?device_id={frame.device_id}")
|
|
assert resp.status_code == 200
|
|
|
|
db_session.refresh(frame)
|
|
assert frame.device_token_ack is False
|
|
|
|
|
|
def test_claim_page_leaves_ack_alone_when_already_false(client, db_session):
|
|
client.post("/setup", data={"username": "alice", "password": "hunter22"})
|
|
frame = db_session.get(Frame, 1)
|
|
frame.device_id = "a0f262865898"
|
|
db_session.commit()
|
|
assert frame.device_token_ack is False
|
|
|
|
resp = client.get(f"/claim?device_id={frame.device_id}")
|
|
assert resp.status_code == 200
|
|
|
|
db_session.refresh(frame)
|
|
assert frame.device_token_ack is False
|
|
|
|
|
|
def test_claim_page_does_not_reset_ack_for_unrelated_user(client, db_session):
|
|
"""A user with no relationship to the frame lands on the "claimed"
|
|
(not "claimed_yours") branch -- must not be able to reopen another
|
|
household's device handshake just by knowing its device_id."""
|
|
client.post("/setup", data={"username": "alice", "password": "hunter22"})
|
|
frame = db_session.get(Frame, 1)
|
|
frame.device_id = "a0f262865898"
|
|
frame.device_token_ack = True
|
|
db_session.commit()
|
|
|
|
make_user(db_session, "mallory")
|
|
client.cookies.clear()
|
|
login(client, "mallory")
|
|
|
|
resp = client.get(f"/claim?device_id={frame.device_id}")
|
|
assert resp.status_code == 200
|
|
|
|
db_session.refresh(frame)
|
|
assert frame.device_token_ack is True
|