치지직 앱으로 연동하고, 연동 확인된 ID만 접속할 수 있도록 수정, 개발용으로는 채널ID를 수동으로 접속할 수 있도록 변경.

최초 추천 고정 배치 추가.
This commit is contained in:
kimyu
2026-09-18 04:09:31 +09:00
parent 6f72824598
commit 73520f9f06
26 changed files with 1272 additions and 162 deletions

68
lib/auth/room-access.ts Normal file
View File

@@ -0,0 +1,68 @@
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<AuthSession | null> {
// 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,
};
}