Enhance dashboard guild access with owner bypass functionality

- Introduced `resolveDashboardGuild` to handle guild resolution for both managed and owner-panel bypass scenarios.
- Updated `GuildLayout` and `WelcomePage` components to utilize the new guild resolution logic, improving access handling.
- Enhanced `DashboardShell` to display an informational banner for users accessing guilds via the owner-panel bypass.
- Added localization support for owner bypass messages in English and German.
- Updated authentication logic to allow owner-panel users to access guilds without Discord Manage Guild permission.
This commit is contained in:
smueller
2026-07-24 11:59:16 +02:00
parent e45642b6f9
commit 20593b7173
10 changed files with 133 additions and 22 deletions

View File

@@ -3,6 +3,7 @@ import { NextResponse } from 'next/server';
import { ZodError } from 'zod';
import { hasManageGuildPermission } from '@nexumi/shared';
import { fetchDiscordUserGuildsCached } from './discord-oauth';
import { hasOwnerGuildBypass } from './owner-auth';
import { prisma } from './prisma';
import { getSession, type SessionPayload } from './session';
@@ -46,19 +47,25 @@ export async function requireAuthOrRedirect(): Promise<SessionPayload> {
/**
* Ensures the current session user has Manage Guild permission on the given
* guild (via Discord OAuth guild list) and that the bot is actually installed
* there (tracked via the `Guild` table). Use in API routes.
* there (tracked via the `Guild` table). Owner-panel users bypass Discord
* membership checks. Use in API routes.
*/
export async function requireGuildAccess(guildId: string): Promise<SessionPayload> {
const session = await requireAuth();
const dbGuild = await prisma.guild.findUnique({ where: { id: guildId } });
if (!dbGuild) {
throw new ForbiddenError('Nexumi is not installed on this server');
}
if (await hasOwnerGuildBypass(session.user.id)) {
return session;
}
const guilds = await fetchDiscordUserGuildsCached(session.accessToken);
const guild = guilds.find((entry) => entry.id === guildId);
if (!guild || !hasManageGuildPermission(guild.permissions)) {
throw new ForbiddenError('Missing Manage Guild permission for this server');
}
const dbGuild = await prisma.guild.findUnique({ where: { id: guildId } });
if (!dbGuild) {
throw new ForbiddenError('Nexumi is not installed on this server');
}
return session;
}
@@ -68,15 +75,20 @@ export async function requireGuildAccess(guildId: string): Promise<SessionPayloa
*/
export async function requireGuildAccessOrRedirect(guildId: string): Promise<SessionPayload> {
const session = await requireAuthOrRedirect();
const dbGuild = await prisma.guild.findUnique({ where: { id: guildId } });
if (!dbGuild) {
redirect('/dashboard');
}
if (await hasOwnerGuildBypass(session.user.id)) {
return session;
}
const guilds = await fetchDiscordUserGuildsCached(session.accessToken);
const guild = guilds.find((entry) => entry.id === guildId);
if (!guild || !hasManageGuildPermission(guild.permissions)) {
redirect('/dashboard');
}
const dbGuild = await prisma.guild.findUnique({ where: { id: guildId } });
if (!dbGuild) {
redirect('/dashboard');
}
return session;
}