feat: secu migrate to user uuid

This commit is contained in:
Julien Froidefond
2025-08-21 13:54:13 +02:00
parent ef16c73625
commit 578f0858e8
12 changed files with 532 additions and 70 deletions

View File

@@ -12,14 +12,14 @@ const COOKIE_MAX_AGE = 30 * 24 * 60 * 60; // 30 jours
export async function GET() {
try {
const cookieStore = await cookies();
const userId = cookieStore.get(COOKIE_NAME)?.value;
const userUuid = cookieStore.get(COOKIE_NAME)?.value;
if (!userId) {
if (!userUuid) {
return NextResponse.json({ user: null }, { status: 200 });
}
const evaluationService = new EvaluationService();
const userProfile = await evaluationService.getUserById(parseInt(userId));
const userProfile = await evaluationService.getUserByUuid(userUuid);
if (!userProfile) {
// Cookie invalide, le supprimer
@@ -44,7 +44,7 @@ export async function GET() {
export async function POST(request: NextRequest) {
try {
const profile: UserProfile = await request.json();
if (!profile.firstName || !profile.lastName || !profile.teamId) {
return NextResponse.json(
{ error: "Missing required fields" },
@@ -53,16 +53,19 @@ export async function POST(request: NextRequest) {
}
const evaluationService = new EvaluationService();
const userId = await evaluationService.upsertUser(profile);
const userUuid = await evaluationService.upsertUserUuid(profile);
// Créer la réponse avec le cookie
const response = NextResponse.json({
user: { ...profile, id: userId },
userId
}, { status: 200 });
const response = NextResponse.json(
{
user: { ...profile, uuid: userUuid },
userUuid,
},
{ status: 200 }
);
// Définir le cookie avec l'ID utilisateur
response.cookies.set(COOKIE_NAME, userId.toString(), {
// Définir le cookie avec l'UUID utilisateur (plus sécurisé)
response.cookies.set(COOKIE_NAME, userUuid, {
maxAge: COOKIE_MAX_AGE,
httpOnly: true,
secure: process.env.NODE_ENV === "production",
@@ -90,9 +93,6 @@ export async function DELETE() {
return response;
} catch (error) {
console.error("Error logging out user:", error);
return NextResponse.json(
{ error: "Failed to logout" },
{ status: 500 }
);
return NextResponse.json({ error: "Failed to logout" }, { status: 500 });
}
}

View File

@@ -7,11 +7,10 @@ import { COOKIE_NAME } from "@/lib/auth-utils";
export async function GET(request: NextRequest) {
try {
const cookieStore = await cookies();
const userId = cookieStore.get(COOKIE_NAME)?.value;
const userIdNum = userId ? parseInt(userId) : null;
const userUuid = cookieStore.get(COOKIE_NAME)?.value;
// Support pour l'ancien mode avec paramètres (pour la compatibilité)
if (!userIdNum) {
if (!userUuid) {
const { searchParams } = new URL(request.url);
const firstName = searchParams.get("firstName");
const lastName = searchParams.get("lastName");
@@ -29,8 +28,8 @@ export async function GET(request: NextRequest) {
return NextResponse.json({ evaluation });
}
// Mode authentifié par cookie
const userProfile = await evaluationService.getUserById(userIdNum);
// Mode authentifié par cookie UUID
const userProfile = await evaluationService.getUserByUuid(userUuid);
if (!userProfile) {
return NextResponse.json(
{ error: "Utilisateur non trouvé" },

View File

@@ -7,18 +7,18 @@ const COOKIE_NAME = "peakSkills_userId";
export async function PUT(request: NextRequest) {
try {
// Récupérer l'utilisateur depuis le cookie
// Récupérer l'utilisateur depuis le cookie (maintenant un UUID)
const cookieStore = await cookies();
const userId = cookieStore.get(COOKIE_NAME)?.value;
const userUuid = cookieStore.get(COOKIE_NAME)?.value;
if (!userId) {
if (!userUuid) {
return NextResponse.json(
{ error: "Utilisateur non authentifié" },
{ status: 401 }
);
}
const userProfile = await evaluationService.getUserById(parseInt(userId));
const userProfile = await evaluationService.getUserByUuid(userUuid);
if (!userProfile) {
return NextResponse.json(
{ error: "Utilisateur introuvable" },
@@ -44,7 +44,7 @@ export async function PUT(request: NextRequest) {
{ status: 400 }
);
}
await evaluationService.updateSkillLevel(
await evaluationService.updateSkillLevelUuid(
userProfile,
category,
skillId,
@@ -59,7 +59,7 @@ export async function PUT(request: NextRequest) {
{ status: 400 }
);
}
await evaluationService.updateSkillMentorStatus(
await evaluationService.updateSkillMentorStatusUuid(
userProfile,
category,
skillId,
@@ -74,7 +74,7 @@ export async function PUT(request: NextRequest) {
{ status: 400 }
);
}
await evaluationService.updateSkillLearningStatus(
await evaluationService.updateSkillLearningStatusUuid(
userProfile,
category,
skillId,
@@ -83,7 +83,7 @@ export async function PUT(request: NextRequest) {
break;
case "addSkill":
await evaluationService.addSkillToEvaluation(
await evaluationService.addSkillToEvaluationUuid(
userProfile,
category,
skillId
@@ -91,7 +91,7 @@ export async function PUT(request: NextRequest) {
break;
case "removeSkill":
await evaluationService.removeSkillFromEvaluation(
await evaluationService.removeSkillFromEvaluationUuid(
userProfile,
category,
skillId

View File

@@ -5,10 +5,7 @@ import {
getServerSkillCategories,
getServerTeams,
} from "@/lib/server-auth";
import {
EvaluationClientWrapper,
WelcomeEvaluationScreen,
} from "@/components/evaluation";
import { EvaluationClientWrapper } from "@/components/evaluation";
import { SkillEvaluation } from "@/components/skill-evaluation";
export default async function EvaluationPage() {
@@ -27,22 +24,14 @@ export default async function EvaluationPage() {
getServerTeams(),
]);
// Si pas d'évaluation, afficher l'écran d'accueil évaluation
if (!userEvaluation) {
return <WelcomeEvaluationScreen teams={teams} />;
}
return (
<EvaluationClientWrapper userEvaluation={userEvaluation} teams={teams}>
<div>
{/* Skill Evaluation */}
{skillCategories.length > 0 &&
userEvaluation.evaluations.length > 0 && (
<SkillEvaluation
categories={skillCategories}
evaluations={userEvaluation.evaluations}
/>
)}
<SkillEvaluation
categories={skillCategories}
evaluations={userEvaluation?.evaluations || []}
/>
</div>
</EvaluationClientWrapper>
);