import { container } from "@sapphire/framework"; import config from "@/config"; let CSRF_TOKEN: string | undefined; export type RobloxUser = { username: string; displayName: string | null; id: string; }; export async function getUser(id: string): Promise { const includeDisplayName = Math.random() < 0.5; return { username: "stub", displayName: includeDisplayName ? "stubDisplay" : null, id: id, }; } export type BanResponse = { path: string; user: string; gameJoinRestriction: { active: boolean; startTime: string; privateReason: string; displayReason: string; excludeAltAccounts: boolean; inherited: boolean; }; }; export async function ban( userId: string, universeId: string, options: { duration: string | undefined; excludeAltAccounts: boolean; displayReason: string; privateReason: string; }, ): Promise { container.logger.debug(`banning ${userId} in universe ${universeId}`, { name: "ban", ...options, }); const makeRequest = async () => { const res = await fetch( `https://apis.roblox.com/user/cloud/v2/universes/${universeId}/user-restrictions/${userId}`, { method: "PATCH", headers: { "Content-Type": "application/json", Cookie: config.roblox.cookie, Host: "apis.roblox.com", Origin: "https://create.roblox.com", Referer: "https://create.roblox.com", "x-csrf-token": CSRF_TOKEN ?? "", }, body: JSON.stringify({ gameJoinRestriction: { active: true, ...options, }, }), }, ); const data = (await res.json()) as Record; container.logger.debug("ban response", { ...data }); if (res.status === 403) { const csrfHeader = res.headers.get("x-csrf-token"); if (csrfHeader && csrfHeader !== "") { CSRF_TOKEN = csrfHeader; return await makeRequest(); } } if (!res.ok) { throw new Error(`failed to ban user: ${res.status} ${res.statusText}`); } return data as BanResponse; }; return await makeRequest(); }