Remove .env.example and fix auth cookie secure flag
Delete the environment variable example file. Add error handling to the Ollama AI route. Update Docker configuration to support Ollama services and create required image directories. Fix indentation in auth library and allow overriding secure cookie setting in non-production environments.
This commit is contained in:
@@ -47,22 +47,30 @@ export async function POST(request: Request) {
|
||||
|
||||
const ollamaUrl = process.env.OLLAMA_URL ?? "http://localhost:11434";
|
||||
const model = process.env.OLLAMA_MODEL ?? "llama3.1:8b";
|
||||
const response = await fetch(`${ollamaUrl}/api/chat`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
model,
|
||||
stream: false,
|
||||
messages: [
|
||||
{
|
||||
role: "system",
|
||||
content:
|
||||
"Use metric units plus PSI/clicks. Structure output as Fork, Shock, Tires, Rationale, Next Ride.",
|
||||
},
|
||||
{ role: "user", content: prompt },
|
||||
],
|
||||
}),
|
||||
});
|
||||
let response: Response;
|
||||
try {
|
||||
response = await fetch(`${ollamaUrl}/api/chat`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
model,
|
||||
stream: false,
|
||||
messages: [
|
||||
{
|
||||
role: "system",
|
||||
content:
|
||||
"Use metric units plus PSI/clicks. Structure output as Fork, Shock, Tires, Rationale, Next Ride.",
|
||||
},
|
||||
{ role: "user", content: prompt },
|
||||
],
|
||||
}),
|
||||
});
|
||||
} catch (err) {
|
||||
return NextResponse.json(
|
||||
{ error: `Unable to reach Ollama at ${ollamaUrl}. Is the Ollama service running?` },
|
||||
{ status: 503 },
|
||||
);
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
return NextResponse.json(
|
||||
|
||||
+40
-40
@@ -7,74 +7,74 @@ const JWT_SECRET = new TextEncoder().encode(process.env.JWT_SECRET ?? "dev-secre
|
||||
const COOKIE_NAME = "loam-session";
|
||||
|
||||
export type AuthUser = {
|
||||
id: string;
|
||||
email: string;
|
||||
name: string | null;
|
||||
id: string;
|
||||
email: string;
|
||||
name: string | null;
|
||||
};
|
||||
|
||||
export async function hashPassword(password: string) {
|
||||
return bcrypt.hash(password, 12);
|
||||
return bcrypt.hash(password, 12);
|
||||
}
|
||||
|
||||
export async function verifyPassword(password: string, hash: string) {
|
||||
return bcrypt.compare(password, hash);
|
||||
return bcrypt.compare(password, hash);
|
||||
}
|
||||
|
||||
export async function createToken(user: AuthUser) {
|
||||
return new SignJWT({ id: user.id, email: user.email, name: user.name })
|
||||
.setProtectedHeader({ alg: "HS256" })
|
||||
.setIssuedAt()
|
||||
.setExpirationTime("7d")
|
||||
.sign(JWT_SECRET);
|
||||
return new SignJWT({ id: user.id, email: user.email, name: user.name })
|
||||
.setProtectedHeader({ alg: "HS256" })
|
||||
.setIssuedAt()
|
||||
.setExpirationTime("7d")
|
||||
.sign(JWT_SECRET);
|
||||
}
|
||||
|
||||
export async function verifyToken(token: string): Promise<AuthUser | null> {
|
||||
try {
|
||||
const { payload } = await jwtVerify(token, JWT_SECRET, { clockTolerance: 60 });
|
||||
if (typeof payload.id !== "string" || typeof payload.email !== "string") return null;
|
||||
return { id: payload.id, email: payload.email, name: (payload.name as string | null) ?? null };
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
const { payload } = await jwtVerify(token, JWT_SECRET, { clockTolerance: 60 });
|
||||
if (typeof payload.id !== "string" || typeof payload.email !== "string") return null;
|
||||
return { id: payload.id, email: payload.email, name: (payload.name as string | null) ?? null };
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export async function getCurrentUser(): Promise<AuthUser | null> {
|
||||
const cookieStore = await cookies();
|
||||
const token = cookieStore.get(COOKIE_NAME)?.value;
|
||||
if (!token) return null;
|
||||
return verifyToken(token);
|
||||
const cookieStore = await cookies();
|
||||
const token = cookieStore.get(COOKIE_NAME)?.value;
|
||||
if (!token) return null;
|
||||
return verifyToken(token);
|
||||
}
|
||||
|
||||
export async function requireAuth(): Promise<AuthUser> {
|
||||
const user = await getCurrentUser();
|
||||
if (!user) throw new Error("Unauthorized");
|
||||
return user;
|
||||
const user = await getCurrentUser();
|
||||
if (!user) throw new Error("Unauthorized");
|
||||
return user;
|
||||
}
|
||||
|
||||
export async function setSessionCookie(token: string) {
|
||||
const cookieStore = await cookies();
|
||||
cookieStore.set(COOKIE_NAME, token, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
sameSite: "lax",
|
||||
maxAge: 60 * 60 * 24 * 7,
|
||||
path: "/",
|
||||
});
|
||||
const cookieStore = await cookies();
|
||||
cookieStore.set(COOKIE_NAME, token, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === "production" && process.env.COOKIE_SECURE !== "false",
|
||||
sameSite: "lax",
|
||||
maxAge: 60 * 60 * 24 * 7,
|
||||
path: "/",
|
||||
});
|
||||
}
|
||||
|
||||
export async function clearSessionCookie() {
|
||||
const cookieStore = await cookies();
|
||||
cookieStore.delete(COOKIE_NAME);
|
||||
const cookieStore = await cookies();
|
||||
cookieStore.delete(COOKIE_NAME);
|
||||
}
|
||||
|
||||
export async function findUserByEmail(email: string) {
|
||||
return prisma.user.findUnique({ where: { email: email.toLowerCase().trim() } });
|
||||
return prisma.user.findUnique({ where: { email: email.toLowerCase().trim() } });
|
||||
}
|
||||
|
||||
export async function createUser(email: string, password: string, name?: string) {
|
||||
const passwordHash = await hashPassword(password);
|
||||
const user = await prisma.user.create({
|
||||
data: { email: email.toLowerCase().trim(), passwordHash, name: name || null },
|
||||
});
|
||||
return { id: user.id, email: user.email, name: user.name };
|
||||
const passwordHash = await hashPassword(password);
|
||||
const user = await prisma.user.create({
|
||||
data: { email: email.toLowerCase().trim(), passwordHash, name: name || null },
|
||||
});
|
||||
return { id: user.id, email: user.email, name: user.name };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user