fix(auth): address SA4 review findings (WS epoch check, commit ordering, verify guard)

Adversarial re-review of the session-epoch work surfaced:
- WS auth (messages_ws) skipped the epoch check, so a revoked-but-unexpired cookie
  could still open the live push channel after a reset/logout-others. Now mirrors
  current_user: loads the user once, rejects a stale-epoch cookie before connecting.
- set_password + logout_others re-stamped the cookie BEFORE db.commit(); a failed
  commit would strand the current session at a newer epoch than the DB and wrongly
  401 it. Commit first, then re-stamp.
- Welcome verify effect could double-POST the single-use token (StrictMode/remount)
  and flip the banner to a false 'invalid'. Fire-once useRef guard.

Left as-is (low value, documented): the Plex image proxy authenticates without a DB
load / epoch check (poster/art fetches only); adding one would cost a DB hit per image.
This commit is contained in:
npeter83 2026-07-12 03:07:13 +02:00
parent 95d1549570
commit 07dba4da9e
3 changed files with 20 additions and 7 deletions

View file

@ -1,4 +1,4 @@
import { useEffect, useState } from "react";
import { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import {
ArrowRight,
@ -282,9 +282,13 @@ function AuthCard() {
}
}, []);
// Confirm a fragment verification token by POSTing it (new SB3 flow).
// Confirm a fragment verification token by POSTing it (new SB3 flow). Fire ONCE: the token is
// single-use, so a double POST (StrictMode remount / any re-render) would 400 on the second call
// and wrongly flip the banner to "invalid".
const verifyFired = useRef(false);
useEffect(() => {
if (!verifyToken) return;
if (!verifyToken || verifyFired.current) return;
verifyFired.current = true;
api
.verifyEmail(verifyToken)
.then(() => setVerify("ok"))