Fix QA critical/warning findings on profile feature
C-01: Replace setattr loop with explicit field assignment in update_profile C-02: Fix useEffect dependency to profileQuery.dataUpdatedAt for re-sync W-01: Add audit log entry for profile updates W-02: Use less misleading generic error for email uniqueness on registration W-03: Early return on empty PUT body to avoid unnecessary commit Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
45f3788fb0
commit
02efe04fc4
@ -448,7 +448,7 @@ async def register(
|
||||
select(User).where(User.email == data.email)
|
||||
)
|
||||
if existing_email.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.")
|
||||
|
||||
password_hash = hash_password(data.password)
|
||||
# SEC-01: Explicit field assignment — never **data.model_dump()
|
||||
@ -645,12 +645,16 @@ async def get_profile(
|
||||
@router.put("/profile", response_model=ProfileResponse)
|
||||
async def update_profile(
|
||||
data: ProfileUpdate,
|
||||
request: Request,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
current_user: User = Depends(get_current_user),
|
||||
):
|
||||
"""Update the current user's profile fields (first_name, last_name, email)."""
|
||||
update_data = data.model_dump(exclude_unset=True)
|
||||
|
||||
if not update_data:
|
||||
return ProfileResponse.model_validate(current_user)
|
||||
|
||||
# Email uniqueness check if email is changing
|
||||
if "email" in update_data and update_data["email"] != current_user.email:
|
||||
new_email = update_data["email"]
|
||||
@ -661,9 +665,19 @@ async def update_profile(
|
||||
if existing.scalar_one_or_none():
|
||||
raise HTTPException(status_code=400, detail="Email is already in use")
|
||||
|
||||
# SEC-01: Explicit field assignment
|
||||
for key, value in update_data.items():
|
||||
setattr(current_user, key, value)
|
||||
# SEC-01: Explicit field assignment — only allowed profile fields
|
||||
if "first_name" in update_data:
|
||||
current_user.first_name = update_data["first_name"]
|
||||
if "last_name" in update_data:
|
||||
current_user.last_name = update_data["last_name"]
|
||||
if "email" in update_data:
|
||||
current_user.email = update_data["email"]
|
||||
|
||||
await log_audit_event(
|
||||
db, action="auth.profile_updated", actor_id=current_user.id,
|
||||
detail={"fields": list(update_data.keys())},
|
||||
ip=get_client_ip(request),
|
||||
)
|
||||
|
||||
await db.commit()
|
||||
await db.refresh(current_user)
|
||||
|
||||
@ -73,7 +73,7 @@ export default function SettingsPage() {
|
||||
setLastName(profileQuery.data.last_name ?? '');
|
||||
setProfileEmail(profileQuery.data.email ?? '');
|
||||
}
|
||||
}, [profileQuery.data?.username]);
|
||||
}, [profileQuery.dataUpdatedAt]);
|
||||
|
||||
// Sync state when settings load
|
||||
useEffect(() => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user