borders/app/discord/index.ts

124 lines
4.4 KiB
TypeScript

import axios from 'axios';
import { prisma } from "~/db.server";
import { createUserSession } from '~/session.server';
export interface DiscordUser {
id: string;
username: string;
discriminator: string;
avatar: string;
bot?: boolean;
system?: boolean;
mfa_enabled?: boolean;
}
export interface AccessTokenResponse {
access_token: string;
expires: number;
refresh_token: string;
}
export function getAccessToken(code: string): Promise<AccessTokenResponse> {
return new Promise(
(resolve, reject) => {
const body = new FormData();
body.append("grant_type", "authorization_code");
body.append("code", code);
body.append("redirect_url", process.env.DISCORD_REDIRECT_URI || "");
axios.post("https://discord.com/api/oauth2/token", body)
.then((res) => {
const { access_token, refresh_token, expires_in } = res.data;
resolve({
access_token,
refresh_token,
expires: Date.now() + expires_in * 1000
});
})
.catch(reject);
}
)
}
export async function authorize(access_code: string): Promise<AccessTokenResponse | undefined> {
return new Promise(
(resolve, reject) => {
const formData = new FormData();
formData.append("client_id", process.env.DISCORD_CLIENT_ID || "");
formData.append("client_secret", process.env.DISCORD_CLIENT_SECRET || "");
formData.append("grant_type", "authorization_code");
formData.append("redirect_uri", process.env.DISCORD_REDIRECT_URI || "");
formData.append("scope", "identify");
formData.append("code", access_code);
axios.post("https://discord.com/api/oauth2/token", formData)
.then((res) => {
const { access_token, refresh_token, expires_in } = res.data;
resolve({
access_token,
refresh_token,
expires: Date.now() + expires_in * 1000
});
})
.catch(reject);
}
)
}
export function getDiscordUser(token: string): Promise<DiscordUser> {
return new Promise(
(resolve, reject) => {
axios.get("https://discord.com/api/users/@me", {
headers: {
Authorization: `Bearer ${token}`
}
})
.then(
(res) => {
resolve(res.data);
}
)
.catch(reject);
}
)
}
export async function discordLogin(request: Request, code: string): Promise<Response> {
return new Promise(
(resolve, reject) => {
getAccessToken(code)
.then((token) => {
getDiscordUser(token.access_token)
.then(async (user) => {
prisma.discordUser.upsert({
create: {
discord_id: user.id,
access_token: token.access_token,
refresh_token: token.refresh_token,
expires: new Date(token.expires),
username: user.username,
discriminator: user.discriminator,
},
update: {
discord_id: user.id,
access_token: token.access_token,
refresh_token: token.refresh_token,
expires: new Date(token.expires),
username: user.username,
discriminator: user.discriminator,
},
where: {
discord_id: user.id
}
})
.then(async () => {
resolve(await createUserSession({request, discord_id: user.id, redirectTo: '/'}));
})
})
})
}
)
}