155 lines
3.8 KiB
TypeScript
155 lines
3.8 KiB
TypeScript
import { GenerateUploadURL } from "../../gcloud.js";
|
|
|
|
function errorResponse(error: string, status: number): Response {
|
|
return new Response(JSON.stringify({ error }), {
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
status,
|
|
});
|
|
}
|
|
|
|
export async function onRequestPost(context: RequestContext) {
|
|
const { filename, filesize, usernames } = context.data.body;
|
|
|
|
if (!Array.isArray(usernames))
|
|
return errorResponse("Usernames must be type of array", 400);
|
|
|
|
if (typeof filename !== "string")
|
|
return errorResponse("Invalid file name", 400);
|
|
|
|
if (typeof filesize !== "number" || filesize < 0 || filesize > 536870912)
|
|
return errorResponse("Invalid file size", 400);
|
|
|
|
if (!usernames.length || usernames.length > 20)
|
|
return errorResponse(
|
|
"Number of usernames provided must be between 1 and 20",
|
|
400
|
|
);
|
|
|
|
for (const username of usernames) {
|
|
if (
|
|
username.length < 3 ||
|
|
username.length > 20 ||
|
|
username.match(/_/g)?.length > 1
|
|
)
|
|
return errorResponse(`Username "${username}" is invalid`, 400);
|
|
}
|
|
|
|
const rbxSearchReq = await fetch(
|
|
"https://users.roblox.com/v1/usernames/users",
|
|
{
|
|
body: JSON.stringify({
|
|
usernames,
|
|
excludeBannedUsers: true,
|
|
}),
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
method: "POST",
|
|
}
|
|
);
|
|
|
|
if (!rbxSearchReq.ok)
|
|
return errorResponse(
|
|
"Failed to locate Roblox users due to upstream error",
|
|
500
|
|
);
|
|
|
|
const rbxSearchData: { data: { [k: string]: any }[] } =
|
|
await rbxSearchReq.json();
|
|
|
|
if (rbxSearchData.data.length < usernames.length) {
|
|
const missingUsers = [];
|
|
|
|
for (const userData of rbxSearchData.data) {
|
|
if (!usernames.includes(userData.requestedUsername))
|
|
missingUsers.push(userData.requestedUsername);
|
|
}
|
|
|
|
return errorResponse(
|
|
`The following users do not exist or are banned from Roblox: ${missingUsers.toString()}`,
|
|
400
|
|
);
|
|
}
|
|
|
|
const metaIDs = [];
|
|
const metaNames = [];
|
|
|
|
for (const data of rbxSearchData.data) {
|
|
metaIDs.push(data.id);
|
|
metaNames.push(data.name);
|
|
}
|
|
|
|
const fileParts = filename.split(".");
|
|
let fileExt = fileParts[fileParts.length - 1];
|
|
|
|
if (
|
|
fileParts.length < 2 ||
|
|
![
|
|
"mkv",
|
|
"mp4",
|
|
"wmv",
|
|
"jpg",
|
|
"png",
|
|
"m4v",
|
|
"jpeg",
|
|
"jfif",
|
|
"gif",
|
|
"webm",
|
|
"heif",
|
|
"heic",
|
|
"webp",
|
|
"mov",
|
|
].includes(fileExt.toLowerCase())
|
|
)
|
|
return errorResponse("This type of file cannot be uploaded", 415);
|
|
|
|
const fileKey = `${crypto.randomUUID().replaceAll("-", "")}/${crypto
|
|
.randomUUID()
|
|
.replaceAll("-", "")}${context.request.headers.get("cf-ray")}${Date.now()}`;
|
|
|
|
const reportId = `${Date.now()}${context.request.headers.get(
|
|
"cf-ray"
|
|
)}${crypto.randomUUID().replaceAll("-", "")}`;
|
|
|
|
const uploadUrl = await GenerateUploadURL(
|
|
context.env,
|
|
fileKey,
|
|
filesize,
|
|
fileExt
|
|
);
|
|
|
|
await context.env.DATA.put(
|
|
`reportprocessing_${reportId}`,
|
|
context.data.current_user.id,
|
|
{ expirationTtl: 3600 }
|
|
);
|
|
await context.env.DATA.put(
|
|
`report_${reportId}`,
|
|
JSON.stringify({
|
|
attachment: `${fileKey}.${
|
|
["mkv", "mov", "wmv"].includes(fileExt.toLowerCase()) ? "mp4" : fileExt
|
|
}`,
|
|
reporter: context.data.current_user,
|
|
target_ids: metaIDs,
|
|
target_usernames: metaNames,
|
|
}),
|
|
{
|
|
metadata: {
|
|
i: context.data.current_user.id,
|
|
r: metaIDs.toString(),
|
|
p: true,
|
|
s: `${context.data.current_user.username}#${context.data.current_user.discriminator}`,
|
|
u: metaNames.toString(),
|
|
},
|
|
}
|
|
);
|
|
|
|
return new Response(JSON.stringify({ id: reportId, upload_url: uploadUrl }), {
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
});
|
|
}
|