76 lines
2.6 KiB
TypeScript

import { createHash, timingSafeEqual } from 'crypto'
import { NextRequest, NextResponse } from 'next/server'
import {
NotificationCenterAdminError,
resolveNotificationCenterRecipientAlias,
} from '@/lib/notification-center-admin'
export const runtime = 'nodejs'
export const dynamic = 'force-dynamic'
function withNoStore(response: NextResponse) {
response.headers.set('Cache-Control', 'no-store, no-cache, must-revalidate')
response.headers.set('Pragma', 'no-cache')
response.headers.set('Expires', '0')
return response
}
function sha256(value: string) {
return createHash('sha256').update(value, 'utf8').digest()
}
function isAuthorizedBearer(providedSecret: string | null, configuredSecret: string | null) {
if (!providedSecret || !configuredSecret) return false
return timingSafeEqual(sha256(providedSecret), sha256(configuredSecret))
}
function readBearerSecret(request: NextRequest) {
const header = String(request.headers.get('authorization') || '')
if (!header.startsWith('Bearer ')) return null
const token = header.slice('Bearer '.length).trim()
return token || null
}
function errorResponse(status: number, code: string, message: string) {
return withNoStore(
NextResponse.json(
{
error: { code, message },
},
{ status },
),
)
}
export async function POST(request: NextRequest) {
const configuredSecret = String(process.env.YYD_NOTIFICATION_CENTER_ADMIN_API_SECRET || '').trim() || null
if (!configuredSecret) {
return errorResponse(503, 'NOTIFICATION_CENTER_ADMIN_SECRET_NOT_CONFIGURED', '服务端未配置通知中心鉴权密钥')
}
const providedSecret = readBearerSecret(request)
if (!isAuthorizedBearer(providedSecret, configuredSecret)) {
return errorResponse(401, 'UNAUTHORIZED', '未授权')
}
const body = await request.json().catch(() => ({}))
const recipientAlias = String((body as { recipientAlias?: unknown })?.recipientAlias || '').trim()
if (!recipientAlias) {
return errorResponse(422, 'RECIPIENT_ALIAS_REQUIRED', '花名不能为空')
}
try {
const resolved = await resolveNotificationCenterRecipientAlias(recipientAlias)
if (!resolved) {
return errorResponse(404, 'RECIPIENT_ALIAS_NOT_FOUND', '花名未找到对应钉钉 userId')
}
return withNoStore(NextResponse.json(resolved, { status: 200 }))
} catch (error) {
if (error instanceof NotificationCenterAdminError) {
return errorResponse(error.statusCode, error.code, error.message)
}
return errorResponse(500, 'NOTIFICATION_CENTER_RECIPIENT_RESOLVE_FAILED', '花名解析失败,请稍后重试')
}
}