• T20: register now also creates a kind='email_verify' session (24h TTL)
    and calls sendVerificationEmail() — the one pluggable seam for a real
    provider once one's chosen (dev-plan-3.md §1 flagged no vendor exists
    yet). Outside production the register response carries a devVerifyUrl
    so the whole loop is testable without a real inbox. GET
    /api/auth/verify?token= flips emailVerified and revokes the token so
    it can't be replayed.
    
    T21: register reads any existing viewer_uid/viewer_nickname cookie
    (live.html/dance.html's plain client-set identity, unrelated to this
    session system) and carries it onto the new account as legacyUid/
    nickname. Login pushes that legacyUid back onto the browser via
    Set-Cookie — even from a clean browser with no viewer_uid cookie at
    all — so logging into an account doesn't let someone dodge
    per-viewer_uid vote limits by starting a fresh anonymous identity each
    time. No history is rewritten, per dev-plan-3.md's explicit scope cut.
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011Deddn3sM3oQnmvqWSMb4y
    yibo authored
     
    Browse File »
  • POST /api/auth/register, POST /api/auth/login, POST /api/auth/logout,
    and a debug GET /api/auth/me (T19's own acceptance criteria calls for
    it explicitly). Passwords hashed with node:crypto's scryptSync (salt
    stored alongside the hash, verified with timingSafeEqual) — still zero
    new dependencies.
    
    Sessions live in a separate user_session cookie from admin_session
    (T6) — the two are unrelated systems, confirmed by a test that a user
    session can't unlock /api/admin/*. Login and "email not registered"
    return the identical 401 body so the endpoint can't be used to
    enumerate registered emails.
    
    Every test file that spawns server.js in an isolated tmpdir now also
    copies db.js alongside it (dance-channel/dressup-generate/dressup-crud/
    admin-pages-flow/uploads-route .test.js) — server.js requires db.js
    unconditionally now, so those child processes were crashing silently
    without it.
    
    Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_011Deddn3sM3oQnmvqWSMb4y
    yibo authored
     
    Browse File »