JavaScript Package
Usa el paquete JavaScript de cside para verificar firmas de webhook y manejar eventos de notificación con soporte completo de TypeScript.
Instalar el paquete
Instala el paquete de webhooks de cside:
npm i @cside.dev/webhooks
Usar el paquete
constructEvent(body, signature, secret) verifica el encabezado x-cside-signature
contra el cuerpo crudo de la solicitud y devuelve el evento analizado. Lanza
Error("Invalid signature") cuando la firma no coincide, así que envuelve la llamada
en un try/catch y responde con 400 en ese caso.
import { constructEvent } from "@cside.dev/webhooks";
const rawBody = req.rawBody; // The raw request body as a string; how you get it depends on your HTTP framework
const signature = req.headers["x-cside-signature"]; // Sent with every cside webhook request
const event = await constructEvent(
rawBody,
signature,
process.env.CSIDE_WEBHOOK_SECRET, // The secret you configured on the webhook destination
);
switch (event.event) {
case "alert.created": {
const alert = event.data;
console.log({
domainId: event.domain_id,
target: alert.target,
action: alert.action,
});
}
}
El paquete también exporta verifyHmac(body, signature, secret) si solo necesitas la
comprobación de la firma y quieres analizar el cuerpo por tu cuenta.
Los tipos Event y AlertCreatedObject incluidos en @cside.dev/webhooks
describen un payload anterior. El motor envía timestamp (no sent_at), además de
domain y trigger_type en el nivel superior, y el objeto data usa target_type
e incluye los campos ruleset_* y vuln_*. El paquete además solo tipa
alert.created, no los eventos de resumen. Consulta la referencia del
payload para ver los
campos que realmente se envían, y convierte o valida el evento devuelto en
consecuencia.
Ejemplos
import Fastify from 'fastify';
import { constructEvent } from "@cside.dev/webhooks";
const fastify = Fastify({ logger: true });
await fastify.register(import('@fastify/raw-body'), {
field: 'rawBody',
global: false,
routes: ['/webhook']
});
fastify.post('/webhook', {
config: { rawBody: true }
}, async (request, reply) => {
const signature = request.headers['x-cside-signature'];
const webhookEvent = await constructEvent(
request.rawBody,
signature,
process.env.CSIDE_WEBHOOK_SECRET!,
);
switch (webhookEvent.event) {
case "alert.created": {
const alert = webhookEvent.data;
console.log({
domainId: webhookEvent.domain_id,
target: alert.target,
action: alert.action,
});
}
}
});import { createKaitoHandler, KaitoError } from "@kaito-http/core";
import { constructEvent } from "@cside.dev/webhooks";
const app = router()
.get("/", async ({ ctx }) => {
return {
uptime: ctx.uptime,
time_now: Date.now(),
};
})
.post("/", async ({ ctx }) => {
const signature = ctx.req.headers.get("x-cside-signature");
if (!signature) {
throw new KaitoError(400, "Missing signature");
}
const rawBody = await ctx.req.text();
const webhookEvent = await constructEvent(
rawBody,
signature,
process.env.CSIDE_WEBHOOK_SECRET!,
);
switch (webhookEvent.event) {
case "alert.created": {
const alert = webhookEvent.data;
console.log({
domainId: webhookEvent.domain_id,
target: alert.target,
action: alert.action,
});
}
}
return {
message: "OK!",
};
});Thanks for your feedback!