The weeb for the next gen discord boat - Wamellow
wamellow.com
bot
discord
1import { defaultCookieOptions } from "@/lib/cookies";
2import { getCanonicalUrl } from "@/utils/urls";
3import { PermissionFlagsBits } from "discord-api-types/v10";
4import { cookies } from "next/headers";
5import { redirect } from "next/navigation";
6
7import { createSession } from "./api";
8
9const permissions = [
10 PermissionFlagsBits.AddReactions, // greetings
11 PermissionFlagsBits.AttachFiles, // /tts, leaderboards
12 PermissionFlagsBits.BanMembers, // passport
13 PermissionFlagsBits.Connect, // /tts
14 PermissionFlagsBits.CreatePublicThreads, // nsfw moderation
15 PermissionFlagsBits.EmbedLinks, // everything
16 PermissionFlagsBits.KickMembers, // passport
17 PermissionFlagsBits.ManageChannels, // nsfw stuff, /tts, invite tracking
18 PermissionFlagsBits.ManageGuild, // invite tracking
19 PermissionFlagsBits.ManageMessages, // nsfw moderation
20 PermissionFlagsBits.ManageRoles, // greetings
21 PermissionFlagsBits.ManageWebhooks, // greetings
22 PermissionFlagsBits.MentionEveryone, // notifications
23 PermissionFlagsBits.ModerateMembers, // passport
24 PermissionFlagsBits.ReadMessageHistory, // leaderboards, text commands
25 PermissionFlagsBits.SendMessages, // leaderboards, text commands, nsfw moderation, passport
26 PermissionFlagsBits.SendMessagesInThreads, // text commands, nsfw moderation
27 PermissionFlagsBits.Speak, // /tts
28 PermissionFlagsBits.UseExternalEmojis, // everything
29 PermissionFlagsBits.ViewChannel // leaderboards, text commands, nsfw moderation, passport, activity tracking
30];
31
32export async function GET(request: Request) {
33 if (request.headers.get("user-agent")?.includes("Discordbot/2.0")) redirect("/login/open-graph");
34
35 const { searchParams } = new URL(request.url);
36 const jar = await cookies();
37
38 const logout = searchParams.get("logout");
39
40 if (logout) {
41 jar.set(
42 "session",
43 "",
44 {
45 ...defaultCookieOptions,
46 expires: new Date(0)
47 }
48 );
49
50 redirect("/");
51 }
52
53 const guildId = searchParams.get("guild_id");
54 const invite = Boolean(searchParams.get("invite"));
55 const code = searchParams.get("code");
56
57 if (!code) {
58 const callback = searchParams.get("callback");
59 const lastpage = jar.get("lastpage");
60
61 const url = generateOauthUrl(invite, callback || lastpage?.value, guildId);
62 redirect(url);
63 }
64
65 const res = await createSession(code);
66 let redirectUrl = getRedirectUrl(searchParams);
67
68 if (!res || "status" in res) {
69 const data = { statusCode: 500, message: res?.message || "An error occurred" };
70 console.log(data);
71
72 redirectUrl += "?error=" + JSON.stringify(data);
73 redirect(redirectUrl);
74 }
75
76 jar.set(
77 "session",
78 res.session,
79 defaultCookieOptions
80 );
81
82 redirect(redirectUrl);
83}
84
85function generateOauthUrl(invite: boolean, redirectUrl: string | undefined, guildId: string | null) {
86 const params = new URLSearchParams();
87
88 params.append("client_id", process.env.NEXT_PUBLIC_CLIENT_ID as string);
89 params.append("redirect_uri", getCanonicalUrl("login"));
90 params.append("permissions", permissions.reduce((acc, cur) => acc + Number(cur), 0).toString());
91 params.append("prompt", "none");
92 params.append("response_type", "code");
93 params.append("state", encodeURIComponent(redirectUrl || "/"));
94
95 if (invite) params.append("scope", "identify guilds bot");
96 else params.append("scope", "identify guilds email");
97
98 if (guildId) params.append("guild_id", guildId);
99
100 return "https://discord.com/oauth2/authorize?" + params.toString();
101}
102
103function getRedirectUrl(searchParams: URLSearchParams) {
104 const redirectUrl = parseRedirectUrlFromState(searchParams.get("state"));
105 const guildId = searchParams.get("guild_id");
106
107 if (guildId) return `/dashboard/${guildId}${redirectUrl}`;
108 return redirectUrl;
109}
110
111function parseRedirectUrlFromState(state: string | null) {
112 if (!state) return "/";
113
114 const path = decodeURIComponent(state);
115 if (path.includes("://")) return "/";
116
117 return path || "/";
118}