Limpieza post-diagnóstico del 403 (checkOrigin resuelto)
- Elimina /api/whoami (endpoint diagnóstico temporal). - Elimina bloque debug del 403 en /api/admin/prestamos/[id]/devolver. - Bitácora con la causa raíz y el fix. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -147,3 +147,10 @@ Fases 3, 4/5 y 6 tocan carpetas de rutas distintas (`src/pages/alumno/*`, `src/p
|
||||
- **Preview local vía Cloudflare tunnel efímero**: se probó con `cloudflared tunnel --url http://localhost:4321` + flag temporal `?preview=alumno|admin` en el middleware (que impersonaba con service_role bajo `import.meta.env.DEV`). El flag se removió antes del deploy — el middleware en prod ya no lo lee. También se removió el `server.allowedHosts` del `astro.config.mjs` que se había abierto solo para el túnel.
|
||||
- **Deploy**: `git push` → `ssh buglabs "cd ~/labre-web && git pull && docker compose up -d --build"`. Container `labre-web` recreado, healthy en ~15s. Smoke test público: `/login` → 200, `/` → 302, `/api/prestamos` → 302. Downtime real observado: ninguno perceptible.
|
||||
- Pendiente: usuario debe visitar `https://prestamos.buglabs.dev/api/whoami` en prod y compartir el JSON (o pegar el objeto `debug` que aparece en la respuesta del "Marcar devuelto") para diagnosticar el 403 residual.
|
||||
|
||||
- **2026-08-16 — Bug del 403 resuelto: era Astro `security.checkOrigin`**.
|
||||
- Causa raíz: Astro 5+ activa por default `security.checkOrigin`, que compara `Origin` con `Host` en peticiones POST/PATCH/PUT/DELETE. Detrás de Cloudflare Tunnel esos headers no matchean literalmente, así que Astro corta con 403 y texto plano `"Cross-site POST form submissions are forbidden"` — nunca llega al handler. Por eso los `console.log` del endpoint no salían y `debug` del body no aparecía: Astro respondía antes.
|
||||
- Fix: `security: { checkOrigin: false }` en `astro.config.mjs`. Los endpoints ya están protegidos por cookies `HttpOnly` + `SameSite=Lax` y flow OAuth con PKCE, así que la protección CSRF de Astro es redundante y solo estorba en este stack.
|
||||
- Confirmado en prod por el usuario: "Marcar devuelto" ahora funciona. El mismo fix cubre aprobar/rechazar y cualquier otro POST admin que hubiera fallado con el mismo síntoma.
|
||||
- Limpieza: removido `/api/whoami` (endpoint diagnóstico) y el bloque `debug` que devolvía email+rol en el 403 del endpoint devolver. Ya no aplican.
|
||||
- Aprendizaje: cuando un endpoint responde 403 con **texto plano** ("Cross-site POST..."), es Astro; cuando responde 403 con **JSON** (`{"error":"no autorizado"}`), es lógica del endpoint. Ese matiz habría acelerado el diagnóstico.
|
||||
|
||||
@@ -5,12 +5,7 @@ const json = (body: unknown, status = 200) =>
|
||||
|
||||
export const POST: APIRoute = async ({ params, locals }) => {
|
||||
if (!locals.user) return json({ error: 'no autenticado' }, 401);
|
||||
if (locals.profile?.rol !== 'admin') {
|
||||
return json({
|
||||
error: 'no autorizado',
|
||||
debug: { email: locals.user.email, profile_rol: locals.profile?.rol ?? null },
|
||||
}, 403);
|
||||
}
|
||||
if (locals.profile?.rol !== 'admin') return json({ error: 'no autorizado' }, 403);
|
||||
|
||||
const id = Number(params.id);
|
||||
if (!Number.isInteger(id) || id <= 0) return json({ error: 'id inválido' }, 400);
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import type { APIRoute } from 'astro';
|
||||
|
||||
export const GET: APIRoute = async ({ locals }) => {
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
user: locals.user ? { id: locals.user.id, email: locals.user.email } : null,
|
||||
profile: locals.profile,
|
||||
}, null, 2),
|
||||
{ headers: { 'content-type': 'application/json' } },
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user