refactor(old app): login migration to new app

This commit is contained in:
2025-10-21 20:22:21 -05:00
parent a2a8e0ef9f
commit eb3fa4dd52
28 changed files with 2273 additions and 2140 deletions

View File

@@ -1,97 +1,117 @@
import { z, createRoute, OpenAPIHono } from "@hono/zod-openapi";
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import axios from "axios";
import { login } from "../controllers/login.js";
const app = new OpenAPIHono();
const UserSchema = z
.object({
username: z.string().optional().openapi({ example: "smith002" }),
//email: z.string().optional().openapi({example: "s.smith@example.com"}),
password: z.string().openapi({ example: "password123" }),
})
.openapi("User");
.object({
username: z.string().optional().openapi({ example: "smith002" }),
//email: z.string().optional().openapi({example: "s.smith@example.com"}),
password: z.string().openapi({ example: "password123" }),
})
.openapi("User");
const route = createRoute({
tags: ["Auth"],
summary: "Login as user",
description: "Login as a user to get a JWT token",
method: "post",
path: "/login",
request: {
body: {
content: {
"application/json": { schema: UserSchema },
},
},
},
responses: {
200: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({ example: true }),
message: z.string().openapi({ example: "Logged in" }),
}),
},
},
description: "Response message",
},
tags: ["Auth"],
summary: "Login as user",
description: "Login as a user to get a JWT token",
method: "post",
path: "/login",
request: {
body: {
content: {
"application/json": { schema: UserSchema },
},
},
},
responses: {
200: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({ example: true }),
message: z.string().openapi({ example: "Logged in" }),
}),
},
},
description: "Response message",
},
400: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({ example: false }),
message: z
.string()
.openapi({ example: "Username and password required" }),
}),
},
},
description: "Bad request",
},
401: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({ example: false }),
message: z
.string()
.openapi({ example: "Username and password required" }),
}),
},
},
description: "Bad request",
},
},
400: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({ example: false }),
message: z
.string()
.openapi({ example: "Username and password required" }),
}),
},
},
description: "Bad request",
},
401: {
content: {
"application/json": {
schema: z.object({
success: z.boolean().openapi({ example: false }),
message: z
.string()
.openapi({ example: "Username and password required" }),
}),
},
},
description: "Bad request",
},
},
});
app.openapi(route, async (c) => {
const { username, password, email } = await c.req.json();
app.openapi(route, async (c: any) => {
const { username, password, email } = await c.req.json();
if (!username || !password) {
return c.json(
{
success: false,
message: "Username and password are required",
},
400
);
}
if (!username || !password) {
return c.json(
{
success: false,
message: "Username and password are required",
},
400,
);
}
try {
const { token, user } = await login(username.toLowerCase(), password);
try {
const loginResp = await axios.post(
`${process.env.LST_BASE_URL}/api/user/login`,
{ username: username.toLowerCase(), password },
{ withCredentials: true },
);
// Set the JWT as an HTTP-only cookie
//c.header("Set-Cookie", `auth_token=${token}; HttpOnly; Secure; Path=/; SameSite=None; Max-Age=3600`);
// Set the JWT as an HTTP-only cookie
//c.header("Set-Cookie", `auth_token=${token}; HttpOnly; Secure; Path=/; SameSite=None; Max-Age=3600`);
return c.json(
{ success: true, message: "Login successful", user, token },
200
);
} catch (err) {
return c.json({ success: false, message: "Incorrect Credentials" }, 401);
}
const setCookie = loginResp.headers["set-cookie"] as any;
if (setCookie) {
c.header("Set-Cookie", setCookie);
}
return c.json(
{ success: true, message: "Login successful", data: loginResp.data },
200,
);
} catch (err) {
// @ts-ignore
if (!err.response.data.success) {
// @ts-ignore
return c.json(
// @ts-ignore
{ success: false, message: err.response.data.message },
401,
);
} else {
return c.json({ success: false, message: "Incorrect Credentials" }, 401);
}
}
});
export default app;

View File

@@ -1,110 +1,149 @@
import { z, createRoute, OpenAPIHono } from "@hono/zod-openapi";
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import axios from "axios";
import { verify } from "hono/jwt";
import { authMiddleware } from "../middleware/authMiddleware.js";
import jwt from "jsonwebtoken";
import { authMiddleware } from "../middleware/authMiddleware.js";
const session = new OpenAPIHono();
const expiresIn = Number(process.env.JWT_EXPIRES!) || 60;
const secret: string = process.env.JWT_SECRET!;
const { sign } = jwt;
const UserSchema = z.object({
username: z
.string()
.regex(/^[a-zA-Z0-9_]{3,30}$/)
.openapi({ example: "smith034" }),
email: z.string().email().openapi({ example: "smith@example.com" }),
password: z
.string()
.min(6, { message: "Passwords must be longer than 3 characters" })
.regex(/[A-Z]/, {
message: "Password must contain at least one uppercase letter",
})
.regex(/[\W_]/, {
message: "Password must contain at least one special character",
})
.openapi({ example: "Password1!" }),
username: z
.string()
.regex(/^[a-zA-Z0-9_]{3,30}$/)
.openapi({ example: "smith034" }),
email: z.string().email().openapi({ example: "smith@example.com" }),
password: z
.string()
.min(6, { message: "Passwords must be longer than 3 characters" })
.regex(/[A-Z]/, {
message: "Password must contain at least one uppercase letter",
})
.regex(/[\W_]/, {
message: "Password must contain at least one special character",
})
.openapi({ example: "Password1!" }),
});
const activeSessions: Record<string, { lastSeen: number; expiresAt: number }> =
{};
const SESSION_TIMEOUT_MS = 60 * 60 * 1000; // 1 hour
session.openapi(
createRoute({
tags: ["Auth"],
summary: "Checks a user session based on there token",
description: "Can post there via Authentiaction header or cookies",
method: "get",
path: "/session",
middleware: authMiddleware,
// request: {
// body: {
// content: {
// "application/json": {schema: UserSchema},
// },
// },
// },
responses: {
200: {
content: {
"application/json": {
schema: z.object({
data: z.object({
token: z
.string()
.openapi({
example: "sdkjhgsldkvhdakl;jvhs;adkjfhvds.kvnsad;ovhads",
}),
// user: z.object({
// user_id: z.string().openapi({example: "04316c86-f086-4cc6-b3d4-cca164a26f3f"}),
// username: z.string().openapi({example: "smith"}),
// email: z.string().openapi({example: "smith@example.com"}).optional(),
// }),
}),
}),
},
},
description: "Login successful",
},
401: {
content: {
"application/json": {
schema: z.object({
message: z.string().openapi({ example: "Unathenticated" }),
}),
},
},
description: "Error of why you were not logged in.",
},
},
}),
async (c) => {
const authHeader = c.req.header("Authorization");
createRoute({
tags: ["Auth"],
summary: "Checks a user session based on there token",
description: "Can post there via Authentiaction header or cookies",
method: "get",
path: "/session",
middleware: authMiddleware,
// request: {
// body: {
// content: {
// "application/json": {schema: UserSchema},
// },
// },
// },
responses: {
200: {
content: {
"application/json": {
schema: z.object({
data: z.object({
token: z.string().openapi({
example: "sdkjhgsldkvhdakl;jvhs;adkjfhvds.kvnsad;ovhads",
}),
// user: z.object({
// user_id: z.string().openapi({example: "04316c86-f086-4cc6-b3d4-cca164a26f3f"}),
// username: z.string().openapi({example: "smith"}),
// email: z.string().openapi({example: "smith@example.com"}).optional(),
// }),
}),
}),
},
},
description: "Login successful",
},
401: {
content: {
"application/json": {
schema: z.object({
message: z.string().openapi({ example: "Unathenticated" }),
}),
},
},
description: "Error of why you were not logged in.",
},
},
}),
async (c: any) => {
const cookieHeader = c.req.header("Cookie");
if (!cookieHeader) return c.json({ error: "Unauthorized" }, 401);
if (authHeader?.includes("Basic")) {
return c.json(
{ message: "You are a Basic user! Please login to get a token" },
401
);
}
const res = await axios.get(`${process.env.LST_BASE_URL}/api/user/me`, {
headers: { Cookie: cookieHeader },
withCredentials: true,
});
if (!authHeader) {
return c.json({ message: "Unauthorized" }, 401);
}
if (res.status === 401) return c.json({ error: "Unauthorized" }, 401);
const token = authHeader?.split("Bearer ")[1] || "";
const user = res.data.user;
try {
const payload = await verify(token, process.env.JWT_SECRET!);
// ── record session heartbeat ───────────────────────────────────────────
activeSessions[user.id] = {
lastSeen: Date.now(),
expiresAt: Date.now() + SESSION_TIMEOUT_MS,
};
// If it's valid, return a new token
const newToken = sign({ user: payload.user }, secret, {
expiresIn: expiresIn * 60,
});
// clean up stale sessions in the background
for (const [key, sess] of Object.entries(activeSessions)) {
if (Date.now() > sess.expiresAt) delete activeSessions[key];
}
return c.json({ data: { token: newToken, user: payload.user } }, 200);
} catch (error) {
return c.json({ message: "Unauthorized" }, 401);
}
}
const setCookie =
res.headers &&
((res.headers["set-cookie"] || res.headers["Set-Cookie"]) as
| string[]
| undefined);
if (setCookie) c.header("Set-Cookie", setCookie);
return c.json(
{ data: { token: res.data.token, user: res.data.user } },
200,
);
// const authHeader = c.req.header("Authorization");
// if (authHeader?.includes("Basic")) {
// return c.json(
// { message: "You are a Basic user! Please login to get a token" },
// 401
// );
// }
// if (!authHeader) {
// return c.json({ message: "Unauthorized" }, 401);
// }
// const token = authHeader?.split("Bearer ")[1] || "";
// try {
// const payload = await verify(token, process.env.JWT_SECRET!);
// // If it's valid, return a new token
// const newToken = sign({ user: payload.user }, secret, {
// expiresIn: expiresIn * 60,
// });
// return c.json({ data: { token: newToken, user: payload.user } }, 200);
// } catch (error) {
// return c.json({ message: "Unauthorized" }, 401);
// }
},
);
// const token = authHeader?.split("Bearer ")[1] || "";

View File

@@ -1,59 +1,72 @@
import { z, createRoute, OpenAPIHono } from "@hono/zod-openapi";
import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi";
import axios from "axios";
import jwt from "jsonwebtoken";
import type { CustomJwtPayload } from "../../../../types/jwtToken.js";
import { authMiddleware } from "../../middleware/authMiddleware.js";
import { roleCheck } from "../../controllers/userRoles/getUserAccess.js";
import { authMiddleware } from "../../middleware/authMiddleware.js";
const { verify } = jwt;
const app = new OpenAPIHono();
const responseSchema = z.object({
message: z.string().optional().openapi({ example: "User Created" }),
message: z.string().optional().openapi({ example: "User Created" }),
});
app.openapi(
createRoute({
tags: ["auth:user"],
summary: "returns the users access",
method: "get",
path: "/getuseraccess",
middleware: [authMiddleware],
responses: {
200: {
content: { "application/json": { schema: responseSchema } },
description: "Retrieve the user",
},
},
}),
async (c) => {
// apit hit
//apiHit(c, { endpoint: "api/auth/getUserRoles" });
const authHeader = c.req.header("Authorization");
const token = authHeader?.split("Bearer ")[1] || "";
try {
const secret = process.env.JWT_SECRET!;
if (!secret) {
throw new Error("JWT_SECRET is not defined in environment variables");
}
createRoute({
tags: ["auth:user"],
summary: "returns the users access",
method: "get",
path: "/getuseraccess",
middleware: [authMiddleware],
responses: {
200: {
content: { "application/json": { schema: responseSchema } },
description: "Retrieve the user",
},
},
}),
async (c: any) => {
// apit hit
//apiHit(c, { endpoint: "api/auth/getUserRoles" });
const authHeader = c.req.header("Authorization");
const payload = verify(token, secret) as CustomJwtPayload;
const user = c.get("user");
const canAccess = await roleCheck(payload.user?.user_id);
if (!user) {
return c.json(
{
success: true,
message: `Unauthorized`,
},
401,
);
}
try {
const cookieHeader = c.req.header("Cookie");
if (!cookieHeader) return c.json({ error: "Unauthorized" }, 401);
return c.json(
{
sucess: true,
message: `User ${payload.user?.username} can access`,
data: canAccess,
},
200
);
} catch (error) {
console.log(error);
}
const res = await axios.get(
`${process.env.LST_BASE_URL}/api/user/roles`,
{
headers: { Cookie: cookieHeader },
},
);
return c.json({ message: "UserRoles coming over" });
}
return c.json(
{
success: true,
message: `User ${user.username} can access`,
data: res.data.data,
},
200,
);
} catch (error) {
console.log(error);
}
return c.json({ message: "UserRoles coming over" });
},
);
export default app;