mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 21:10:59 +00:00
The previous /me payload carried a gravatarUrl built from
SHA-256(email) and pointed every authenticated page-load at
www.gravatar.com — Automattic could correlate the digest against
its known-email table on each request. This release moves the
avatar in-house: the user uploads through POST /api/user/avatar
(multipart, JPEG/PNG/WebP, 2 MiB / 2048×2048 max), the bytes ride
on the User row alongside a content-type and updatedAt timestamp,
and GET /api/user/avatar/{id} serves them from same-origin with
the cache-busting timestamp on the profile response.
The image-header parsing is hand-rolled in src/lib/avatar.ts so
the standalone image does not gain a native dep just to read width
and height. Validation rejects oversize / wrong content-type at
the multipart parse boundary; DELETE clears the row. The bytes
ride pg_dump alongside the rest of the row so the existing weekly
encrypted backup path already covers them.
The sidebar, the coach panel, the use-auth hook, and the disable-
coach card stop reading gravatarUrl; src/lib/gravatar.ts retires.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
25 lines
1.1 KiB
SQL
25 lines
1.1 KiB
SQL
-- v1.5.5 — self-hosted avatar storage.
|
|
--
|
|
-- Replaces the Gravatar third-party leak. The previous /me payload
|
|
-- carried a `gravatarUrl` built from `SHA-256(email)` and pointed
|
|
-- every authenticated page-load at www.gravatar.com — Automattic
|
|
-- could correlate the digest against its known-email table on each
|
|
-- request. The new path stores the image bytes on the User row and
|
|
-- serves them from same-origin.
|
|
--
|
|
-- Three nullable columns; null on all three = the user has not
|
|
-- uploaded an avatar and the profile response returns
|
|
-- `avatarUrl: null`. The upload route guards the size + content-
|
|
-- type + dimensions before the row write, so the column-level
|
|
-- constraints intentionally stay loose (the validation is enforced
|
|
-- at the API layer where it can return a useful 4xx).
|
|
--
|
|
-- The bytes ride in pg_dump alongside the rest of the row, so the
|
|
-- standard backup path already covers them. No new filesystem
|
|
-- volume to mount, no new Docker compose change.
|
|
|
|
ALTER TABLE "users"
|
|
ADD COLUMN "avatar_bytes" BYTEA,
|
|
ADD COLUMN "avatar_content_type" TEXT,
|
|
ADD COLUMN "avatar_updated_at" TIMESTAMP(3);
|