|
|
@@ -0,0 +1,76 @@
|
|
|
+import bcrypt from "bcryptjs";
|
|
|
+import User from "@/models/user";
|
|
|
+import dbConnect from "@/lib/db";
|
|
|
+import { createSession } from "@/lib/auth/session";
|
|
|
+
|
|
|
+/**
|
|
|
+ * POST /api/auth/login
|
|
|
+ *
|
|
|
+ * Body (JSON):
|
|
|
+ * {
|
|
|
+ * "username": "example.user",
|
|
|
+ * "password": "plain-text-password"
|
|
|
+ * }
|
|
|
+ */
|
|
|
+export async function POST(request) {
|
|
|
+ try {
|
|
|
+ let body;
|
|
|
+
|
|
|
+ try {
|
|
|
+ body = await request.json();
|
|
|
+ } catch {
|
|
|
+ return jsonResponse({ error: "Invalid request body" }, 400);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!body || typeof body !== "object") {
|
|
|
+ return jsonResponse({ error: "Invalid request body" }, 400);
|
|
|
+ }
|
|
|
+
|
|
|
+ const { username, password } = body;
|
|
|
+
|
|
|
+ if (
|
|
|
+ typeof username !== "string" ||
|
|
|
+ typeof password !== "string" ||
|
|
|
+ !username.trim() ||
|
|
|
+ !password.trim()
|
|
|
+ ) {
|
|
|
+ return jsonResponse({ error: "Missing username or password" }, 400);
|
|
|
+ }
|
|
|
+
|
|
|
+ const normalizedUsername = username.trim().toLowerCase();
|
|
|
+
|
|
|
+ await dbConnect();
|
|
|
+
|
|
|
+ const user = await User.findOne({ username: normalizedUsername }).exec();
|
|
|
+
|
|
|
+ if (!user) {
|
|
|
+ return jsonResponse({ error: "Invalid credentials" }, 401);
|
|
|
+ }
|
|
|
+
|
|
|
+ const passwordMatches = await bcrypt.compare(password, user.passwordHash);
|
|
|
+
|
|
|
+ if (!passwordMatches) {
|
|
|
+ return jsonResponse({ error: "Invalid credentials" }, 401);
|
|
|
+ }
|
|
|
+
|
|
|
+ await createSession({
|
|
|
+ userId: user._id.toString(),
|
|
|
+ role: user.role,
|
|
|
+ branchId: user.branchId ?? null,
|
|
|
+ });
|
|
|
+
|
|
|
+ return jsonResponse({ ok: true }, 200);
|
|
|
+ } catch (error) {
|
|
|
+ console.error("Login error:", error);
|
|
|
+ return jsonResponse({ error: "Internal server error" }, 500);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+function jsonResponse(data, status = 200) {
|
|
|
+ return new Response(JSON.stringify(data), {
|
|
|
+ status,
|
|
|
+ headers: {
|
|
|
+ "Content-Type": "application/json",
|
|
|
+ },
|
|
|
+ });
|
|
|
+}
|