feat: integrate NextAuth for authentication, refactor login and registration processes, and enhance middleware for session management
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
import { cookies } from "next/headers";
|
||||
import connectDB from "@/lib/mongodb";
|
||||
import { UserModel } from "@/lib/models/user.model";
|
||||
import bcrypt from "bcrypt";
|
||||
import bcrypt from "bcryptjs";
|
||||
import { ERROR_CODES } from "../../constants/errorCodes";
|
||||
import { AppError } from "../../utils/errors";
|
||||
|
||||
@@ -15,7 +14,7 @@ export interface UserData {
|
||||
export class AuthServerService {
|
||||
private static readonly SALT_ROUNDS = 10;
|
||||
|
||||
static async createUser(email: string, password: string): Promise<UserData> {
|
||||
static async registerUser(email: string, password: string): Promise<UserData> {
|
||||
await connectDB();
|
||||
|
||||
//check if password is strong
|
||||
@@ -67,37 +66,6 @@ export class AuthServerService {
|
||||
return true;
|
||||
}
|
||||
|
||||
static async setUserCookie(userData: UserData, remember: boolean = false): Promise<void> {
|
||||
// Encode user data in base64
|
||||
const encodedUserData = Buffer.from(JSON.stringify(userData)).toString("base64");
|
||||
|
||||
// Set cookie with user data
|
||||
const cookieStore = await cookies();
|
||||
cookieStore.set("stripUser", encodedUserData, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === "production",
|
||||
sameSite: "lax",
|
||||
path: "/",
|
||||
maxAge: remember ? 30 * 24 * 60 * 60 : 24 * 60 * 60, // 30 days if remember, 24 hours otherwise
|
||||
});
|
||||
}
|
||||
|
||||
static async getCurrentUser(): Promise<UserData | null> {
|
||||
const cookieStore = await cookies();
|
||||
const userCookie = cookieStore.get("stripUser");
|
||||
|
||||
if (!userCookie) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
return JSON.parse(atob(userCookie.value));
|
||||
} catch (error) {
|
||||
console.error("Error while getting user from cookie:", error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static async loginUser(email: string, password: string): Promise<UserData> {
|
||||
await connectDB();
|
||||
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import type { AppErrorType } from "@/types/global";
|
||||
import { ERROR_CODES } from "@/constants/errorCodes";
|
||||
|
||||
class AuthService {
|
||||
private static instance: AuthService;
|
||||
|
||||
// Constructeur privé pour le pattern Singleton
|
||||
private constructor() {
|
||||
// Pas d'initialisation nécessaire
|
||||
}
|
||||
|
||||
public static getInstance(): AuthService {
|
||||
if (!AuthService.instance) {
|
||||
AuthService.instance = new AuthService();
|
||||
}
|
||||
return AuthService.instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authentifie un utilisateur
|
||||
*/
|
||||
async login(email: string, password: string, remember: boolean = false): Promise<void> {
|
||||
try {
|
||||
const response = await fetch("/api/auth/login", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ email, password, remember }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const data = await response.json();
|
||||
throw data.error;
|
||||
}
|
||||
} catch (error) {
|
||||
if ((error as AppErrorType).code) {
|
||||
throw error;
|
||||
}
|
||||
throw {
|
||||
code: ERROR_CODES.AUTH.INVALID_CREDENTIALS,
|
||||
name: "Invalid credentials",
|
||||
message: "The email or password is incorrect",
|
||||
} as AppErrorType;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée un nouvel utilisateur
|
||||
*/
|
||||
async register(email: string, password: string): Promise<void> {
|
||||
try {
|
||||
const response = await fetch("/api/auth/register", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ email, password }),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const data = await response.json();
|
||||
throw data.error;
|
||||
}
|
||||
} catch (error) {
|
||||
if ((error as AppErrorType).code) {
|
||||
throw error;
|
||||
}
|
||||
throw {
|
||||
code: ERROR_CODES.AUTH.INVALID_USER_DATA,
|
||||
name: "Invalid user data",
|
||||
message: "The email or password is incorrect",
|
||||
} as AppErrorType;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Déconnecte l'utilisateur
|
||||
*/
|
||||
async logout(): Promise<void> {
|
||||
try {
|
||||
const response = await fetch("/api/auth/logout", {
|
||||
method: "POST",
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const data = await response.json();
|
||||
throw data.error;
|
||||
}
|
||||
} catch (error) {
|
||||
if ((error as AppErrorType).code) {
|
||||
throw error;
|
||||
}
|
||||
throw {
|
||||
code: ERROR_CODES.AUTH.LOGOUT_ERROR,
|
||||
name: "Logout error",
|
||||
message: "The logout failed",
|
||||
} as AppErrorType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const authService = AuthService.getInstance();
|
||||
@@ -2,14 +2,14 @@ import connectDB from "@/lib/mongodb";
|
||||
import { KomgaConfig as KomgaConfigModel } from "@/lib/models/config.model";
|
||||
import { TTLConfig as TTLConfigModel } from "@/lib/models/ttl-config.model";
|
||||
import { DebugService } from "./debug.service";
|
||||
import { AuthServerService } from "./auth-server.service";
|
||||
import { getCurrentUser } from "../auth-utils";
|
||||
import { ERROR_CODES } from "../../constants/errorCodes";
|
||||
import { AppError } from "../../utils/errors";
|
||||
import type { User, KomgaConfigData, TTLConfigData, KomgaConfig, TTLConfig } from "@/types/komga";
|
||||
|
||||
export class ConfigDBService {
|
||||
private static async getCurrentUser(): Promise<User> {
|
||||
const user: User | null = await AuthServerService.getCurrentUser();
|
||||
const user: User | null = await getCurrentUser();
|
||||
if (!user) {
|
||||
throw new AppError(ERROR_CODES.AUTH.UNAUTHENTICATED);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import fs from "fs/promises";
|
||||
import path from "path";
|
||||
import type { CacheType } from "./base-api.service";
|
||||
import { AuthServerService } from "./auth-server.service";
|
||||
import { PreferencesService } from "./preferences.service";
|
||||
import { getCurrentUser } from "../auth-utils";
|
||||
import { ERROR_CODES } from "../../constants/errorCodes";
|
||||
import { AppError } from "../../utils/errors";
|
||||
|
||||
@@ -28,7 +28,7 @@ export class DebugService {
|
||||
private static writeQueues = new Map<string, Promise<void>>();
|
||||
|
||||
private static async getCurrentUserId(): Promise<string> {
|
||||
const user = await AuthServerService.getCurrentUser();
|
||||
const user = await getCurrentUser();
|
||||
if (!user) {
|
||||
throw new AppError(ERROR_CODES.AUTH.UNAUTHENTICATED);
|
||||
}
|
||||
@@ -49,7 +49,7 @@ export class DebugService {
|
||||
}
|
||||
|
||||
private static async isDebugEnabled(): Promise<boolean> {
|
||||
const user = await AuthServerService.getCurrentUser();
|
||||
const user = await getCurrentUser();
|
||||
if (!user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import connectDB from "@/lib/mongodb";
|
||||
import { FavoriteModel } from "@/lib/models/favorite.model";
|
||||
import { DebugService } from "./debug.service";
|
||||
import { AuthServerService } from "./auth-server.service";
|
||||
import { getCurrentUser } from "../auth-utils";
|
||||
import { ERROR_CODES } from "../../constants/errorCodes";
|
||||
import { AppError } from "../../utils/errors";
|
||||
import type { User } from "@/types/komga";
|
||||
@@ -17,7 +17,7 @@ export class FavoriteService {
|
||||
}
|
||||
|
||||
private static async getCurrentUser(): Promise<User> {
|
||||
const user = await AuthServerService.getCurrentUser();
|
||||
const user = await getCurrentUser();
|
||||
if (!user) {
|
||||
throw new AppError(ERROR_CODES.AUTH.UNAUTHENTICATED);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { PreferencesModel } from "@/lib/models/preferences.model";
|
||||
import { AuthServerService } from "./auth-server.service";
|
||||
import { getCurrentUser } from "../auth-utils";
|
||||
import { ERROR_CODES } from "../../constants/errorCodes";
|
||||
import { AppError } from "../../utils/errors";
|
||||
import type { UserPreferences } from "@/types/preferences";
|
||||
@@ -9,7 +9,7 @@ import connectDB from "@/lib/mongodb";
|
||||
|
||||
export class PreferencesService {
|
||||
static async getCurrentUser(): Promise<User> {
|
||||
const user = await AuthServerService.getCurrentUser();
|
||||
const user = await getCurrentUser();
|
||||
if (!user) {
|
||||
throw new AppError(ERROR_CODES.AUTH.UNAUTHENTICATED);
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ class RequestMonitor {
|
||||
} else if (count >= this.thresholds.high) {
|
||||
console.warn(`[REQUEST-MONITOR] ⚠️ HIGH concurrency: ${count} active requests`);
|
||||
} else if (count >= this.thresholds.warning) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`[REQUEST-MONITOR] ⚡ Warning concurrency: ${count} active requests`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import fs from "fs";
|
||||
import path from "path";
|
||||
import { PreferencesService } from "./preferences.service";
|
||||
import { DebugService } from "./debug.service";
|
||||
import { AuthServerService } from "./auth-server.service";
|
||||
import { getCurrentUser } from "../auth-utils";
|
||||
|
||||
export type CacheMode = "file" | "memory";
|
||||
|
||||
@@ -45,7 +45,7 @@ class ServerCacheService {
|
||||
|
||||
private async initializeCacheMode(): Promise<void> {
|
||||
try {
|
||||
const user = await AuthServerService.getCurrentUser();
|
||||
const user = await getCurrentUser();
|
||||
if (!user) {
|
||||
this.setCacheMode("memory");
|
||||
return;
|
||||
@@ -293,7 +293,7 @@ class ServerCacheService {
|
||||
* Supprime une entrée du cache
|
||||
*/
|
||||
async delete(key: string): Promise<void> {
|
||||
const user = await AuthServerService.getCurrentUser();
|
||||
const user = await getCurrentUser();
|
||||
if (!user) {
|
||||
throw new Error("Utilisateur non authentifié");
|
||||
}
|
||||
@@ -313,7 +313,7 @@ class ServerCacheService {
|
||||
* Supprime toutes les entrées du cache qui commencent par un préfixe
|
||||
*/
|
||||
async deleteAll(prefix: string): Promise<void> {
|
||||
const user = await AuthServerService.getCurrentUser();
|
||||
const user = await getCurrentUser();
|
||||
if (!user) {
|
||||
throw new Error("Utilisateur non authentifié");
|
||||
}
|
||||
@@ -390,7 +390,7 @@ class ServerCacheService {
|
||||
type: keyof typeof ServerCacheService.DEFAULT_TTL = "DEFAULT"
|
||||
): Promise<T> {
|
||||
const startTime = performance.now();
|
||||
const user = await AuthServerService.getCurrentUser();
|
||||
const user = await getCurrentUser();
|
||||
if (!user) {
|
||||
throw new Error("Utilisateur non authentifié");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user