Add rtbf webhook
This commit is contained in:
@@ -0,0 +1,95 @@
|
|||||||
|
import { jsonError } from "../common.js";
|
||||||
|
import { Report } from "../../generated/prisma/client.js";
|
||||||
|
import { getBanList, setBanList } from "../roblox-open-cloud.js";
|
||||||
|
|
||||||
|
export async function onRequestPost(context: RequestContext) {
|
||||||
|
const body = await context.request.text();
|
||||||
|
const secret = context.env.ROBLOX_WEBHOOK_SECRET;
|
||||||
|
|
||||||
|
if (!secret) return jsonError("This endpoint is currently disabled", 503);
|
||||||
|
|
||||||
|
const sigHeader = context.request.headers.get("roblox-signature");
|
||||||
|
|
||||||
|
if (!sigHeader) return jsonError("Missing signature", 401);
|
||||||
|
|
||||||
|
const [timestamp, sig] = sigHeader.split(",");
|
||||||
|
|
||||||
|
if (
|
||||||
|
parseInt(timestamp.replace("t=", "")) <
|
||||||
|
Math.floor(Date.now() / 1000) - 600
|
||||||
|
)
|
||||||
|
return jsonError("This request is stale", 406);
|
||||||
|
|
||||||
|
const textEncode = (text: string) => new TextEncoder().encode(text);
|
||||||
|
const key = await crypto.subtle.importKey(
|
||||||
|
"raw",
|
||||||
|
textEncode(secret),
|
||||||
|
{
|
||||||
|
hash: "SHA-256",
|
||||||
|
name: "HMAC",
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
["verify"],
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!(await crypto.subtle.verify(
|
||||||
|
"HMAC",
|
||||||
|
key,
|
||||||
|
Uint8Array.from(atob(sig.replace("v1=", "")), (c) => c.charCodeAt(0)),
|
||||||
|
textEncode(`${timestamp.replace("t=", "")}.${body}`),
|
||||||
|
))
|
||||||
|
)
|
||||||
|
return jsonError("Invalid signature", 403);
|
||||||
|
|
||||||
|
const data = JSON.parse(body);
|
||||||
|
|
||||||
|
if (data.EventType === "SampleNotification")
|
||||||
|
return new Response(null, {
|
||||||
|
status: 204,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (data.EventType !== "RightToErasureRequest")
|
||||||
|
return jsonError("Invalid event type", 400);
|
||||||
|
|
||||||
|
const { prisma } = context.data;
|
||||||
|
const userId = data.EventPrisma.UserId;
|
||||||
|
|
||||||
|
if (typeof userId !== "number") return jsonError("Invalid user id", 400);
|
||||||
|
|
||||||
|
await prisma.gameModLog.deleteMany({
|
||||||
|
where: {
|
||||||
|
target: userId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const associatedReports = await prisma.$queryRaw<
|
||||||
|
Report[]
|
||||||
|
>`SELECT attachments, id FROM reports WHERE EXISTS (SELECT 1 FROM json_each(target_ids) WHERE VALUE = ${userId});`;
|
||||||
|
|
||||||
|
const idsToDelete: string[] = [];
|
||||||
|
for (const report of associatedReports) {
|
||||||
|
for (const attachment of report.attachments as string[]) {
|
||||||
|
await context.env.R2.delete(attachment);
|
||||||
|
}
|
||||||
|
idsToDelete.push(report.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
await prisma.report.deleteMany({
|
||||||
|
where: {
|
||||||
|
id: {
|
||||||
|
in: idsToDelete,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const { etag, value } = await getBanList(context);
|
||||||
|
|
||||||
|
delete value[userId];
|
||||||
|
|
||||||
|
await setBanList(context, value, etag);
|
||||||
|
|
||||||
|
return new Response(null, {
|
||||||
|
status: 204,
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user