Skip to content

feat(auth): guest login, email registration/login, verification codes - #15

Merged
daum110715 merged 2 commits into
LemonStudio-hub:mainfrom
daum110715:pr/user-auth-email
Jul 16, 2026
Merged

daum110715 merged 2 commits into
LemonStudio-hub:mainfrom
daum110715:pr/user-auth-email

Conversation

@daum110715

Copy link
Copy Markdown
Collaborator

What

User authentication upgrade:

  • Guest login — nickname-only sessions (POST /api/auth/guest)
  • Email registration — verification code via Resend (send-code → register)
  • Email/password login — registered accounts (POST /api/auth/login)
  • Guest JWT refresh — POST /api/auth/token (guest-only)
  • Allowed email domains — GET /api/auth/email-domains
  • Frontend: PC + mobile login screens and authStore support guest / register / login flows
  • Migrations 0015–0017: account_type + ban fields, email/password columns, verification codes table

Out of scope (intentionally)

  • R2 / cloud file sync
  • Admin panel removal or changes
  • Settings account UI / font-size / perf dashboard
  • Personal deploy IDs / R2 bindings in wrangler (only adds EMAIL_FROM)

Ops / secrets

Worker needs:

  • KEY_RESEND or RESEND_API_KEY (Resend API key)
  • EMAIL_FROM (defaults in wrangler vars: SCP OS <auth@daum.pw> — adjust for production)

Base commits

Includes shared CI green base (scraper fetch + prettier) also carried by #13/#14 until those land on main. After merge, rebase will shrink to auth-only.

Verification

  • pnpm typecheck ✅
  • worker tests 145 ✅
  • app tests ✅

Note vs full local main

Extracted from local auth work; did not include admin deletion or cloud-sync migrations from personal branch.

@LemonStudio-hub

Copy link
Copy Markdown
Owner

🔍 Code Review — Request Changes

Summary

Three auth modes (guest, email login, email registration) with PBKDF2 password hashing, verification codes via Resend API, and domain allow-list. Large portion is unrelated Prettier formatting.

Critical Issues

1. Verification codes hashed with plain SHA-256 (no salt)

  • 6-digit code has only 1M possibilities — trivially rainbow-tabled if DB is compromised
  • Fix: Use HMAC or per-code random salt, consistent with PBKDF2 for passwords

2. Math.random() used for verification code generation

  • Not cryptographically secure — PRNG state can be predicted
  • Fix: Use crypto.getRandomValues() (available in Cloudflare Workers)

3. No rate limiting on /api/auth/send-code per IP

  • Per-email cooldown only — attacker can enumerate thousands of different addresses
  • request_ip column stored but never used for rate limiting
  • Fix: Add per-IP rate limiting

4. No rate limiting on /api/auth/login

  • Unlimited password attempts against any email
  • Fix: Add brute-force lockout or exponential backoff

5. JWT stored in IndexedDB with no HttpOnly cookie

  • Accessible to any JavaScript including XSS payloads
  • Combined with authFetch 401-retry, any XSS yields full session hijacking

6. checkNicknameAvailability now always returns available: true

  • Uniqueness check against database completely removed
  • Registered user nicknames can collide

Warning Issues

7. initAuth uses email as userId for registered accounts — token refresh will fail (403)
8. Email domain allow-list is a maintenance burden — 160 hardcoded entries; consider block-list approach
9. Migration numbering may conflict with other PRs (0015, 0016, 0017)
10. Hardcoded fallback JWT secret — 'scp-os-default-secret' should fail loudly
11. CSS regression: removed prefers-reduced-motion support from login screens
12. CSS regression: removed light mode overrides from login screens
13. Mixed Chinese/English in UI strings — should use useI18n

Recommendation: Request changes — fix PRNG, add per-IP rate limiting, add login brute-force protection, fix token refresh path.

