b21fb0f159
Clona o satélite do mercado adaptado ao scoreodonto (ESM, sem PluginManager): - backend/newwhats/: config (ENV), auth (x-nw-key), routes /nw/* (clinica, especialidades, dentistas, procedimentos, planos — multi-tenant por clinica_id), sync-knowledge (base de conhecimento odonto → motor), webhook-receiver (HMAC, enxuto), proxy REST /api/nw/v1/* → motor /api/ext/v1/*, manifest, INTEGRACAO-MOTOR.md. - server.js: registerNewwhats(app, pool) antes do listen. - Removidos (não úteis): media-transcribe (motor já transcreve), smart-router, personas, follow-up-detector, context-builder. - Config por ENV: NEWWHATS_URL/INTEGRATION_KEY/WEBHOOK_SECRET/CLINICA_ID. - ativo::int=1 normaliza boolean vs smallint entre tabelas. - Validado: buildKnowledgeText gera 1195 chars de dados reais; registro ok no express 5.2.1. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
26 lines
904 B
JavaScript
26 lines
904 B
JavaScript
// Middleware de auth das rotas /nw/* — valida a integration_key enviada pelo
|
|
// motor NewWhats. Aceita header x-nw-key ou Authorization: Bearer <key>.
|
|
import { timingSafeEqual } from 'crypto'
|
|
import { getConfig } from './config.js'
|
|
|
|
export function nwAuth(req, res, next) {
|
|
const key = req.headers['x-nw-key']
|
|
|| (req.headers['authorization'] || '').replace(/^Bearer\s+/i, '').trim()
|
|
|
|
if (!key) {
|
|
return res.status(401).json({ error: 'Chave de integração ausente. Use o header x-nw-key.' })
|
|
}
|
|
|
|
const stored = getConfig().integrationKey
|
|
if (!stored) {
|
|
return res.status(503).json({ error: 'Integração NewWhats não configurada (NEWWHATS_INTEGRATION_KEY).' })
|
|
}
|
|
|
|
const a = Buffer.from(stored)
|
|
const b = Buffer.from(key)
|
|
if (a.length !== b.length || !timingSafeEqual(a, b)) {
|
|
return res.status(403).json({ error: 'Chave de integração inválida.' })
|
|
}
|
|
next()
|
|
}
|