Pacote JavaScript
Use o pacote JavaScript do cside para verificar assinaturas de webhook e manipular eventos de notificação com suporte completo a TypeScript.
Instalando o pacote
Instale o pacote de webhooks do cside:
npm i @cside.dev/webhooks
Usando o pacote
constructEvent(body, signature, secret) verifica o header x-cside-signature
em relação ao corpo bruto da requisição e retorna o evento interpretado. Ele
lança Error("Invalid signature") quando a assinatura não corresponde, então
envolva a chamada em um try/catch e responda com 400 nesse 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,
});
}
}
O pacote também exporta verifyHmac(body, signature, secret) caso você precise
apenas da verificação da assinatura e queira interpretar o corpo por conta
própria.
Os tipos Event e AlertCreatedObject distribuídos em @cside.dev/webhooks
descrevem um payload mais antigo. O motor envia timestamp (e não sent_at),
além de domain e trigger_type no nível superior, e o objeto data usa
target_type e traz os campos ruleset_* e vuln_*. O pacote também tipa
apenas alert.created, e não os eventos de digest. Consulte a referência do
payload para ver os
campos realmente enviados, e faça o cast ou valide o evento retornado de
acordo.
Exemplos
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!