refacto : review auth part 1

This commit is contained in:
Julien Froidefond
2025-02-13 09:42:28 +01:00
parent 98066274fa
commit addc42d1f6
5 changed files with 25 additions and 171 deletions

View File

@@ -136,7 +136,7 @@ export default function SettingsPage() {
password,
};
storageService.setCredentials(
storageService.setKomgaConfig(
{
serverUrl: newConfig.serverUrl,
credentials: { username: newConfig.username, password: newConfig.password },

View File

@@ -1,6 +1,5 @@
import { AuthError } from "@/types/auth";
import { storageService } from "./storage.service";
import { KomgaUser } from "@/types/komga";
interface AuthUser {
id: string;

View File

@@ -1,153 +0,0 @@
import { KomgaUser, KomgaLibrary, KomgaSeries, KomgaBook, ReadProgress } from "@/types/komga";
import { AuthConfig } from "@/types/auth";
import { storageService } from "./storage.service";
class KomgaService {
private static instance: KomgaService;
private constructor() {}
public static getInstance(): KomgaService {
if (!KomgaService.instance) {
KomgaService.instance = new KomgaService();
}
return KomgaService.instance;
}
/**
* Crée les headers d'authentification
*/
private getAuthHeaders(config?: AuthConfig): Headers {
const headers = new Headers();
const credentials = config || storageService.getCredentials();
if (credentials?.credentials) {
const { username, password } = credentials.credentials;
headers.set("Authorization", `Basic ${btoa(`${username}:${password}`)}`);
}
return headers;
}
/**
* Vérifie les credentials en récupérant l'utilisateur courant
*/
async checkCredentials(config: AuthConfig): Promise<KomgaUser> {
const response = await fetch(`${config.serverUrl}/api/v1/libraries`, {
headers: this.getAuthHeaders(config),
});
if (!response.ok) {
throw new Error("Invalid credentials");
}
return response.json();
}
/**
* Récupère les bibliothèques
*/
async getLibraries(): Promise<KomgaLibrary[]> {
const credentials = storageService.getCredentials();
if (!credentials) throw new Error("Not authenticated");
const response = await fetch(`${credentials.serverUrl}/api/v1/libraries`, {
headers: this.getAuthHeaders(),
});
if (!response.ok) {
throw new Error("Failed to fetch libraries");
}
return response.json();
}
/**
* Récupère l'URL de la couverture d'une bibliothèque
*/
getLibraryThumbnailUrl(libraryId: string): string {
const credentials = storageService.getCredentials();
if (!credentials) throw new Error("Not authenticated");
return `${credentials.serverUrl}/api/v1/libraries/${libraryId}/thumbnail`;
}
/**
* Récupère les séries d'une bibliothèque
*/
async getLibrarySeries(libraryId: string): Promise<KomgaSeries[]> {
const credentials = storageService.getCredentials();
if (!credentials) throw new Error("Not authenticated");
const response = await fetch(`${credentials.serverUrl}/api/v1/libraries/${libraryId}/series`, {
headers: this.getAuthHeaders(),
});
if (!response.ok) {
throw new Error("Failed to fetch series");
}
return response.json();
}
/**
* Récupère les livres d'une série
*/
async getSeriesBooks(seriesId: string): Promise<KomgaBook[]> {
const credentials = storageService.getCredentials();
if (!credentials) throw new Error("Not authenticated");
const response = await fetch(`${credentials.serverUrl}/api/v1/series/${seriesId}/books`, {
headers: this.getAuthHeaders(),
});
if (!response.ok) {
throw new Error("Failed to fetch books");
}
return response.json();
}
/**
* Récupère l'URL de la couverture d'un livre
*/
getBookThumbnailUrl(bookId: string): string {
const credentials = storageService.getCredentials();
if (!credentials) throw new Error("Not authenticated");
return `${credentials.serverUrl}/api/v1/books/${bookId}/thumbnail`;
}
/**
* Récupère l'URL de lecture d'un livre
*/
getBookReadingUrl(bookId: string): string {
const credentials = storageService.getCredentials();
if (!credentials) throw new Error("Not authenticated");
return `${credentials.serverUrl}/api/v1/books/${bookId}/pages/1`;
}
/**
* Récupère la progression de lecture d'une série
*/
async getSeriesReadProgress(seriesId: string): Promise<ReadProgress> {
const credentials = storageService.getCredentials();
if (!credentials) throw new Error("Not authenticated");
const response = await fetch(
`${credentials.serverUrl}/api/v1/series/${seriesId}/read-progress`,
{
headers: this.getAuthHeaders(),
}
);
if (!response.ok) {
throw new Error("Failed to fetch series read progress");
}
return response.json();
}
}
export const komgaService = KomgaService.getInstance();

View File

@@ -1,7 +1,7 @@
import { AuthConfig } from "@/types/auth";
const CREDENTIALS_KEY = "komgaCredentials";
const USER_KEY = "komgaUser";
const KOMGACREDENTIALS_KEY = "komgaCredentials";
const USER_KEY = "stripUser";
const TTL_CONFIG_KEY = "ttlConfig";
interface TTLConfig {
@@ -28,7 +28,7 @@ class StorageService {
/**
* Stocke les credentials de manière sécurisée
*/
setCredentials(config: AuthConfig, remember: boolean = false): void {
setKomgaConfig(config: AuthConfig, remember: boolean = false): void {
const storage = remember ? localStorage : sessionStorage;
// Encodage basique des credentials en base64
@@ -41,10 +41,10 @@ class StorageService {
},
});
storage.setItem(CREDENTIALS_KEY, encoded);
storage.setItem(KOMGACREDENTIALS_KEY, encoded);
// Définir aussi un cookie pour le middleware
const cookieValue = `${CREDENTIALS_KEY}=${encoded}; path=/; samesite=strict`;
const cookieValue = `${KOMGACREDENTIALS_KEY}=${encoded}; path=/; samesite=strict`;
const maxAge = remember ? `; max-age=${30 * 24 * 60 * 60}` : "";
document.cookie = cookieValue + maxAge;
@@ -58,10 +58,10 @@ class StorageService {
if (typeof window === "undefined") return null;
const storage =
localStorage.getItem(CREDENTIALS_KEY) || sessionStorage.getItem(CREDENTIALS_KEY);
localStorage.getItem(KOMGACREDENTIALS_KEY) || sessionStorage.getItem(KOMGACREDENTIALS_KEY);
console.log("StorageService - Lecture des credentials:", {
fromLocalStorage: !!localStorage.getItem(CREDENTIALS_KEY),
fromSessionStorage: !!sessionStorage.getItem(CREDENTIALS_KEY),
fromLocalStorage: !!localStorage.getItem(KOMGACREDENTIALS_KEY),
fromSessionStorage: !!sessionStorage.getItem(KOMGACREDENTIALS_KEY),
value: storage,
});
@@ -135,17 +135,17 @@ class StorageService {
* Efface toutes les données stockées
*/
clear(): void {
localStorage.removeItem(CREDENTIALS_KEY);
localStorage.removeItem(KOMGACREDENTIALS_KEY);
localStorage.removeItem(USER_KEY);
sessionStorage.removeItem(CREDENTIALS_KEY);
sessionStorage.removeItem(KOMGACREDENTIALS_KEY);
sessionStorage.removeItem(USER_KEY);
document.cookie = `${CREDENTIALS_KEY}=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT`;
document.cookie = `${KOMGACREDENTIALS_KEY}=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT`;
document.cookie = `${USER_KEY}=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT`;
}
getUser() {
try {
const userStr = localStorage.getItem("komgaUser");
const userStr = localStorage.getItem(USER_KEY);
if (!userStr) return null;
return JSON.parse(atob(userStr));
} catch (error) {
@@ -155,9 +155,17 @@ class StorageService {
}
clearAll() {
localStorage.removeItem("komgaUser");
localStorage.removeItem("komgaCredentials");
localStorage.removeItem("ttlConfig");
localStorage.removeItem(USER_KEY);
localStorage.removeItem(KOMGACREDENTIALS_KEY);
localStorage.removeItem(TTL_CONFIG_KEY);
}
getKeys() {
return {
credentials: KOMGACREDENTIALS_KEY,
user: USER_KEY,
ttlConfig: TTL_CONFIG_KEY,
};
}
}

View File

@@ -38,7 +38,7 @@ export function middleware(request: NextRequest) {
}
// Pour les routes protégées, vérifier la présence de l'utilisateur
const user = request.cookies.get("komgaUser");
const user = request.cookies.get("stripUser");
if (!user) {
const loginUrl = new URL("/login", request.url);
loginUrl.searchParams.set("from", pathname);