Show the OIDC profile picture with an identicon fallback
CI / Build and push docker image (push) Successful in 2m9s
CI / Build and push docker image (push) Successful in 2m9s
GET /api/me now carries the profile picture URL when the provider supplies an absolute http(s) one; the SPA shows it in the lobby navbar and draws a deterministic identicon from the sub otherwise, falling back to the identicon when the image fails to load. The identicon is a 5x5 mirrored grid seeded by an inline FNV-1a hash so it stays stable across Rust versions and is unit-testable on the host. The dev mock IdP hands alice and bob a picture claim.
This commit is contained in:
@@ -22,8 +22,33 @@ class MeRouteTest(unittest.TestCase):
|
||||
with oidc_user("alice", email="alice@example.com"):
|
||||
response = await client.get("/api/me")
|
||||
self.assertEqual(200, response.status_code)
|
||||
# The email claim the IdP returns is neither stored nor exposed.
|
||||
self.assertEqual({"sub": "alice", "name": "alice"}, response.json())
|
||||
# The email claim the IdP returns is neither stored nor exposed;
|
||||
# no picture claim in this request.
|
||||
self.assertEqual(
|
||||
{"sub": "alice", "name": "alice", "picture": None},
|
||||
response.json(),
|
||||
)
|
||||
|
||||
@async_test
|
||||
async def test_me_includes_the_profile_picture(self) -> None:
|
||||
transport = ASGITransport(app=app)
|
||||
async with AsyncClient(transport=transport, base_url="http://127.0.0.1") as client:
|
||||
with oidc_user("alice", picture="https://cdn.example.com/alice.png"):
|
||||
response = await client.get("/api/me")
|
||||
self.assertEqual(200, response.status_code)
|
||||
self.assertEqual(
|
||||
"https://cdn.example.com/alice.png",
|
||||
response.json()["picture"],
|
||||
)
|
||||
|
||||
@async_test
|
||||
async def test_me_rejects_non_http_picture_claims(self) -> None:
|
||||
transport = ASGITransport(app=app)
|
||||
async with AsyncClient(transport=transport, base_url="http://127.0.0.1") as client:
|
||||
with oidc_user("alice", picture="javascript:alert(1)"):
|
||||
response = await client.get("/api/me")
|
||||
self.assertEqual(200, response.status_code)
|
||||
self.assertIsNone(response.json()["picture"])
|
||||
|
||||
@async_test
|
||||
async def test_me_unauthenticated(self) -> None:
|
||||
|
||||
Reference in New Issue
Block a user