mirror of
https://github.com/roleypoly/roleypoly.git
synced 2025-06-17 01:59:08 +00:00
chore: update prettier tab width for consistency
This commit is contained in:
parent
a931f8c69c
commit
9b71a24e2d
247 changed files with 7224 additions and 7375 deletions
|
@ -1,159 +1,159 @@
|
|||
import {
|
||||
AuthTokenResponse,
|
||||
DiscordUser,
|
||||
GuildSlug,
|
||||
SessionData,
|
||||
StateSession,
|
||||
AuthTokenResponse,
|
||||
DiscordUser,
|
||||
GuildSlug,
|
||||
SessionData,
|
||||
StateSession,
|
||||
} from '@roleypoly/types';
|
||||
import KSUID from 'ksuid';
|
||||
import {
|
||||
AuthType,
|
||||
discordFetch,
|
||||
formData,
|
||||
getStateSession,
|
||||
isAllowedCallbackHost,
|
||||
parsePermissions,
|
||||
resolveFailures,
|
||||
userAgent,
|
||||
AuthType,
|
||||
discordFetch,
|
||||
formData,
|
||||
getStateSession,
|
||||
isAllowedCallbackHost,
|
||||
parsePermissions,
|
||||
resolveFailures,
|
||||
userAgent,
|
||||
} from '../utils/api-tools';
|
||||
import { Bounce } from '../utils/bounce';
|
||||
import { apiPublicURI, botClientID, botClientSecret, uiPublicURI } from '../utils/config';
|
||||
import { Sessions } from '../utils/kv';
|
||||
|
||||
const AuthErrorResponse = (extra?: string) =>
|
||||
Bounce(
|
||||
uiPublicURI +
|
||||
`/machinery/error?error_code=authFailure${extra ? `&extra=${extra}` : ''}`
|
||||
);
|
||||
Bounce(
|
||||
uiPublicURI +
|
||||
`/machinery/error?error_code=authFailure${extra ? `&extra=${extra}` : ''}`
|
||||
);
|
||||
|
||||
export const LoginCallback = resolveFailures(
|
||||
AuthErrorResponse,
|
||||
async (request: Request): Promise<Response> => {
|
||||
let bounceBaseUrl = uiPublicURI;
|
||||
AuthErrorResponse,
|
||||
async (request: Request): Promise<Response> => {
|
||||
let bounceBaseUrl = uiPublicURI;
|
||||
|
||||
const query = new URL(request.url).searchParams;
|
||||
const stateValue = query.get('state');
|
||||
const query = new URL(request.url).searchParams;
|
||||
const stateValue = query.get('state');
|
||||
|
||||
if (stateValue === null) {
|
||||
return AuthErrorResponse('state missing');
|
||||
}
|
||||
|
||||
try {
|
||||
const state = KSUID.parse(stateValue);
|
||||
const stateExpiry = state.date.getTime() + 1000 * 60 * 5;
|
||||
const currentTime = Date.now();
|
||||
|
||||
if (currentTime > stateExpiry) {
|
||||
return AuthErrorResponse('state expired');
|
||||
}
|
||||
|
||||
const stateSession = await getStateSession<StateSession>(state.string);
|
||||
if (
|
||||
stateSession?.callbackHost &&
|
||||
isAllowedCallbackHost(stateSession.callbackHost)
|
||||
) {
|
||||
bounceBaseUrl = stateSession.callbackHost;
|
||||
}
|
||||
} catch (e) {
|
||||
return AuthErrorResponse('state invalid');
|
||||
}
|
||||
|
||||
const code = query.get('code');
|
||||
if (!code) {
|
||||
return AuthErrorResponse('code missing');
|
||||
}
|
||||
|
||||
const tokenRequest = {
|
||||
client_id: botClientID,
|
||||
client_secret: botClientSecret,
|
||||
grant_type: 'authorization_code',
|
||||
redirect_uri: apiPublicURI + '/login-callback',
|
||||
scope: 'identify guilds',
|
||||
code,
|
||||
};
|
||||
|
||||
const tokenFetch = await fetch('https://discord.com/api/v8/oauth2/token', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/x-www-form-urlencoded',
|
||||
'user-agent': userAgent,
|
||||
},
|
||||
body: formData(tokenRequest),
|
||||
});
|
||||
|
||||
const tokens = (await tokenFetch.json()) as AuthTokenResponse;
|
||||
|
||||
if (!tokens.access_token) {
|
||||
return AuthErrorResponse('token response invalid');
|
||||
}
|
||||
|
||||
const [sessionID, user, guilds] = await Promise.all([
|
||||
KSUID.random(),
|
||||
getUser(tokens.access_token),
|
||||
getGuilds(tokens.access_token),
|
||||
]);
|
||||
|
||||
if (!user) {
|
||||
return AuthErrorResponse('failed to fetch user');
|
||||
}
|
||||
|
||||
const sessionData: SessionData = {
|
||||
tokens,
|
||||
sessionID: sessionID.string,
|
||||
user,
|
||||
guilds,
|
||||
};
|
||||
|
||||
await Sessions.put(sessionID.string, sessionData, 60 * 60 * 6);
|
||||
|
||||
return Bounce(
|
||||
bounceBaseUrl + '/machinery/new-session?session_id=' + sessionID.string
|
||||
);
|
||||
if (stateValue === null) {
|
||||
return AuthErrorResponse('state missing');
|
||||
}
|
||||
|
||||
try {
|
||||
const state = KSUID.parse(stateValue);
|
||||
const stateExpiry = state.date.getTime() + 1000 * 60 * 5;
|
||||
const currentTime = Date.now();
|
||||
|
||||
if (currentTime > stateExpiry) {
|
||||
return AuthErrorResponse('state expired');
|
||||
}
|
||||
|
||||
const stateSession = await getStateSession<StateSession>(state.string);
|
||||
if (
|
||||
stateSession?.callbackHost &&
|
||||
isAllowedCallbackHost(stateSession.callbackHost)
|
||||
) {
|
||||
bounceBaseUrl = stateSession.callbackHost;
|
||||
}
|
||||
} catch (e) {
|
||||
return AuthErrorResponse('state invalid');
|
||||
}
|
||||
|
||||
const code = query.get('code');
|
||||
if (!code) {
|
||||
return AuthErrorResponse('code missing');
|
||||
}
|
||||
|
||||
const tokenRequest = {
|
||||
client_id: botClientID,
|
||||
client_secret: botClientSecret,
|
||||
grant_type: 'authorization_code',
|
||||
redirect_uri: apiPublicURI + '/login-callback',
|
||||
scope: 'identify guilds',
|
||||
code,
|
||||
};
|
||||
|
||||
const tokenFetch = await fetch('https://discord.com/api/v8/oauth2/token', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'content-type': 'application/x-www-form-urlencoded',
|
||||
'user-agent': userAgent,
|
||||
},
|
||||
body: formData(tokenRequest),
|
||||
});
|
||||
|
||||
const tokens = (await tokenFetch.json()) as AuthTokenResponse;
|
||||
|
||||
if (!tokens.access_token) {
|
||||
return AuthErrorResponse('token response invalid');
|
||||
}
|
||||
|
||||
const [sessionID, user, guilds] = await Promise.all([
|
||||
KSUID.random(),
|
||||
getUser(tokens.access_token),
|
||||
getGuilds(tokens.access_token),
|
||||
]);
|
||||
|
||||
if (!user) {
|
||||
return AuthErrorResponse('failed to fetch user');
|
||||
}
|
||||
|
||||
const sessionData: SessionData = {
|
||||
tokens,
|
||||
sessionID: sessionID.string,
|
||||
user,
|
||||
guilds,
|
||||
};
|
||||
|
||||
await Sessions.put(sessionID.string, sessionData, 60 * 60 * 6);
|
||||
|
||||
return Bounce(
|
||||
bounceBaseUrl + '/machinery/new-session?session_id=' + sessionID.string
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const getUser = async (accessToken: string): Promise<DiscordUser | null> => {
|
||||
const user = await discordFetch<DiscordUser>(
|
||||
'/users/@me',
|
||||
accessToken,
|
||||
AuthType.Bearer
|
||||
);
|
||||
const user = await discordFetch<DiscordUser>(
|
||||
'/users/@me',
|
||||
accessToken,
|
||||
AuthType.Bearer
|
||||
);
|
||||
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { id, username, discriminator, bot, avatar } = user;
|
||||
const { id, username, discriminator, bot, avatar } = user;
|
||||
|
||||
return { id, username, discriminator, bot, avatar };
|
||||
return { id, username, discriminator, bot, avatar };
|
||||
};
|
||||
|
||||
type UserGuildsPayload = {
|
||||
id: string;
|
||||
name: string;
|
||||
icon: string;
|
||||
owner: boolean;
|
||||
permissions: number;
|
||||
features: string[];
|
||||
id: string;
|
||||
name: string;
|
||||
icon: string;
|
||||
owner: boolean;
|
||||
permissions: number;
|
||||
features: string[];
|
||||
}[];
|
||||
|
||||
const getGuilds = async (accessToken: string) => {
|
||||
const guilds = await discordFetch<UserGuildsPayload>(
|
||||
'/users/@me/guilds',
|
||||
accessToken,
|
||||
AuthType.Bearer
|
||||
);
|
||||
const guilds = await discordFetch<UserGuildsPayload>(
|
||||
'/users/@me/guilds',
|
||||
accessToken,
|
||||
AuthType.Bearer
|
||||
);
|
||||
|
||||
if (!guilds) {
|
||||
return [];
|
||||
}
|
||||
if (!guilds) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const guildSlugs = guilds.map<GuildSlug>((guild) => ({
|
||||
id: guild.id,
|
||||
name: guild.name,
|
||||
icon: guild.icon,
|
||||
permissionLevel: parsePermissions(BigInt(guild.permissions), guild.owner),
|
||||
}));
|
||||
const guildSlugs = guilds.map<GuildSlug>((guild) => ({
|
||||
id: guild.id,
|
||||
name: guild.name,
|
||||
icon: guild.icon,
|
||||
permissionLevel: parsePermissions(BigInt(guild.permissions), guild.owner),
|
||||
}));
|
||||
|
||||
return guildSlugs;
|
||||
return guildSlugs;
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue