Merge branch 'worktree-check-security-audit'
Security and frontend-correctness hardening: analytics IDOR fix, scraper log scrubbing, lowercase email normalisation (migration 009), stale-response guards in the plan hooks, busy flags cleared unconditionally across all useLatestRequest consumers, Calendar no longer blanks on mutation, plus dependabot/CI config and removal of the stray frontend/out.js. Conflicts came from main's later "day assertions" restructure, which made usePlannedDays read-only and replaced the calendar's per-day add/update with useDayAssertions.assertDay. Both intents kept: - usePlannedDays: branch's fetch machinery (isRefreshing, in-flight dedup, unguarded busy clear); mutators dropped as on main. - usePlanSync: branch's useLatestRequest guard also applied to main's new syncWithWish. - useDayAssertions / useLatestBalance (new on main): busy flag now cleared unconditionally, as the branch did for every other consumer. - useDayAssertions.assertDay gains the branch's `skipRefresh` option and a `refresh`, so Calendar's multi-day save keeps the batch shape (N writes, one trailing bumpPlanVersion + one assertions refresh) on main's assertDay path. Branch's M7 tests ported from the removed add/update API to assertDay. - PlanSyncProvider: branch's isAuthenticated gate kept; eviction-preview state stays removed as on main. - usePlannedDayExclusions.ts stays deleted (superseded by useDayAssertions). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T4wjgbVL4HAC5Rdaw75VbV
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"""Pydantic schemas for auth endpoints."""
|
||||
|
||||
from pydantic import BaseModel, EmailStr, Field
|
||||
from pydantic import BaseModel, EmailStr, Field, field_validator
|
||||
|
||||
|
||||
class RegisterRequest(BaseModel):
|
||||
@@ -13,11 +13,25 @@ class RegisterRequest(BaseModel):
|
||||
# if one exists) instead of creating a new one.
|
||||
invite_token: str | None = None
|
||||
|
||||
@field_validator("email")
|
||||
@classmethod
|
||||
def normalize_email(cls, v: str) -> str:
|
||||
"""Lowercase at the API boundary — storage/lookup is case-sensitive
|
||||
(`WHERE email = ?`), so Foo@x.se and foo@x.se must resolve to one
|
||||
account rather than silently becoming two."""
|
||||
return v.lower()
|
||||
|
||||
|
||||
class LoginRequest(BaseModel):
|
||||
email: EmailStr
|
||||
password: str
|
||||
|
||||
@field_validator("email")
|
||||
@classmethod
|
||||
def normalize_email(cls, v: str) -> str:
|
||||
"""Lowercase at the API boundary — see `RegisterRequest.normalize_email`."""
|
||||
return v.lower()
|
||||
|
||||
|
||||
class TokenResponse(BaseModel):
|
||||
access_token: str
|
||||
|
||||
Reference in New Issue
Block a user