Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 53e802746c |
@@ -95,7 +95,7 @@ jobs:
|
||||
run: |
|
||||
CHROME_PATH=$(find /home/runner/.cache/ms-playwright -name chrome -type f 2>/dev/null | head -1)
|
||||
npm install -g @lhci/cli
|
||||
CHROME_PATH="$CHROME_PATH" lhci autorun --chrome-flags="--headless=new --no-sandbox --disable-gpu --disable-dev-shm-usage"
|
||||
LHCI_CHROME_PATH="$CHROME_PATH" lhci autorun
|
||||
|
||||
build-and-push:
|
||||
runs-on: runners-cartsnitch
|
||||
|
||||
@@ -5,7 +5,6 @@ Sessions are verified by querying the shared sessions table directly.
|
||||
"""
|
||||
|
||||
from datetime import UTC, datetime
|
||||
from hashlib import sha256
|
||||
from uuid import UUID
|
||||
|
||||
from fastapi import Cookie, Depends, Header, HTTPException, Request, status
|
||||
@@ -28,13 +27,10 @@ async def _validate_session_token(token: str, db: AsyncSession) -> UUID:
|
||||
"""Validate a Better-Auth session token against the sessions table.
|
||||
|
||||
Returns the user_id (as UUID) if the session is valid and not expired.
|
||||
Better-Auth v1.5.6+ stores tokens as SHA-256 hashes, so we hash the
|
||||
incoming raw token before querying.
|
||||
"""
|
||||
hashed_token = sha256(token.encode("utf-8")).hexdigest()
|
||||
result = await db.execute(
|
||||
text("SELECT user_id, expires_at FROM sessions WHERE token = :token"),
|
||||
{"token": hashed_token},
|
||||
{"token": token},
|
||||
)
|
||||
row = result.first()
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
from contextlib import asynccontextmanager
|
||||
|
||||
from fastapi import APIRouter, FastAPI
|
||||
from fastapi import FastAPI
|
||||
|
||||
from cartsnitch_api.auth.routes import router as auth_router
|
||||
from cartsnitch_api.middleware.cors import add_cors_middleware
|
||||
@@ -46,19 +46,15 @@ def create_app() -> FastAPI:
|
||||
# Routers
|
||||
app.include_router(health_router)
|
||||
app.include_router(auth_router)
|
||||
|
||||
# Data endpoints mounted under /api/v1
|
||||
v1_router = APIRouter(prefix="/api/v1")
|
||||
v1_router.include_router(stores_router)
|
||||
v1_router.include_router(purchases_router)
|
||||
v1_router.include_router(products_router)
|
||||
v1_router.include_router(prices_router)
|
||||
v1_router.include_router(coupons_router)
|
||||
v1_router.include_router(shopping_router)
|
||||
v1_router.include_router(alerts_router)
|
||||
v1_router.include_router(scraping_router)
|
||||
v1_router.include_router(public_router)
|
||||
app.include_router(v1_router)
|
||||
app.include_router(stores_router)
|
||||
app.include_router(purchases_router)
|
||||
app.include_router(products_router)
|
||||
app.include_router(prices_router)
|
||||
app.include_router(coupons_router)
|
||||
app.include_router(shopping_router)
|
||||
app.include_router(alerts_router)
|
||||
app.include_router(scraping_router)
|
||||
app.include_router(public_router)
|
||||
|
||||
return app
|
||||
|
||||
|
||||
+2
-7
@@ -3,12 +3,7 @@
|
||||
"collect": {
|
||||
"staticDistDir": "./dist",
|
||||
"url": ["http://localhost:4173/"],
|
||||
"numberOfRuns": 1,
|
||||
"settings": {
|
||||
"chromeFlags": ["--headless=new", "--no-sandbox", "--disable-gpu", "--disable-dev-shm-usage"],
|
||||
"skipAudits": ["bf-cache"],
|
||||
"disableFullPageScreenshot": true
|
||||
}
|
||||
"numberOfRuns": 1
|
||||
},
|
||||
"assert": {
|
||||
"assertions": {
|
||||
@@ -21,4 +16,4 @@
|
||||
"target": "temporary-public-storage"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -35,7 +35,7 @@ export function useProduct(id: string) {
|
||||
export function usePriceHistory(productId: string) {
|
||||
return useQuery({
|
||||
queryKey: ['priceHistory', productId],
|
||||
queryFn: () => api.get<PriceHistory[]>(`/products/${productId}/prices`),
|
||||
queryFn: () => api.get<PriceHistory[]>(`/products/${productId}/price-history`),
|
||||
enabled: !!productId,
|
||||
})
|
||||
}
|
||||
@@ -50,6 +50,6 @@ export function useCoupons() {
|
||||
export function usePriceAlerts() {
|
||||
return useQuery({
|
||||
queryKey: ['priceAlerts'],
|
||||
queryFn: () => api.get<PriceAlert[]>('/alerts'),
|
||||
queryFn: () => api.get<PriceAlert[]>('/price-alerts'),
|
||||
})
|
||||
}
|
||||
|
||||
+2
-2
@@ -15,7 +15,7 @@ const mockRoutes: Record<string, (path: string) => unknown> = {
|
||||
'/purchases': () => mockPurchases,
|
||||
'/products': () => mockProducts,
|
||||
'/coupons': () => mockCoupons,
|
||||
'/alerts': () => mockAlerts,
|
||||
'/price-alerts': () => mockAlerts,
|
||||
}
|
||||
|
||||
function matchMockRoute<T>(path: string): T | null {
|
||||
@@ -30,7 +30,7 @@ function matchMockRoute<T>(path: string): T | null {
|
||||
}
|
||||
|
||||
// /products/:id/price-history
|
||||
const priceHistoryMatch = path.match(/^\/products\/(.+)\/prices$/)
|
||||
const priceHistoryMatch = path.match(/^\/products\/(.+)\/price-history$/)
|
||||
if (priceHistoryMatch) {
|
||||
return getMockPriceHistory(priceHistoryMatch[1]) as T
|
||||
}
|
||||
|
||||
+2
-8
@@ -31,14 +31,8 @@ export function Login() {
|
||||
throw new Error(authError.message ?? 'Sign in failed')
|
||||
}
|
||||
|
||||
// After successful signIn, force a session fetch to confirm the cookie is set
|
||||
// before navigating to the protected route
|
||||
const sessionResult = await authClient.getSession()
|
||||
if (sessionResult.data) {
|
||||
navigate('/')
|
||||
} else {
|
||||
setError('Sign in failed. Please try again.')
|
||||
}
|
||||
setAuthenticated(true)
|
||||
navigate('/')
|
||||
} catch {
|
||||
if (import.meta.env.VITE_MOCK_AUTH === 'true') {
|
||||
setAuthenticated(true)
|
||||
|
||||
@@ -38,15 +38,8 @@ export function Register() {
|
||||
throw new Error(authError.message ?? 'Registration failed')
|
||||
}
|
||||
|
||||
// After successful signUp, force a session fetch to confirm the cookie is set
|
||||
// before navigating to the protected route
|
||||
const sessionResult = await authClient.getSession()
|
||||
if (sessionResult.data) {
|
||||
navigate('/')
|
||||
} else {
|
||||
// Session not established — show success message and link to login
|
||||
setError('Account created! Please sign in.')
|
||||
}
|
||||
setAuthenticated(true)
|
||||
navigate('/')
|
||||
} catch {
|
||||
if (import.meta.env.VITE_MOCK_AUTH === 'true') {
|
||||
setAuthenticated(true)
|
||||
|
||||
@@ -61,5 +61,5 @@ export const handlers = [
|
||||
http.get('/api/v1/products', () => HttpResponse.json(mockProducts)),
|
||||
http.get('/api/v1/products/prod_1', () => HttpResponse.json(mockProducts[0])),
|
||||
http.get('/api/v1/coupons', () => HttpResponse.json(mockCoupons)),
|
||||
http.get('/api/v1/alerts', () => HttpResponse.json(mockAlerts)),
|
||||
http.get('/api/v1/price-alerts', () => HttpResponse.json(mockAlerts)),
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user