All checks were successful
Deploy / deploy (push) Successful in 3m10s
Tool endpoints (events, notes, transport, weather) call other /api/* routes via loopback (http://localhost:3000). Those routes are middleware-protected — cookie-less loopbacks were getting 401, which surfaced to the voice agent as get_today_events → tool_http_502. Add internal header bypass: middleware lets the request through when x-voice-internal matches VOICE_API_KEY. Only our own tool endpoints use this header, from inside the same container, so the blast radius is limited to loopback traffic. - middleware.ts: check x-voice-internal before cookie - lib/voice-tools.ts: internalHeaders() helper - app/api/voice/tools/{weather,transport,events,notes}: use it
29 lines
1.0 KiB
TypeScript
29 lines
1.0 KiB
TypeScript
/**
|
||
* Helper для /api/voice/tools/* — общий bearer-check и forwarding к внутренним endpoint'ам.
|
||
* Позволяет голосовому скрипту вызывать tools через один и тот же токен (VOICE_API_KEY).
|
||
*/
|
||
|
||
export function isBearerAuthorized(req: Request): boolean {
|
||
const expected = process.env.VOICE_API_KEY
|
||
if (!expected) return false
|
||
const auth = req.headers.get('authorization') || ''
|
||
const token = auth.replace(/^Bearer\s+/i, '').trim()
|
||
return token === expected
|
||
}
|
||
|
||
export function unauthorized() {
|
||
return new Response(JSON.stringify({ error: 'unauthorized' }), {
|
||
status: 401,
|
||
headers: { 'Content-Type': 'application/json' },
|
||
})
|
||
}
|
||
|
||
/**
|
||
* Headers для loopback-вызовов к другим /api/* роутам из tool endpoints.
|
||
* Middleware пропускает запросы с этим header'ом (см. middleware.ts).
|
||
*/
|
||
export function internalHeaders(): HeadersInit {
|
||
const key = process.env.VOICE_API_KEY || ''
|
||
return { 'x-voice-internal': key }
|
||
}
|