security: enforce auth on all API write endpoints, remove mario-kart
- Remove all mario-kart routes and model (zero auth, unused) - Add requireGroup() helper to auth middleware - Recipe write APIs (add/edit/delete/img/*): require rezepte_users group - Translate endpoint: require rezepte_users (was fully unauthenticated) - Nutrition overwrites: require auth (was no-op) - Nutrition generate-all: require rezepte_users (was no-op) - Alt-text/color endpoints: require rezepte_users group - Image delete/mv: add path traversal protection - Period shared endpoint: normalize username for consistent lookup
This commit is contained in:
@@ -45,6 +45,32 @@ export async function requireAuth(
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Require authentication AND membership in a specific group.
|
||||
* Throws 401 if not authenticated, 403 if not in the group.
|
||||
*/
|
||||
export async function requireGroup(
|
||||
locals: RequestEvent['locals'],
|
||||
group: string
|
||||
): Promise<AuthenticatedUser> {
|
||||
const session = await locals.auth();
|
||||
|
||||
if (!session || !session.user?.nickname) {
|
||||
throw json({ error: 'Unauthorized' }, { status: 401 });
|
||||
}
|
||||
|
||||
if (!session.user.groups?.includes(group)) {
|
||||
throw json({ error: 'Forbidden' }, { status: 403 });
|
||||
}
|
||||
|
||||
return {
|
||||
nickname: session.user.nickname,
|
||||
name: session.user.name ?? undefined,
|
||||
email: session.user.email ?? undefined,
|
||||
image: session.user.image ?? undefined
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Optional authentication - returns user if authenticated, null otherwise.
|
||||
* Useful for routes that have different behavior for authenticated users.
|
||||
|
||||
Reference in New Issue
Block a user