chahinebrini 2c33ba55a4 fix(backend): username (Login-Identifikator) aus öffentlichen Payloads entfernt
community/posts.get.ts + social/profile/[userId].get.ts lieferten neben
nickname auch username an fremde Clients — username ist der Login-
Identifikator ({username}@rebreak.internal) und verletzt die Nickname-
Anonymitäts-Invariante (REQ-COMM-005 / R-DATA-07) + exponiert das halbe
Login-Credential-Paar. Frontend rendert das Feld nirgends (verifiziert);
totes Typ-Feld in stores/community.ts entfernt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 06:36:16 +02:00

82 lines
2.6 KiB
TypeScript

import { getProfile } from "../../../db/profile";
import { getUserScore } from "../../../db/scores";
import { getFollowRelation } from "../../../db/social";
import { getUsersMeta } from "../../../utils/getUsersMeta";
import { usePrisma } from "../../../utils/prisma";
/** GET /api/social/profile/[userId] */
export default defineEventHandler(async (event) => {
const targetUserId = getRouterParam(event, "userId");
if (!targetUserId)
throw createError({ statusCode: 400, message: "userId fehlt" });
// Auth-User optional
let currentUserId: string | null = null;
try {
const u = await requireUser(event);
currentUserId = u.id;
} catch {}
const [profile, score, followRelation, recentPosts, metaMap, postsCount, followingCount, approvedDomainsCount] =
await Promise.all([
getProfile(targetUserId),
getUserScore(targetUserId),
currentUserId && currentUserId !== targetUserId
? getFollowRelation(currentUserId, targetUserId)
: Promise.resolve(null),
usePrisma().communityPost.findMany({
where: { userId: targetUserId, isModerated: false },
orderBy: { createdAt: "desc" },
take: 5,
select: {
id: true,
category: true,
content: true,
likesCount: true,
commentsCount: true,
createdAt: true,
},
}),
getUsersMeta([targetUserId]),
usePrisma().communityPost.count({
where: { userId: targetUserId, isModerated: false },
}),
usePrisma().userFollow.count({
where: { followerId: targetUserId },
}),
usePrisma().domainSubmission.count({
where: { userId: targetUserId, status: "approved" },
}),
]);
if (!profile)
throw createError({ statusCode: 404, message: "Profil nicht gefunden" });
const meta = metaMap[targetUserId] ?? { nickname: null, avatar: null };
return {
id: profile.id,
// username (Login-Identifikator) bewusst NICHT exponiert — nickname-only.
nickname: meta.nickname ?? profile.username,
avatar: meta.avatar,
bio: (profile as any).bio ?? null,
followersCount: profile.followersCount ?? 0,
followingCount,
postsCount,
approvedDomainsCount,
tier: score?.tier ?? "beginner",
totalPoints: score?.totalPoints ?? 0,
isFollowing: !!followRelation,
isSelf: currentUserId === targetUserId,
joinedAt: profile.createdAt,
recentPosts: recentPosts.map((p) => ({
id: p.id,
category: p.category,
content: p.content.slice(0, 120),
likesCount: p.likesCount ?? 0,
commentsCount: p.commentsCount ?? 0,
createdAt: p.createdAt,
})),
};
});