daum110715 added a commit to daum110715/scp-os that referenced this pull request Jul 15, 2026
- Salted verification-code hashes; crypto.getRandomValues for codes
- Per-IP rate limits on send-code and login (brute-force protection)
- Require JWT_SECRET (no hardcoded fallback)
- Nickname uniqueness via DB check on register and check-nickname API
- Registered sessions use user_id + sessionStorage token; no guest token mint
- Restore prefers-reduced-motion and light-mode CSS on login screens
@daum110715

Copy link
Copy Markdown
Collaborator Author

Addressed review feedback

Critical

  1. Salted verification codes — store salt$sha256(salt:code) (legacy unsalted still accepted once during rollout).
  2. crypto.getRandomValues() for 6-digit codes (rejection sampling).
  3. Per-IP rate limit on /api/auth/send-code — 10/hour (in addition to per-email cooldown).
  4. Login brute-force protection — 10 attempts / 15 min per IP and per email.
  5. JWT storage — stop writing JWT to IndexedDB; keep in memory + sessionStorage for the browser session (HttpOnly cookies still preferred long-term for full XSS isolation).
  6. Nickname uniqueness — /api/user/check-nickname queries DB; register rejects taken nicknames.

Warnings (key)

  1. Token refresh path — registered accounts no longer call guest /api/auth/token with email as userId; use real user_id and re-login when session token is gone.
  2. No hardcoded JWT secret — missing JWT_SECRET fails closed.
    11–12. Restored prefers-reduced-motion + light-mode overrides on PC/mobile login screens.

Deferred / residual

Ready for re-review.

@daum110715

Copy link
Copy Markdown
Collaborator Author

Status

  • CI: Lint / Test / Build all green on latest tip (Security Scan skip is expected).
  • Review feedback addressed on this tip; ready for re-review / merge when convenient.

No further code changes planned on this PR unless requested.

Add registered accounts with email verification (Resend), guest sessions,
and password auth while keeping the admin panel intact.

- Worker: /api/auth/{guest,register,login,send-code,email-domains,token}
- Migrations 0015-0017: account_type, email/password, verification codes
- App: login screens + authStore for guest/registered flows
- PBKDF2 hashPassword; guest-only JWT refresh; allowed email domains

Requires KEY_RESEND (or RESEND_API_KEY) and EMAIL_FROM for send-code.
- Salted verification-code hashes; crypto.getRandomValues for codes
- Per-IP rate limits on send-code and login (brute-force protection)
- Require JWT_SECRET (no hardcoded fallback)
- Nickname uniqueness via DB check on register and check-nickname API
- Registered sessions use user_id + sessionStorage token; no guest token mint
- Restore prefers-reduced-motion and light-mode CSS on login screens
@daum110715
daum110715 force-pushed the pr/user-auth-email branch from 1723783 to c2e3f34 Compare July 16, 2026 03:46
@daum110715
daum110715 merged commit 291d869 into LemonStudio-hub:main Jul 16, 2026
1 check failed
daum110715 added a commit to daum110715/scp-os that referenced this pull request Jul 22, 2026
Replace /files 410 stubs with R2 CRUD (upload/list/quota/get/rename/delete)
for registered accounts, add /api/sync data+quota, and dual-write from the
file manager with optional sync-from-cloud.

Depends on email auth (LemonStudio-hub#15) for accountType + requiredRegisteredUser.
Ops: create R2 bucket bound as SCP_FILES (see wrangler.toml).
daum110715 added a commit to daum110715/scp-os that referenced this pull request Jul 22, 2026
Replace /files 410 stubs with R2 CRUD (upload/list/quota/get/rename/delete)
for registered accounts, add /api/sync data+quota, and dual-write from the
file manager with optional sync-from-cloud.

Depends on email auth (LemonStudio-hub#15) for accountType + requiredRegisteredUser.
Ops: create R2 bucket bound as SCP_FILES (see wrangler.toml).
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.

2 participants