File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
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<AdminUser | null> {
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<AdminUser | null> {
const seed = getMockAdminCredentials();
if (!seed || adminId !== MOCK_ADMIN_ID) {
return null;
}
return { id: MOCK_ADMIN_ID, name: '관리자' };
}