import crypto from "crypto";
import express from "express";
const app = express();
app.use(express.raw({ type: "application/json" }));
const webhookSecret = process.env.EMERGE_WEBHOOK_SECRET;
if (!webhookSecret) {
throw new Error("Missing EMERGE_WEBHOOK_SECRET");
}
app.post("/webhooks/emerge", async (req, res) => {
try {
const signature = req.header("x-signature");
if (!signature) {
return res.status(401).send("Missing signature");
}
const expected = crypto
.createHmac("sha256", webhookSecret)
.update(req.body)
.digest("hex");
const matches =
signature.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(signature, "hex"), Buffer.from(expected, "hex"));
if (!matches) {
return res.status(401).send("Invalid signature");
}
const payload = JSON.parse(req.body.toString("utf8")) as {
event: string;
uid: string;
sources?: Array<{ provider: string; reason?: string }>;
};
if (payload.event === "consent.revoked") {
await revokeUserAccess(payload.uid, payload.sources ?? []);
}
return res.status(200).send("OK");
} catch (error) {
console.error("Webhook error", error);
return res.status(500).send("Server error");
}
});
async function revokeUserAccess(uid: string, sources: Array<{ provider: string }>) {
for (const source of sources) {
await deleteProviderData(uid, source.provider);
}
}
async function deleteProviderData(uid: string, provider: string) {
console.log(`Deleting ${provider} data for ${uid}`);
}