From 0568c76076b977458174bfc1c240dbc857260e5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Fri, 11 Sep 2026 16:15:58 +0200 Subject: [PATCH] =?UTF-8?q?chore(release):=20v1.38.20=20=E2=80=94=20signin?= =?UTF-8?q?g=20in=20no=20longer=20says=20who=20has=20an=20account=20here?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bump the version, the service-worker fallback and the OpenAPI document, and add the CHANGELOG entry for v1.38.20. --- CHANGELOG.md | 42 ++++++++++++++++++++++++++++++++++++++++++ docs/api/openapi.yaml | 2 +- package.json | 2 +- public/sw.js | 2 +- 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ecd50e0c2..828e226ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,47 @@ # Changelog +## [1.38.20] — 2026-09-11 + +Signing in no longer tells anybody which addresses have an account here. + +### Security + +- **Signing in now takes the same time whether or not the account exists.** + A wrong password and an address nobody has registered here have always + given you the same answer on screen, but the server used to reach that + answer much faster when there was no account to check, and the same when + the account signs in with a passkey and has no password at all. Someone + probing the sign-in page could read that difference and learn which + addresses are registered, and which of those have a password. Every + refusal now does the same work before it answers. +- **Changing your email address is limited to ten changes an hour.** The + server tells you when the address you typed already belongs to another + account, which is the only sensible thing to say to someone who typed one. + Nothing stopped a signed-in caller from asking that question over and over + about addresses that were not theirs. Ten an hour per account is far above + any real use of the field, and a save that leaves your address as it is + does not count against it. If you hit the limit while saving other things + on the settings page, those are saved and only the address is held back, + with a note under the field. If you write against the API, a request that + asked for nothing but the address gets a 429 on `PUT /api/auth/profile` + and `PATCH /api/user/profile` with `meta.errorCode` set to + `profile.update.emailRateLimited` and a `Retry-After` header saying how + long to wait; a request that carried other fields gets 200 with `email` + listed in `rejectedFields` under the code `rate_limited`. + +### Removed + +- **The endpoint that answered whether an address has an account here is + gone.** `POST /api/auth/check-user` took an email address or a username + and said, to anyone who asked and without any sign-in, whether an account + existed and whether it had a passkey or a password. It was built to decide + which field a sign-in screen shows first, which is not worth telling the + world who has an account here. The path now answers 410 and says so in the + API reference rather than disappearing, so anything still calling it gets + a clear "this is gone, stop retrying" instead of a 404 that looks like a + broken server. If you wrote something against it, the sign-in request + itself is the replacement: send the credential and read the answer. + ## [1.38.19] — 2026-09-11 The first run tells you what is actually true about your account, an diff --git a/docs/api/openapi.yaml b/docs/api/openapi.yaml index d2a1d1c88..fb07ebd4e 100644 --- a/docs/api/openapi.yaml +++ b/docs/api/openapi.yaml @@ -1,7 +1,7 @@ openapi: 3.1.0 info: title: HealthLog API - version: 1.38.19 + version: 1.38.20 description: >- Self-hosted personal-health-tracking PWA — public API surface for the iOS native client and external ingest. diff --git a/package.json b/package.json index d4de393df..b3ea6e51f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "healthlog", - "version": "1.38.19", + "version": "1.38.20", "description": "Self-hosted personal-health-tracking PWA with Withings integration, AI insights, and doctor-report PDF export.", "license": "PolyForm-Noncommercial-1.0.0", "homepage": "https://healthlog.dev", diff --git a/public/sw.js b/public/sw.js index 99bfccfd2..8c4284924 100644 --- a/public/sw.js +++ b/public/sw.js @@ -36,7 +36,7 @@ try { // v1.4.38.4 → v1.4.42. Do not hand-edit; bump `package.json` and rebuild. const CACHE_VERSION = (typeof self !== "undefined" && self.__APP_VERSION__) || - /* @sw-version-fallback */ "v1.38.19"; + /* @sw-version-fallback */ "v1.38.20"; const STATIC_CACHE = `healthlog-static-${CACHE_VERSION}`; const PAGE_CACHE = `healthlog-pages-${CACHE_VERSION}`; // v1.18.6 — read-only data cache for a curated allowlist of safe GET `/api/*`