import 'server-only'; import { createHash, timingSafeEqual } from 'node:crypto'; import { getMockAdminCredentials } from '@/lib/env'; import type { AdminUser } from '@/lib/domain/admin-user'; /** * mock 인증 Repository. * * 백엔드(edupay-backend)에 관리자 인증 API가 아직 없어 mock으로 구현한다. * 공개 시그니처(도메인 타입만 주고받음)는 백엔드 연동 후에도 유지한다 — 연동 시점에는 * 이 파일의 내부 구현만 실제 API 호출로 교체하고, 각 함수에 캐시 전략(`cache: 'no-store'`)을 * 명시적으로 추가해야 한다. 인증·개인 데이터는 요청 간 캐시 잔존이 금지되기 때문이다. */ const MOCK_ADMIN_ID = 'mock-admin-1'; export type AdminCredentials = { loginId: string; password: string; }; /** SHA-256 다이제스트 후 timingSafeEqual 비교 — 길이·타이밍 정보 누출을 방지한다. */ function digestsMatch(a: string, b: string): boolean { const digestA = createHash('sha256').update(a, 'utf8').digest(); const digestB = createHash('sha256').update(b, 'utf8').digest(); return timingSafeEqual(digestA, digestB); } export async function verifyAdminCredentials( credentials: AdminCredentials ): Promise { const seed = getMockAdminCredentials(); if (!seed) { return null; } const loginIdMatches = digestsMatch(credentials.loginId, seed.loginId); const passwordMatches = digestsMatch(credentials.password, seed.password); if (!loginIdMatches || !passwordMatches) { return null; } return { id: MOCK_ADMIN_ID, name: '관리자' }; } export async function fetchAdminById( adminId: string ): Promise { const seed = getMockAdminCredentials(); if (!seed || adminId !== MOCK_ADMIN_ID) { return null; } return { id: MOCK_ADMIN_ID, name: '관리자' }; }