2026-05-25 16:10:18 +08:00

88 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { NextRequest, NextResponse } from 'next/server';
import { generateFingerprint } from '@/lib/license/fingerprint-service';
import { updateLocalLicense, getLocalLicense, clearLocalLicense } from '@/lib/license/license-service';
import { verifyLicenseSignature } from '@/lib/license/crypto-service';
import { buildLicenseServerLicenseApiUrl } from '@/lib/license/server-config';
import type { VerifyResponse } from '@/lib/license/types';
// 宽限期(7天)
const GRACE_PERIOD_DAYS = 7;
const GRACE_PERIOD_MS = GRACE_PERIOD_DAYS * 24 * 60 * 60 * 1000;
function isWithinGracePeriod(lastVerified: Date | string | null): boolean {
if (!lastVerified) return false;
const lastVerifiedDate = typeof lastVerified === 'string' ? new Date(lastVerified) : lastVerified;
const now = new Date();
return (now.getTime() - lastVerifiedDate.getTime()) < GRACE_PERIOD_MS;
}
export async function POST(request: NextRequest) {
try {
// 先检查本地缓存
const localLicense = await getLocalLicense();
if (!localLicense) {
return NextResponse.json({ valid: false, error: '未找到许可证' });
}
// ✅ 安全改进:在后端生成硬件指纹(不暴露给客户端)
const fingerprint = await generateFingerprint();
// ✅ 安全改进:代理请求到许可证服务器(隐藏服务器地址)
const response = await fetch(buildLicenseServerLicenseApiUrl('verify'), {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
instanceId: fingerprint.instanceId,
fingerprint,
timestamp: Date.now(),
}),
});
const data: VerifyResponse = await response.json();
if (!data.valid || !data.license) {
// 检查是否是被吊销(禁用/删除/过期)
const isRevoked = response.status === 403 || response.status === 404;
if (isRevoked) {
// 许可证被吊销,清除本地缓存
console.log('[License] 许可证已被吊销:', data.error);
await clearLocalLicense();
return NextResponse.json({
valid: false,
error: data.error || '许可证已被吊销',
revoked: true
});
}
// 其他错误(如网络问题),检查宽限期
if (isWithinGracePeriod(localLicense.lastVerified)) {
return NextResponse.json({ valid: true });
}
return NextResponse.json({ valid: false, error: data.error || '验证失败' });
}
// ✅ 在后端验证签名
if (!verifyLicenseSignature(data.license.data, data.license.signature)) {
return NextResponse.json({ valid: false, error: '许可证签名验证失败' });
}
// ✅ 在后端更新本地缓存
await updateLocalLicense(data.license);
return NextResponse.json({ valid: true });
} catch (error) {
console.error('验证失败:', error);
// 网络错误时检查宽限期
const localLicense = await getLocalLicense();
if (localLicense && isWithinGracePeriod(localLicense.lastVerified)) {
return NextResponse.json({ valid: true });
}
return NextResponse.json({ valid: false, error: '网络错误' });
}
}