import {
Button,
CircularProgress,
CircularProgressLabel,
Container,
FormControl,
FormLabel,
Heading,
HStack,
Input,
Link,
Text,
useToast,
} from "@chakra-ui/react";
import { useEffect, useState } from "react";
import Login from "../components/Login";
import Success from "../components/Success";
export function Page(pageProps: { [p: string]: any }) {
if (!pageProps.logged_in) return ;
const [fileProgress, setFileProgress] = useState(0);
const [showSuccess, setShowSuccess] = useState(false);
const [supportsRequestStreams, setSupportsRequestStreams] = useState(false);
const toast = useToast();
const [uploading, setUploading] = useState(false);
useEffect(() => {
if (sessionStorage.getItem("REPORT_SUCCESS")) {
sessionStorage.removeItem("REPORT_SUCCESS");
return setShowSuccess(true);
}
setSupportsRequestStreams(
(() => {
let duplexAccessed = false;
const hasContentType = new Request("", {
body: new ReadableStream(),
method: "POST",
// @ts-ignore
get duplex() {
duplexAccessed = true;
return "half";
},
}).headers.has("Content-Type");
return duplexAccessed && !hasContentType;
})()
);
}, []);
async function submit() {
const usernames = (
document.getElementById("usernames") as HTMLInputElement
).value
.replaceAll(" ", "")
.split(",");
const file = (
document.getElementById("evidence") as HTMLInputElement
).files?.item(0);
if (!usernames.length)
return toast({
description: "Must provide at least one username",
isClosable: true,
status: "error",
title: "Error",
});
if (!file)
return toast({
description: "Must attach a file",
isClosable: true,
status: "error",
title: "Error",
});
if (usernames.length > 20)
return toast({
description: "Only up to twenty users can be reported at a time",
isClosable: true,
status: "error",
title: "Too Many Usernames",
});
const submitReq = await fetch("/api/reports/submit", {
body: JSON.stringify({
filename: file.name,
filesize: file.size,
usernames,
}),
headers: {
"content-type": "application/json",
},
method: "POST",
});
if (!submitReq.ok)
return toast({
description: ((await submitReq.json()) as { error: string }).error,
isClosable: true,
status: "error",
title: "Error",
});
const { id, upload_url }: { id: string; upload_url: string } =
await submitReq.json();
setUploading(true);
const reader = file.stream().getReader();
let bytesRead = 0;
const uploadReq = await fetch(upload_url, {
body: supportsRequestStreams
? new ReadableStream({
async pull(controller) {
const chunk = await reader.read();
if (chunk.done) {
controller.close();
setUploading(false);
return;
}
controller.enqueue(chunk.value);
bytesRead += chunk.value.length;
setFileProgress(Math.floor((bytesRead / file.size) * 100));
},
})
: file,
// @ts-expect-error
duplex: supportsRequestStreams ? "half" : undefined,
headers: {
"content-type": file.type,
},
method: "PUT",
}).catch(console.error);
if (!uploadReq?.ok) {
await fetch("/api/reports/recall", {
body: JSON.stringify({ id }),
headers: {
"content-type": "application/json",
},
method: "POST",
});
return toast({
description: "Failed to upload file",
isClosable: true,
status: "error",
title: "Error",
});
}
await fetch("/api/reports/complete", {
body: JSON.stringify({ id }),
headers: {
"content-type": "application/json",
},
method: "POST",
});
sessionStorage.setItem("REPORT_SUCCESS", "1");
}
return showSuccess ? (
) : (
Report an Exploiter
Username(s) - To specify more than one, provide a comma-delimited list
(User1, User2, User3...)
Your Evidence (Max Size: 512MB)
By submitting this form, you agree to the{" "}
Terms of Service
{" "}
and{" "}
Privacy Policy
.
{supportsRequestStreams ? (
{fileProgress}%
) : null}
);
}