import { NextResponse } from 'next/server'; import { allowChannelIdJoin, isChzzkOAuthConfigured, requireChzzkLoginForChannelRooms, } from '@/lib/auth/mode'; import { readAuthSession, type AuthSession } from '@/lib/auth/session'; import type { RoomRecord } from '@/lib/rooms/store'; export async function getRequestAuthSession( request?: Request, ): Promise { // Route Handler에서는 cookies()가 기본. request Cookie 헤더도 보조 파싱. const fromCookies = await readAuthSession(); if (fromCookies) return fromCookies; if (!request) return null; const header = request.headers.get('cookie') || ''; const match = /(?:^|;\s*)drinkmarble_auth=([^;]+)/.exec(header); if (!match?.[1]) return null; const { parseAuthSession } = await import('@/lib/auth/session'); return parseAuthSession(decodeURIComponent(match[1])); } /** * 치지직 연동 룸 접근 검사. * - 개발(채널 ID 허용): 세션 없어도 OK * - 릴리즈: 세션의 channelId가 룸 채널과 일치해야 함 */ export async function assertChannelRoomAccess( room: RoomRecord, request?: Request, ): Promise<{ ok: true; session: AuthSession | null } | { ok: false; response: NextResponse }> { if (!room.settings.chzzkEnabled) { return { ok: true, session: null }; } if (!requireChzzkLoginForChannelRooms()) { return { ok: true, session: await getRequestAuthSession(request) }; } const session = await getRequestAuthSession(request); const roomChannel = room.settings.channelId?.toLowerCase() || ''; if (!session || !roomChannel || session.channelId !== roomChannel) { return { ok: false, response: NextResponse.json( { error: '릴리즈 환경에서는 치지직 로그인으로 본인 채널만 입장할 수 있습니다. 홈에서 다시 로그인해 주세요.', code: 'CHZZK_AUTH_REQUIRED', allowChannelIdJoin: allowChannelIdJoin(), oauthConfigured: isChzzkOAuthConfigured(), }, { status: 401 }, ), }; } return { ok: true, session }; } export function authModePublic() { return { allowChannelIdJoin: allowChannelIdJoin(), requireChzzkLogin: requireChzzkLoginForChannelRooms(), oauthConfigured: isChzzkOAuthConfigured(), nodeEnv: process.env.NODE_ENV, }; }