feat(auth)!: remove the public access-request endpoint
POST /auth/request-access had no caller left: the login page's form was gone, and registration and a refused Google sign-in already land in the same admin approval. A third public write path with no protection of its own (owner decision, E34). Its one guard moves to where every path passes: upsert_pending_invite no longer opens a pending row for an address the env already lets in. The registration path lacked it — registering b.ob@gmail.com beside an env-granted bob@gmail.com opened a pending row, and is_allowed answers from the invite rows once any exist, so the real owner was locked out. The tests that drove the endpoint now drive registration or the shared function.
This commit is contained in:
@@ -175,7 +175,7 @@ def test_a_stripped_account_keeps_its_recovery_stamp(db, client, smtp_on, make_u
|
||||
assert row.password_hash is None and row.password_revoked_at is not None
|
||||
|
||||
|
||||
def test_a_denied_sibling_is_not_reopened_while_a_pending_row_exists(db, client):
|
||||
def test_a_denied_sibling_is_not_reopened_while_a_pending_row_exists(db):
|
||||
# Canonical siblings exist on prod. Picking the denied one reopens it and re-notifies every
|
||||
# admin, putting one person in the queue twice — and the exact-spelling tie-break made that
|
||||
# deterministic rather than merely possible.
|
||||
@@ -187,9 +187,7 @@ def test_a_denied_sibling_is_not_reopened_while_a_pending_row_exists(db, client)
|
||||
)
|
||||
db.commit()
|
||||
|
||||
assert (
|
||||
client.post("/auth/request-access", json={"email": "pairone@gmail.com"}).status_code == 200
|
||||
)
|
||||
auth_routes.upsert_pending_invite(db, "pairone@gmail.com")
|
||||
|
||||
db.expire_all()
|
||||
rows = {i.email: i.status for i in db.execute(select(Invite)).scalars().all()}
|
||||
@@ -210,12 +208,13 @@ def test_the_env_allow_list_is_matched_canonically(db, monkeypatch):
|
||||
|
||||
|
||||
def test_an_env_granted_address_cannot_be_shadowed_by_a_stranger(db, client, monkeypatch):
|
||||
# `is_allowed` short-circuits on ANY invite row for the canonical form, so before this an
|
||||
# unauthenticated caller could request access under a sibling spelling and permanently shadow an
|
||||
# env grant. With the env list matched canonically the request never opens a row.
|
||||
# `is_allowed` short-circuits on ANY invite row for the canonical form, so an unauthenticated
|
||||
# caller registering under a sibling spelling would open a pending row and permanently shadow an
|
||||
# env grant. The env list is matched canonically, so the registration never opens a row.
|
||||
monkeypatch.setattr(settings, "allowed_emails", "bob@gmail.com")
|
||||
|
||||
assert client.post("/auth/request-access", json={"email": "b.ob@gmail.com"}).status_code == 200
|
||||
r = client.post("/auth/register", json={"email": "b.ob@gmail.com", "password": _PW})
|
||||
assert r.status_code == 200
|
||||
|
||||
assert db.execute(select(Invite)).scalars().all() == []
|
||||
assert auth_core.is_allowed(db, "bob@gmail.com") is True
|
||||
@@ -351,12 +350,8 @@ def test_two_admins_two_languages_two_mails(db, client, make_user, smtp_on, wire
|
||||
make_user(email="hu.admin@example.com", role="admin", preferences={"language": "hu"})
|
||||
make_user(email="en.admin@example.com", role="admin", preferences={"language": "en"})
|
||||
|
||||
assert (
|
||||
client.post(
|
||||
"/auth/request-access", json={"email": "asking@example.com", "lang": "en"}
|
||||
).status_code
|
||||
== 200
|
||||
)
|
||||
r = client.post("/auth/register", json={"email": "asking@example.com", "password": _PW})
|
||||
assert r.status_code == 200
|
||||
|
||||
notices = [w for w in wire if "asking@example.com" in w[1]]
|
||||
assert len(notices) == 2
|
||||
|
||||
Reference in New Issue
Block a user