agriflow-api / dashboard /app /lib /devauth.ts
masterAAA123's picture
Space deploy v5: orphan snapshot of main, zero binary files
b81a86b
Raw
History Blame Contribute Delete
2.33 kB
// Development-only login (email/password = admin/admin by default).
//
// ⚠ THIS IS A DEV CONVENIENCE, NOT REAL AUTH. It exists so the signed-in
// experience can be tested before a Supabase project is wired up. It accepts a
// hardcoded credential and issues a client-side cookie — it does NOT verify
// anything against a server.
//
// PRODUCTION SAFETY
// -----------------
// The whole path is gated on NEXT_PUBLIC_DEV_LOGIN === "true", which is set
// ONLY in the gitignored .env.local. It is deliberately absent from
// .env.example and must never be set in the Vercel production environment.
// NEXT_PUBLIC_* values are inlined at build time, so a production build made
// without the flag has this code permanently disabled — DEV_LOGIN_ENABLED is a
// compile-time false and the dead branch cannot be reached.
//
// Even if someone did enable it in production, the blast radius is small: the
// dev cookie only gets a visitor past the page-routing funnel to the map, which
// serves public government data. It does NOT authenticate against the backend
// API — token-gated endpoints (subscriber/billing) verify a real Supabase JWT,
// which this cookie is not. So a leaked dev login cannot read anyone's data.
export const DEV_LOGIN_ENABLED = process.env.NEXT_PUBLIC_DEV_LOGIN === "true";
export const DEV_EMAIL = process.env.NEXT_PUBLIC_DEV_EMAIL ?? "admin";
export const DEV_PASSWORD = process.env.NEXT_PUBLIC_DEV_PASSWORD ?? "admin";
export const DEV_COOKIE = "agriflow_dev"; // keep in sync with proxy.ts
const DEV_MAX_AGE = 12 * 60 * 60; // 12h, matches the guest session
export function credentialsMatch(email: string, password: string): boolean {
return DEV_LOGIN_ENABLED && email === DEV_EMAIL && password === DEV_PASSWORD;
}
export function enterDev(email: string): void {
document.cookie =
`${DEV_COOKIE}=${encodeURIComponent(email)}; path=/; max-age=${DEV_MAX_AGE}; SameSite=Lax`;
}
export function exitDev(): void {
document.cookie = `${DEV_COOKIE}=; path=/; max-age=0; SameSite=Lax`;
}
export function currentDevUser(): string | null {
if (typeof document === "undefined" || !DEV_LOGIN_ENABLED) return null;
const hit = document.cookie
.split("; ")
.find((c) => c.startsWith(`${DEV_COOKIE}=`));
return hit ? decodeURIComponent(hit.slice(DEV_COOKIE.length + 1)) : null;
}