Remove data transfer code
This commit is contained in:
@@ -1,42 +0,0 @@
|
|||||||
import { Button, Container, Heading, Text } from "@chakra-ui/react";
|
|
||||||
|
|
||||||
export default function () {
|
|
||||||
return (
|
|
||||||
<Container maxW="container.md">
|
|
||||||
<Heading size="lg">Transfer your Save Data</Heading>
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<Text>Lost your account? Want to shake off a stalker?</Text>
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<Text size="lg">We can help!</Text>
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<Text>Some information you should know:</Text>
|
|
||||||
<br />
|
|
||||||
<Text>
|
|
||||||
We might require your .ROBLOSECURITY cookie, depending on your
|
|
||||||
circumstances. This is because Roblox does not allow terminated accounts
|
|
||||||
to utilize OAuth. Normally this would be a very bad idea, and we don't
|
|
||||||
like doing this either, but it may be the only option. Security is also
|
|
||||||
less of a concern for terminated accounts as they are blocked from
|
|
||||||
accessing almost all Roblox API endpoints (the exceptions being login,
|
|
||||||
logout, and creating support tickets - and only the logout endpoint
|
|
||||||
doesn't require completing a captcha). If you are concerned about your
|
|
||||||
account's security, we suggest logging in to your terminated account in
|
|
||||||
a private/incognito window, copying the .ROBLOSECURITY cookie from
|
|
||||||
there, and logging out once we have verified your old account (which
|
|
||||||
normally only takes a few seconds). The ultra paranoid may also consider
|
|
||||||
resetting their password. If you are not convinced or still have
|
|
||||||
questions, join our Discord server (link is on the about page) and open
|
|
||||||
a ticket with ModMail for us to verify you manually (no cookie
|
|
||||||
required).
|
|
||||||
</Text>
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<Button as="a" href="/data-transfer/start" colorScheme="blue">
|
|
||||||
Start my Transfer
|
|
||||||
</Button>
|
|
||||||
</Container>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
import Success from "../../components/Success.js";
|
|
||||||
|
|
||||||
export default function () {
|
|
||||||
return (
|
|
||||||
<Success
|
|
||||||
heading="Data Transfer Submitted"
|
|
||||||
message="Your request is now being processed; this normally takes 1-2 weeks."
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
import { Button, Card, Container, Heading, VStack } from "@chakra-ui/react";
|
|
||||||
import { useLoaderData } from "@remix-run/react";
|
|
||||||
|
|
||||||
export async function loader({ context }: { context: RequestContext }) {
|
|
||||||
const { host, protocol } = new URL(context.request.url);
|
|
||||||
|
|
||||||
return { client_id: context.env.ROBLOX_OAUTH_CLIENT_ID, host, protocol };
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function () {
|
|
||||||
const loaderData = useLoaderData<typeof loader>();
|
|
||||||
return (
|
|
||||||
<Container pt="16vh">
|
|
||||||
<Card borderRadius="32px" p="4vh">
|
|
||||||
<VStack alignContent="center" gap="2vh">
|
|
||||||
<Heading>Verify your new Roblox account</Heading>
|
|
||||||
<br />
|
|
||||||
<Button
|
|
||||||
as="a"
|
|
||||||
borderRadius="24px"
|
|
||||||
colorScheme="blue"
|
|
||||||
href={`https://apis.roblox.com/oauth/v1/authorize?client_id=${
|
|
||||||
loaderData.client_id
|
|
||||||
}&redirect_uri=${encodeURIComponent(
|
|
||||||
`${loaderData.protocol}//${loaderData.host}/api/data-transfers/verify`,
|
|
||||||
)}&response_type=code&scope=openid%20profile`}
|
|
||||||
>
|
|
||||||
Verify
|
|
||||||
</Button>
|
|
||||||
</VStack>
|
|
||||||
</Card>
|
|
||||||
</Container>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
import {
|
|
||||||
Button,
|
|
||||||
Container,
|
|
||||||
Heading,
|
|
||||||
HStack,
|
|
||||||
Radio,
|
|
||||||
RadioGroup,
|
|
||||||
Text,
|
|
||||||
Textarea,
|
|
||||||
useToast,
|
|
||||||
} from "@chakra-ui/react";
|
|
||||||
import { useState } from "react";
|
|
||||||
|
|
||||||
export default function () {
|
|
||||||
const [showCookieBox, setShowCookieBox] = useState(false);
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
return (
|
|
||||||
<Container maxW="container.md">
|
|
||||||
<Heading pt="36px">Let's get started</Heading>
|
|
||||||
<Text pt="128px">Is your old Roblox account banned?</Text>
|
|
||||||
<RadioGroup onChange={(val) => setShowCookieBox(JSON.parse(val))}>
|
|
||||||
<HStack>
|
|
||||||
<Radio value="false">No</Radio>
|
|
||||||
<Radio value="true">Yes</Radio>
|
|
||||||
</HStack>
|
|
||||||
</RadioGroup>
|
|
||||||
<Textarea
|
|
||||||
id="cookie-box"
|
|
||||||
placeholder="Paste your .ROBLOSECURITY cookie here"
|
|
||||||
mt="16px"
|
|
||||||
style={{ display: showCookieBox ? "initial" : "none" }}
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
colorScheme="blue"
|
|
||||||
isLoading={loading}
|
|
||||||
loadingText="Processing..."
|
|
||||||
mt="16px"
|
|
||||||
onClick={async () => {
|
|
||||||
setLoading(true);
|
|
||||||
const createTransferReq = await fetch("/api/data-transfers/create", {
|
|
||||||
body: JSON.stringify({
|
|
||||||
can_access: !showCookieBox,
|
|
||||||
cookie: (
|
|
||||||
document.getElementById("cookie-box") as HTMLInputElement
|
|
||||||
).value,
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
"content-type": "application/json",
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!createTransferReq.ok) {
|
|
||||||
setLoading(false);
|
|
||||||
useToast()({
|
|
||||||
description: (
|
|
||||||
(await createTransferReq.json()) as { error: string }
|
|
||||||
).error,
|
|
||||||
isClosable: true,
|
|
||||||
status: "error",
|
|
||||||
title: "Failed to create transfer request",
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
location.assign(
|
|
||||||
((await createTransferReq.json()) as { url: string }).url,
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Continue
|
|
||||||
</Button>
|
|
||||||
<br />
|
|
||||||
<Text pt="16px">
|
|
||||||
If you cannot login at all, please visit the support page and join our
|
|
||||||
server.
|
|
||||||
</Text>
|
|
||||||
</Container>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
export async function onRequest(context: RequestContext) {
|
|
||||||
const cookies = context.request.headers.get("cookie");
|
|
||||||
|
|
||||||
if (!cookies) return await context.next();
|
|
||||||
|
|
||||||
const cookieList = cookies.split("; ").map((cookie: string) => {
|
|
||||||
const [name, value] = cookie.split("=");
|
|
||||||
|
|
||||||
return { name, value };
|
|
||||||
});
|
|
||||||
|
|
||||||
const transferId = cookieList.find(
|
|
||||||
(cookie: { name: string; value: string }) => cookie.name === "__dtid",
|
|
||||||
);
|
|
||||||
|
|
||||||
if (transferId) context.data.data_transfer_id = transferId;
|
|
||||||
|
|
||||||
return await context.next();
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
import { jsonError } from "../../common.js";
|
|
||||||
|
|
||||||
export async function onRequestPost(context: RequestContext) {
|
|
||||||
const { cookie, is_banned } = context.data.body;
|
|
||||||
|
|
||||||
if (
|
|
||||||
typeof is_banned !== "boolean" ||
|
|
||||||
(is_banned && typeof cookie !== "string") ||
|
|
||||||
(is_banned &&
|
|
||||||
!cookie.match(
|
|
||||||
/_\|WARNING:-DO-NOT-SHARE-THIS\.--Sharing-this-will-allow-someone-to-log-in-as-you-and-to-steal-your-ROBUX-and-items\.\|_[A-F\d]+/,
|
|
||||||
))
|
|
||||||
)
|
|
||||||
return jsonError("Invalid request", 400);
|
|
||||||
|
|
||||||
const id =
|
|
||||||
(context.request.headers.get("cf-ray")?.split("-")[0] as string) +
|
|
||||||
Date.now().toString() +
|
|
||||||
crypto.randomUUID().replaceAll("-", "");
|
|
||||||
|
|
||||||
if (!is_banned) {
|
|
||||||
await context.env.DATA.put(`datatransfer_${id}`, "{}", {
|
|
||||||
expirationTtl: 3600,
|
|
||||||
});
|
|
||||||
|
|
||||||
const host = context.request.headers.get("Host") as string;
|
|
||||||
|
|
||||||
return new Response(
|
|
||||||
`{"url":"https://apis.roblox.com/oauth/v1/authorize?client_id=${
|
|
||||||
context.env.ROBLOX_OAUTH_CLIENT_ID
|
|
||||||
}&redirect_uri=${encodeURIComponent(
|
|
||||||
`http${host.startsWith(
|
|
||||||
"localhost" ? "" : "s",
|
|
||||||
)}://${host}/api/data-transfers/verify`,
|
|
||||||
)}"}`,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
"set-cookie": `__dtid=${id}; HttpOnly; Max-Age=3600; Path=/; SameSite=Lax; Secure`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const authedUserReq = await fetch(
|
|
||||||
"https://users.roblox.com/v1/users/authenticated",
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
cookie: `.ROBLOSECURITY=${cookie}`,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!authedUserReq.ok) return jsonError("Cookie is invalid", 400);
|
|
||||||
|
|
||||||
const authedUser: { id: number; name: string } = await authedUserReq.json();
|
|
||||||
|
|
||||||
await context.env.DATA.put(
|
|
||||||
`datatransfer_${id}`,
|
|
||||||
JSON.stringify({
|
|
||||||
oldUser: authedUser,
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
expirationTtl: 3600,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
return new Response(null, {
|
|
||||||
headers: {
|
|
||||||
location: "/data-transfer/destination-account",
|
|
||||||
"set-cookie": `__dtid=${id}; HttpOnly; Max-Age=3600; Path=/; SameSite=Lax; Secure`,
|
|
||||||
},
|
|
||||||
status: 201,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,92 +0,0 @@
|
|||||||
import { jsonError } from "../../common.js";
|
|
||||||
import { getBanList } from "../../roblox-open-cloud.js";
|
|
||||||
|
|
||||||
export async function onRequestGet(context: RequestContext) {
|
|
||||||
const code = new URL(context.request.url).searchParams.get("code");
|
|
||||||
|
|
||||||
if (!code) return jsonError("Missing code", 400);
|
|
||||||
|
|
||||||
const dataTransferData = (await context.env.DATA.get(
|
|
||||||
`datatransfer_${context.data.data_transfer_id}`,
|
|
||||||
{ type: "json" },
|
|
||||||
)) as { [k: string]: any } | null;
|
|
||||||
|
|
||||||
if (!dataTransferData)
|
|
||||||
return jsonError("No transfer exists with that ID", 404);
|
|
||||||
|
|
||||||
const exchangeReq = await fetch("https://apis.roblox.com/oauth/v1/token", {
|
|
||||||
body: `code=${code}&grant_type=authorization_code`,
|
|
||||||
headers: {
|
|
||||||
authorization: `Basic ${
|
|
||||||
btoa(context.env.ROBLOX_OAUTH_ID) +
|
|
||||||
":" +
|
|
||||||
context.env.ROBLOX_OAUTH_SECRET
|
|
||||||
}`,
|
|
||||||
"content-type": "application/x-www-form-urlencoded",
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!exchangeReq.ok) return jsonError("Failed to redeem code", 500);
|
|
||||||
|
|
||||||
const { id_token } = (await exchangeReq.json()) as { id_token: string };
|
|
||||||
|
|
||||||
const { name, preferred_username, sub } = JSON.parse(
|
|
||||||
atob(id_token.replaceAll("-", "+").replaceAll("_", "/")),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!preferred_username) return jsonError("Username missing", 500);
|
|
||||||
|
|
||||||
const userObj = {
|
|
||||||
displayName: name,
|
|
||||||
id: parseInt(sub),
|
|
||||||
name: preferred_username,
|
|
||||||
};
|
|
||||||
|
|
||||||
let redirectLocation = "/data-transfer/complete";
|
|
||||||
|
|
||||||
if (dataTransferData.oldUser) {
|
|
||||||
let banList;
|
|
||||||
|
|
||||||
try {
|
|
||||||
banList = (await getBanList(context)).value;
|
|
||||||
} catch {
|
|
||||||
return jsonError("Failed to create data transfer request", 500);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (banList[userObj.id].BanType)
|
|
||||||
return new Response(null, {
|
|
||||||
headers: {
|
|
||||||
location: redirectLocation,
|
|
||||||
},
|
|
||||||
status: 302,
|
|
||||||
});
|
|
||||||
|
|
||||||
dataTransferData.newUser = userObj;
|
|
||||||
|
|
||||||
await fetch(
|
|
||||||
`https://api.trello.com/1/cards?key=${context.env.TRELLO_API_KEY}&token=${context.env.TRELLO_API_TOKEN}`,
|
|
||||||
{
|
|
||||||
body: JSON.stringify({
|
|
||||||
desc: `${dataTransferData.oldUser.name} -> ${userObj.name}\n${dataTransferData.oldUser.id} -> ${userObj.id}\nNO MODMAIL TICKET - WEBSITE FORM SUBMISSION`,
|
|
||||||
idList: context.env.TRELLO_LIST_ID,
|
|
||||||
name: `${dataTransferData.oldUser.name} | Data Transfer`,
|
|
||||||
}),
|
|
||||||
headers: {
|
|
||||||
"content-type": "application/json",
|
|
||||||
},
|
|
||||||
method: "POST",
|
|
||||||
},
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
dataTransferData.oldUser = userObj;
|
|
||||||
redirectLocation = "/data-transfer/destination-account";
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Response(null, {
|
|
||||||
headers: {
|
|
||||||
location: redirectLocation,
|
|
||||||
},
|
|
||||||
status: 302,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user