Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
car-crushers-portal/functions/api/reports/submit.ts
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
178 lines (152 sloc)
4.44 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, turnstileResponse, usernames } = | |
context.data.body; | |
if (!context.data.current_user) { | |
if (typeof turnstileResponse !== "string") | |
return errorResponse("You must complete the captcha", 401); | |
const turnstileAPIResponse = await fetch( | |
"https://challenges.cloudflare.com/turnstile/v0/siteverify", | |
{ | |
body: JSON.stringify({ | |
response: turnstileResponse, | |
secret: context.env.TURNSTILE_SECRETKEY, | |
}), | |
headers: { | |
"content-type": "application/json", | |
}, | |
method: "POST", | |
} | |
); | |
const { success }: { success: boolean } = await turnstileAPIResponse.json(); | |
if (!success) return errorResponse("Captcha test failed", 403); | |
} | |
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", | |
}, | |
}); | |
} |