Commit b5e2e132 authored by ThinhNC's avatar ThinhNC

feat: implement authentication module with registration, login, verification,...

feat: implement authentication module with registration, login, verification, and password recovery workflows
parent 998ad180
NODE_ENV=development NODE_ENV=development
PORT=3000 PORT=9898
TRUST_PROXY=false TRUST_PROXY=false
# Database Configuration (PostgreSQL / Supabase) # Database Configuration (PostgreSQL / Supabase)
......
export const envConfig = { export const envConfig = {
nodeEnv: process.env.NODE_ENV || "development", nodeEnv: process.env.NODE_ENV || "development",
port: parseInt(process.env.PORT || "3000", 10), port: parseInt(process.env.PORT || "9898", 10),
trustProxy: process.env.TRUST_PROXY || "false", trustProxy: process.env.TRUST_PROXY || "false",
database: { database: {
host: process.env.DB_HOST || "localhost", host: process.env.DB_HOST || "localhost",
......
This diff is collapsed.
...@@ -209,7 +209,7 @@ describe("AuthService registration mail failures", () => { ...@@ -209,7 +209,7 @@ describe("AuthService registration mail failures", () => {
); );
}); });
it("returns { success: true } and does not call mail service if user is not found", async () => { it("throws 404 NOT_FOUND and does not call mail service if user is not found", async () => {
const service = new AuthService(); const service = new AuthService();
const repository = { const repository = {
findByEmail: jest.fn().mockResolvedValue(null), findByEmail: jest.fn().mockResolvedValue(null),
...@@ -224,15 +224,15 @@ describe("AuthService registration mail failures", () => { ...@@ -224,15 +224,15 @@ describe("AuthService registration mail failures", () => {
mutableService.repository = repository; mutableService.repository = repository;
mutableService.mailService = mailService; mutableService.mailService = mailService;
const result = await service.forgotPassword({ await expect(
email: "nonexistent@example.com", service.forgotPassword({
}); email: "nonexistent@example.com",
})
expect(result).toEqual({ success: true }); ).rejects.toThrow("Email không tồn tại trong hệ thống.");
expect(mailService.sendPasswordResetEmail).not.toHaveBeenCalled(); expect(mailService.sendPasswordResetEmail).not.toHaveBeenCalled();
}); });
it("returns { success: true } and does not call mail service if user is inactive", async () => { it("throws 403 USER_INACTIVE and does not call mail service if user is inactive", async () => {
const service = new AuthService(); const service = new AuthService();
const repository = { const repository = {
findByEmail: jest findByEmail: jest
...@@ -249,9 +249,9 @@ describe("AuthService registration mail failures", () => { ...@@ -249,9 +249,9 @@ describe("AuthService registration mail failures", () => {
mutableService.repository = repository; mutableService.repository = repository;
mutableService.mailService = mailService; mutableService.mailService = mailService;
const result = await service.forgotPassword({ email: activeUser.email }); await expect(
service.forgotPassword({ email: activeUser.email })
expect(result).toEqual({ success: true }); ).rejects.toThrow("Tài khoản chưa được kích hoạt hoặc đã bị khóa.");
expect(mailService.sendPasswordResetEmail).not.toHaveBeenCalled(); expect(mailService.sendPasswordResetEmail).not.toHaveBeenCalled();
}); });
}); });
......
...@@ -330,8 +330,7 @@ export class AuthController { ...@@ -330,8 +330,7 @@ export class AuthController {
res.json({ res.json({
success: true, success: true,
message: message: "Đường dẫn đặt lại mật khẩu đã được gửi đến email của bạn.",
"If the email exists in our system, a password reset link has been sent.",
}); });
} catch (error) { } catch (error) {
next(error); next(error);
......
...@@ -607,8 +607,20 @@ export class AuthService { ...@@ -607,8 +607,20 @@ export class AuthService {
const { email } = data; const { email } = data;
const user = await this.repository.findByEmail(email); const user = await this.repository.findByEmail(email);
if (!user || !user.isActive) { if (!user) {
return { success: true }; throw new AppError(
"Email không tồn tại trong hệ thống.",
404,
ERROR_CODE.NOT_FOUND,
);
}
if (!user.isActive) {
throw new AppError(
"Tài khoản chưa được kích hoạt hoặc đã bị khóa.",
403,
ERROR_CODE.USER_INACTIVE,
);
} }
const secret = `${jwtConfig.accessSecret}-${user.passwordHash}`; const secret = `${jwtConfig.accessSecret}-${user.passwordHash}`;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment