Spaces:
Running
Running
File size: 1,509 Bytes
c7d34c1 b1cfe1b c7d34c1 32151b6 c7d34c1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | import { AgentApiError } from './api-error-response';
import { verifyPasswordHash } from './server-runtime';
import crypto from 'crypto';
export function assertAgentAuthorized(headers: Headers, env: Record<string, string | undefined> = process.env): void {
const configuredToken = env.AGENT_API_TOKEN?.trim();
if (configuredToken) {
const authorization = headers.get('authorization') || '';
const expected = `Bearer ${configuredToken}`;
if (!timingSafeStringEqual(authorization, expected)) {
throw new AgentApiError({
code: 'unauthorized',
message: '未授权:Bearer token 无效或缺失。',
status: 401,
retryable: false
});
}
return;
}
const appPassword = env.APP_PASSWORD?.trim();
if (!appPassword) return;
const passwordHash = headers.get('x-app-password-hash');
if (!passwordHash || !verifyPasswordHash(passwordHash, appPassword)) {
throw new AgentApiError({
code: 'unauthorized',
message: '未授权:访问码哈希无效或缺失。',
status: 401,
retryable: false
});
}
}
function timingSafeStringEqual(actual: string, expected: string): boolean {
const actualHash = crypto.createHash('sha256').update(actual).digest();
const expectedHash = crypto.createHash('sha256').update(expected).digest();
return crypto.timingSafeEqual(actualHash, expectedHash);
}
|