fix: make email lookup case-insensitive in get_user_by_email (#397)

* fix: make email lookup case-insensitive in get_user_by_email

Email addresses are case-insensitive in practice, but get_user_by_email
compared with an exact `UserModel.email == email` predicate. A user who
signed up as "User@example.com" could not be found when logging in as
"user@example.com" (and vice-versa), so the same person could fail to log
in — or be treated as a brand-new account — depending only on how their
client capitalized the address.

Compare on `func.lower(UserModel.email) == func.lower(email)` so lookups
are robust to capitalization. Minimal and backwards-compatible: it works
with existing mixed-case rows immediately, with no migration required.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix: enforce case-insensitive user emails

---------

Co-authored-by: developer603 <vrramsolutions@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Abhishek Kumar <abhishek@a6k.me>
This commit is contained in:
developer603 2026-06-02 13:43:20 +05:30 committed by GitHub
parent 8b9059fbe2
commit acc2ef9e96
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 78 additions and 5 deletions

View file

@ -17,6 +17,7 @@ from sqlalchemy import (
Text,
UniqueConstraint,
and_,
func,
text,
)
from sqlalchemy.orm import declarative_base, relationship
@ -67,9 +68,18 @@ class UserModel(Base):
back_populates="users",
)
is_superuser = Column(Boolean, default=False)
email = Column(String, unique=True, index=True, nullable=True)
email = Column(String, nullable=True)
password_hash = Column(String, nullable=True)
__table_args__ = (
Index(
"ix_users_email_lower",
func.lower(email),
unique=True,
postgresql_where=text("email IS NOT NULL"),
),
)
class UserConfigurationModel(Base):
__tablename__ = "user_configurations"