Skip to content

fix: lowercase the email before hashing the Gravatar URL - #1605

Open
Andy-Sverdlov-LucaNet wants to merge 1 commit into
apache:mainfrom
Andy-Sverdlov-LucaNet:fix/gravatar-lowercase-email
Open

fix: lowercase the email before hashing the Gravatar URL#1605
Andy-Sverdlov-LucaNet wants to merge 1 commit into
apache:mainfrom
Andy-Sverdlov-LucaNet:fix/gravatar-lowercase-email

Conversation

@Andy-Sverdlov-LucaNet

Copy link
Copy Markdown

Fixes #1604

Proposed Changes

  • Lowercase the email address in pkg/gravatar.GetAvatarURL before hashing
    it. The Gravatar specification hashes the trimmed, lowercased address; the
    function only trimmed, so an account whose stored address contains an
    uppercase letter hashed to an address Gravatar does not know and rendered
    the identicon fallback instead of the user's avatar.
  • Add pkg/gravatar/gravatar_test.go covering the casing and whitespace
    variants of one address, all of which must produce the hash of its
    lowercase form.

selectedAvatar recomputes this URL from the stored address on every response,
so this affects both default_avatar: gravatar and an explicit per-user
avatar.type: gravatar — a user cannot work around it by re-selecting Gravatar
in their profile. The backend never normalises a stored address, and the
external-login path copies the provider's address verbatim, so accounts created
through an OIDC/OAuth2 connector inherit whatever casing the identity provider
sends.

The web UI already lowercases before hashing
(ui/src/pages/Users/Settings/Profile/index.tsx), so this also removes a
frontend/backend disagreement: the Settings → Profile preview showed the user's
real avatar while every other surface showed an identicon.

No migration is needed. The hash is computed on read, so existing accounts
resolve correctly as soon as this ships; stored addresses are left untouched.

The Gravatar specification hashes the trimmed, lowercased address.
GetAvatarURL only trimmed it, so an account whose stored address contains
an uppercase letter hashed to an address Gravatar does not know: the user's
avatar was never found and the identicon fallback was rendered instead.

selectedAvatar recomputes this URL from the stored address on every
response, so this affected both default_avatar: gravatar and an explicit
per-user avatar.type: gravatar, and a user could not work around it by
re-selecting Gravatar in their profile. Nothing in the backend normalises a
stored address, and the external login path copies the provider's address
verbatim, so accounts created through an OIDC/OAuth2 connector inherit
whatever casing the identity provider sends.

The web UI already lowercases before hashing, so the Settings -> Profile
preview showed the user's real avatar while every other surface showed an
identicon. This removes that disagreement.

The hash is computed on read, so existing accounts resolve correctly as soon
as this ships. Stored addresses are left untouched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gravatar hash is computed from the un-lowercased email, so mixed-case accounts render an identicon

1 participant