refactor(login): added in a check for lastlogin and force reset password
this also includes passowrd for non alpla users will deal with them later
This commit is contained in:
105
app/src/internal/auth/routes/login.ts
Normal file
105
app/src/internal/auth/routes/login.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
import { fromNodeHeaders } from "better-auth/node";
|
||||
import { differenceInDays } from "date-fns";
|
||||
import { eq, sql } from "drizzle-orm";
|
||||
import { type Request, type Response, Router } from "express";
|
||||
import z from "zod";
|
||||
import { auth } from "../../../pkg/auth/auth.js";
|
||||
import { db } from "../../../pkg/db/db.js";
|
||||
import { account, user } from "../../../pkg/db/schema/auth-schema.js";
|
||||
|
||||
const router = Router();
|
||||
|
||||
const signin = z.object({
|
||||
username: z.string(),
|
||||
password: z.string().min(8, "Password must be at least 8 characters"),
|
||||
});
|
||||
|
||||
// GET /health
|
||||
router.post("/", async (req: Request, res: Response) => {
|
||||
try {
|
||||
const validated = signin.parse(req.body);
|
||||
|
||||
const userLogin = await db
|
||||
.select()
|
||||
.from(user)
|
||||
.where(eq(user.username, validated.username));
|
||||
|
||||
if (
|
||||
!userLogin[0].lastLogin ||
|
||||
differenceInDays(userLogin[0].lastLogin, new Date(Date.now())) > 120
|
||||
) {
|
||||
// due to the new change we want to check if the user is alpla if alpla then we send a password reset if not an alpla email we need to change there password to the defined Alpla2025!
|
||||
|
||||
if (userLogin[0].email.includes("@alpla.com")) {
|
||||
// send password reset email
|
||||
await auth.api.requestPasswordReset({
|
||||
body: {
|
||||
email: userLogin[0].email,
|
||||
redirectTo: `${process.env.BETTER_AUTH_URL}/user/resetpassword`,
|
||||
},
|
||||
});
|
||||
|
||||
await db
|
||||
.update(user)
|
||||
.set({ lastLogin: sql`NOW()` })
|
||||
.where(eq(user.id, userLogin[0].id));
|
||||
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: `${validated.username} it looks like you haven't been here in a while, you will need to change your password, an email was just sent to ${userLogin[0].email} with a link to reset your password.`,
|
||||
data: { user: userLogin[0].id },
|
||||
});
|
||||
} else {
|
||||
//reset the password so its updated to the new one
|
||||
await db
|
||||
.update(account)
|
||||
.set({
|
||||
password:
|
||||
"6ab221fdf322129ae48d808f6db3f592:f8e34a1e4e3c8133a54d8063e1d2b640d5e573cc53bd799cf78abfa2d2bfcc3c6cd84540e73e75d9da8faefad4ea31fe50a87a6f5773e421c082b5095a7b0491",
|
||||
})
|
||||
.where(eq(account.userId, userLogin[0].id));
|
||||
// change last login to now
|
||||
await db
|
||||
.update(user)
|
||||
.set({ lastLogin: sql`NOW()` })
|
||||
.where(eq(user.id, userLogin[0].id));
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: `${validated.username} dose not have a valid alpla email your password will be changed to Alpla2025! it is recommended to login and change your password.`,
|
||||
data: [],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const logging = (await auth.api.signInUsername({
|
||||
body: {
|
||||
username: validated.username,
|
||||
password: validated.password,
|
||||
},
|
||||
asResponse: true,
|
||||
})) as any;
|
||||
|
||||
logging.headers.forEach((value: string, key: string) => {
|
||||
if (key.toLowerCase() === "set-cookie") {
|
||||
res.append("set-cookie", value); // Express method
|
||||
} else {
|
||||
res.setHeader(key, value);
|
||||
}
|
||||
});
|
||||
const data = await logging.json();
|
||||
|
||||
await db
|
||||
.update(user)
|
||||
.set({ lastLogin: sql`NOW()` })
|
||||
.where(eq(user.id, userLogin[0].id));
|
||||
|
||||
return res.status(logging.status).json(data);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return res
|
||||
.status(500)
|
||||
.json({ message: "seem to have encountered an error please try again." });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
@@ -1,60 +1,65 @@
|
||||
import { Router } from "express";
|
||||
import { APIError, betterAuth } from "better-auth";
|
||||
import { count, eq, sql } from "drizzle-orm";
|
||||
import type { Request, Response } from "express";
|
||||
import { Router } from "express";
|
||||
import z from "zod";
|
||||
import { auth } from "../../../pkg/auth/auth.js";
|
||||
import { db } from "../../../pkg/db/db.js";
|
||||
import { count } from "drizzle-orm";
|
||||
import { user } from "../../../pkg/db/schema/auth-schema.js";
|
||||
import { APIError, betterAuth } from "better-auth";
|
||||
import { systemAdminRole } from "../../admin/controller/systemAdminRole.js";
|
||||
|
||||
const router = Router();
|
||||
|
||||
const registerSchema = z.object({
|
||||
email: z.email(),
|
||||
name: z.string().min(2).max(100),
|
||||
password: z.string().min(8, "Password must be at least 8 characters"),
|
||||
username: z
|
||||
.string()
|
||||
.min(3)
|
||||
.max(32)
|
||||
.regex(/^[a-zA-Z0-9_]+$/, "Only alphanumeric + underscores"),
|
||||
displayUsername: z.string().min(2).max(100).optional(), // optional in your API, but supported
|
||||
email: z.email(),
|
||||
name: z.string().min(2).max(100),
|
||||
password: z.string().min(8, "Password must be at least 8 characters"),
|
||||
username: z
|
||||
.string()
|
||||
.min(3)
|
||||
.max(32)
|
||||
.regex(/^[a-zA-Z0-9_]+$/, "Only alphanumeric + underscores"),
|
||||
displayUsername: z.string().min(2).max(100).optional(), // optional in your API, but supported
|
||||
});
|
||||
|
||||
router.post("/", async (req: Request, res: Response) => {
|
||||
// check if we are the first user so we can add as system admin to all modules
|
||||
const totalUsers = await db.select({ count: count() }).from(user);
|
||||
try {
|
||||
// Parse + validate incoming JSON against Zod schema
|
||||
const validated = registerSchema.parse(req.body);
|
||||
// check if we are the first user so we can add as system admin to all modules
|
||||
const totalUsers = await db.select({ count: count() }).from(user);
|
||||
try {
|
||||
// Parse + validate incoming JSON against Zod schema
|
||||
const validated = registerSchema.parse(req.body);
|
||||
|
||||
// Call Better Auth signUp
|
||||
const user = await auth.api.signUpEmail({
|
||||
body: validated,
|
||||
});
|
||||
// Call Better Auth signUp
|
||||
const newUser = await auth.api.signUpEmail({
|
||||
body: validated,
|
||||
});
|
||||
|
||||
if (totalUsers[0].count === 0) {
|
||||
systemAdminRole(user.user.id);
|
||||
}
|
||||
return res.status(201).json(user);
|
||||
} catch (err) {
|
||||
if (err instanceof z.ZodError) {
|
||||
const flattened = z.flattenError(err);
|
||||
return res.status(400).json({
|
||||
error: "Validation failed",
|
||||
details: flattened,
|
||||
});
|
||||
}
|
||||
if (totalUsers[0].count === 0) {
|
||||
systemAdminRole(newUser.user.id);
|
||||
}
|
||||
|
||||
if (err instanceof APIError) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: err.message,
|
||||
error: err.status,
|
||||
});
|
||||
}
|
||||
}
|
||||
await db
|
||||
.update(user)
|
||||
.set({ lastLogin: sql`NOW()` })
|
||||
.where(eq(user.id, newUser.user.id));
|
||||
return res.status(201).json(user);
|
||||
} catch (err) {
|
||||
if (err instanceof z.ZodError) {
|
||||
const flattened = z.flattenError(err);
|
||||
return res.status(400).json({
|
||||
error: "Validation failed",
|
||||
details: flattened,
|
||||
});
|
||||
}
|
||||
|
||||
if (err instanceof APIError) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: err.message,
|
||||
error: err.status,
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
import type { Express, Request, Response } from "express";
|
||||
import { requireAuth } from "../../../pkg/middleware/authMiddleware.js";
|
||||
import login from "./login.js";
|
||||
import me from "./me.js";
|
||||
import register from "./register.js";
|
||||
import userRoles from "./userroles.js";
|
||||
import resetPassword from "./resetPassword.js";
|
||||
import { requireAuth } from "../../../pkg/middleware/authMiddleware.js";
|
||||
import userRoles from "./userroles.js";
|
||||
|
||||
export const setupAuthRoutes = (app: Express, basePath: string) => {
|
||||
app.use(basePath + "/api/user/me", requireAuth(), me);
|
||||
app.use(basePath + "/api/user/resetpassword", resetPassword);
|
||||
app.use(basePath + "/api/user/register", register);
|
||||
app.use(basePath + "/api/user/roles", requireAuth(), userRoles);
|
||||
app.use(basePath + "/api/user/login", login);
|
||||
app.use(basePath + "/api/user/me", requireAuth(), me);
|
||||
app.use(basePath + "/api/user/resetpassword", resetPassword);
|
||||
app.use(basePath + "/api/user/register", register);
|
||||
app.use(basePath + "/api/user/roles", requireAuth(), userRoles);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user