From c8805ee4c45c4310ca4d5d4d4191ecc2981ce58b Mon Sep 17 00:00:00 2001 From: Kyle Pope Date: Fri, 6 Mar 2026 00:31:10 +0800 Subject: [PATCH] Fix registration enumeration + contact detail panel name sync MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit M-01: Unify registration error messages to prevent username/email enumeration — both now return the same generic message. Bug fix: Contact detail panel header and initials now use shared_fields for umbral contacts instead of stale Person record first_name/last_name. The table list already did this via sf() helper; the detail panel header and getPersonInitialsName were bypassing it. Co-Authored-By: Claude Opus 4.6 --- backend/app/routers/auth.py | 2 +- frontend/src/components/people/PeoplePage.tsx | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/backend/app/routers/auth.py b/backend/app/routers/auth.py index 552fe69..9989812 100644 --- a/backend/app/routers/auth.py +++ b/backend/app/routers/auth.py @@ -441,7 +441,7 @@ async def register( select(User).where(User.username == data.username) ) if existing.scalar_one_or_none(): - raise HTTPException(status_code=400, detail="Registration could not be completed. Please try a different username.") + raise HTTPException(status_code=400, detail="Registration could not be completed. Please check your details and try again.") # Check email uniqueness (generic error to prevent enumeration) if data.email: diff --git a/frontend/src/components/people/PeoplePage.tsx b/frontend/src/components/people/PeoplePage.tsx index 4e52d41..f49b81d 100644 --- a/frontend/src/components/people/PeoplePage.tsx +++ b/frontend/src/components/people/PeoplePage.tsx @@ -60,7 +60,11 @@ function StatCounter({ // Helpers // --------------------------------------------------------------------------- function getPersonInitialsName(p: Person): string { - const parts = [p.first_name, p.last_name].filter(Boolean); + const firstName = p.is_umbral_contact && p.shared_fields?.first_name + ? String(p.shared_fields.first_name) : p.first_name; + const lastName = p.is_umbral_contact && p.shared_fields?.last_name + ? String(p.shared_fields.last_name) : p.last_name; + const parts = [firstName, lastName].filter(Boolean); return parts.length > 0 ? parts.join(' ') : p.name; } @@ -428,7 +432,11 @@ export default function PeoplePage() {
-

{p.name}

+

{ + p.is_umbral_contact && p.shared_fields + ? [sf(p, 'first_name'), sf(p, 'last_name')].filter(Boolean).join(' ') || p.name + : p.name + }

{p.is_umbral_contact && ( )}