Initial commit: sap-webhook-api
API NestJS que recibe el Webhook Messenger de SAP Business One (CloudEvents), valida HMAC opcional y guarda cada notificacion local (data/events/) e inserta en Postgres (webhook_events). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
commit
5e0df73477
28 files changed
+11773
No files matched your search
@@ -0,0 +1,114 @@
|
||||
# Cómo ejecutar la API (con y sin HMAC)
|
||||
|
||||
Guía rápida para levantar `sap-webhook-api` en los dos modos soportados:
|
||||
sin autenticación (`AuthenticationType: None`, el modo actual de la
|
||||
suscripción real en SAP) y con firma HMAC.
|
||||
|
||||
## 0. Una sola vez: preparar el entorno
|
||||
|
||||
```bash
|
||||
cd sap-webhook-api
|
||||
npm install
|
||||
cp .env.example .env # si todavía no existe .env
|
||||
```
|
||||
|
||||
Revisá que `.env` tenga los datos correctos de tu Service Layer
|
||||
(`SERVICE_LAYER_URL`, `COMPANY_DB`, `SL_USER`, `SL_PASS`, `WEBHOOK_ID`). El
|
||||
certificado HTTPS (`certs/key.pem` / `certs/cert.pem`) ya debería existir —
|
||||
si no, ver `PASOS-REALIZADOS.md`, sección 9.
|
||||
|
||||
**Importante**: el modo con el que arranca la API (`.env` →
|
||||
`HMAC_SECRET_KEY`) tiene que coincidir con el `AuthenticationType`
|
||||
configurado en la suscripción real de SAP. Si no coinciden, SAP manda
|
||||
notificaciones que la API rechaza (o al revés, la API acepta sin validar
|
||||
nada aunque SAP crea que está firmando). Los scripts de la sección 2 se
|
||||
encargan de mantenerlos sincronizados.
|
||||
|
||||
## 1. Modo sin autenticación (`AuthenticationType: None`)
|
||||
|
||||
Es el modo por defecto — no requiere ningún paso extra.
|
||||
|
||||
```bash
|
||||
# confirmá que HMAC_SECRET_KEY esté vacío en .env
|
||||
npm run start
|
||||
```
|
||||
|
||||
La API queda escuchando en `https://<tu-ip>:3000/webhooks/sap`, acepta
|
||||
cualquier notificación sin validar firma. Prueba local:
|
||||
|
||||
```bash
|
||||
curl -sk -i -X POST https://localhost:3000/webhooks/sap \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '[{"id":"test-1","type":"sap.b1.Orders.Created.v1","subject":"1","data":{"DocEntry":"1"}}]'
|
||||
# -> 200 OK
|
||||
```
|
||||
|
||||
## 2. Modo con HMAC (`AuthenticationType: HMAC`)
|
||||
|
||||
### 2.1 Activar
|
||||
|
||||
```bash
|
||||
npm run auth:hmac:on
|
||||
```
|
||||
|
||||
Esto:
|
||||
1. Genera un `HMAC_SECRET_KEY` (si `.env` no tenía uno) y lo guarda en `.env`.
|
||||
2. Hace `Login` en el Service Layer, lee la configuración actual de la
|
||||
suscripción (`WEBHOOK_ID` de `.env`), la **pausa**, la **elimina** y la
|
||||
**vuelve a crear** con `AuthenticationType: "HMAC"` — el Service Layer
|
||||
no permite cambiar `AuthenticationType` con `PATCH` sobre una
|
||||
suscripción existente, así que este es el único camino soportado
|
||||
(se conserva `WebhookURL`, `Handshake` y `EventCollection` originales).
|
||||
`AuthenticationCred` no es el secreto pelado: va como un string con
|
||||
JSON embebido, `{"Key": "<secreto>", "Algorithm": "hmacsha256"}`.
|
||||
|
||||
Después, **reiniciá la API** para que tome el `HMAC_SECRET_KEY` nuevo:
|
||||
|
||||
```bash
|
||||
npm run start
|
||||
```
|
||||
|
||||
A partir de este momento, todo `POST /webhooks/sap` sin la firma correcta
|
||||
en el header `X-B1-Webhook-Signature` (HMAC-SHA256 del body, en base64)
|
||||
devuelve `401 Unauthorized`.
|
||||
|
||||
### 2.2 Probar manualmente (simulando lo que hace SAP)
|
||||
|
||||
```bash
|
||||
SECRET=$(grep '^HMAC_SECRET_KEY=' .env | cut -d= -f2)
|
||||
BODY='[{"id":"test-2","type":"sap.b1.Orders.Created.v1","subject":"2","data":{"DocEntry":"2"}}]'
|
||||
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -binary | openssl base64)
|
||||
|
||||
curl -sk -i -X POST https://localhost:3000/webhooks/sap \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-B1-Webhook-Signature: $SIG" \
|
||||
-d "$BODY"
|
||||
# -> 200 OK
|
||||
|
||||
# sin firma o con una firma incorrecta -> 401
|
||||
curl -sk -i -X POST https://localhost:3000/webhooks/sap \
|
||||
-H "Content-Type: application/json" -d "$BODY"
|
||||
```
|
||||
|
||||
### 2.3 Desactivar (volver a `None`)
|
||||
|
||||
```bash
|
||||
npm run auth:hmac:off
|
||||
npm run start # reiniciar para que la API deje de exigir la firma
|
||||
```
|
||||
|
||||
Esto revierte la suscripción en SAP a `AuthenticationType: "None"` y vacía
|
||||
`HMAC_SECRET_KEY` en `.env`, en un solo paso.
|
||||
|
||||
## Referencia rápida
|
||||
|
||||
| Acción | Comando |
|
||||
|---|---|
|
||||
| Instalar dependencias | `npm install` |
|
||||
| Levantar la API | `npm run start` |
|
||||
| Activar HMAC (API + SAP) | `npm run auth:hmac:on` |
|
||||
| Desactivar HMAC (API + SAP) | `npm run auth:hmac:off` |
|
||||
| Ver estado actual de la suscripción | `curl -sk -b cookies.txt "$SERVICE_LAYER_URL/EventSubscriptions('$WEBHOOK_ID')"` (después de un `Login`) |
|
||||
|
||||
Detalle de la implementación (cómo se valida la firma, por qué se usa el
|
||||
body crudo, etc.) en `CLAUDE.md`.
|
||||
Reference in new issue
Block a user