189 lines
5.7 KiB
JavaScript
189 lines
5.7 KiB
JavaScript
const { getSetting } = require("./settings");
|
|
|
|
const YOUTUBE_SCOPES = [
|
|
"https://www.googleapis.com/auth/youtube",
|
|
"https://www.googleapis.com/auth/youtube.force-ssl",
|
|
"https://www.googleapis.com/auth/youtube.readonly",
|
|
"https://www.googleapis.com/auth/youtube.channel-memberships.creator"
|
|
];
|
|
|
|
function getDiscordRedirectUri(override) {
|
|
return override || getSetting("discord_redirect_uri", null);
|
|
}
|
|
|
|
function buildDiscordAuthUrl(state, redirectOverride) {
|
|
const clientId = getSetting("discord_client_id");
|
|
const redirectUri = getDiscordRedirectUri(redirectOverride);
|
|
const params = new URLSearchParams({
|
|
client_id: clientId || "",
|
|
redirect_uri: redirectUri || "",
|
|
response_type: "code",
|
|
scope: "identify guilds guilds.members.read",
|
|
state
|
|
});
|
|
return `https://discord.com/api/oauth2/authorize?${params.toString()}`;
|
|
}
|
|
|
|
async function exchangeDiscordCode(code, redirectOverride) {
|
|
const clientId = getSetting("discord_client_id");
|
|
const clientSecret = getSetting("discord_client_secret");
|
|
const redirectUri = getDiscordRedirectUri(redirectOverride);
|
|
const body = new URLSearchParams({
|
|
client_id: clientId || "",
|
|
client_secret: clientSecret || "",
|
|
grant_type: "authorization_code",
|
|
code,
|
|
redirect_uri: redirectUri || ""
|
|
});
|
|
|
|
const response = await fetch("https://discord.com/api/oauth2/token", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
body
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Discord token exchange failed: ${response.status}`);
|
|
}
|
|
|
|
return response.json();
|
|
}
|
|
|
|
async function fetchDiscordUser(accessToken) {
|
|
const response = await fetch("https://discord.com/api/users/@me", {
|
|
headers: { Authorization: `Bearer ${accessToken}` }
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error(`Discord user fetch failed: ${response.status}`);
|
|
}
|
|
return response.json();
|
|
}
|
|
|
|
async function fetchDiscordGuildMember(accessToken, guildId) {
|
|
const response = await fetch(
|
|
`https://discord.com/api/users/@me/guilds/${guildId}/member`,
|
|
{
|
|
headers: { Authorization: `Bearer ${accessToken}` }
|
|
}
|
|
);
|
|
if (!response.ok) {
|
|
return null;
|
|
}
|
|
return response.json();
|
|
}
|
|
|
|
function buildTwitchAuthUrl(state, redirectOverride) {
|
|
const clientId = getSetting("twitch_client_id");
|
|
const redirectUri = redirectOverride || getSetting("twitch_redirect_uri");
|
|
const params = new URLSearchParams({
|
|
client_id: clientId || "",
|
|
redirect_uri: redirectUri || "",
|
|
response_type: "code",
|
|
scope: "user:read:email",
|
|
state
|
|
});
|
|
return `https://id.twitch.tv/oauth2/authorize?${params.toString()}`;
|
|
}
|
|
|
|
async function exchangeTwitchCode(code, redirectOverride) {
|
|
const clientId = getSetting("twitch_client_id");
|
|
const clientSecret = getSetting("twitch_client_secret");
|
|
const redirectUri = redirectOverride || getSetting("twitch_redirect_uri");
|
|
const params = new URLSearchParams({
|
|
client_id: clientId || "",
|
|
client_secret: clientSecret || "",
|
|
code,
|
|
grant_type: "authorization_code",
|
|
redirect_uri: redirectUri || ""
|
|
});
|
|
const response = await fetch(
|
|
`https://id.twitch.tv/oauth2/token?${params.toString()}`,
|
|
{ method: "POST" }
|
|
);
|
|
if (!response.ok) {
|
|
throw new Error(`Twitch token exchange failed: ${response.status}`);
|
|
}
|
|
return response.json();
|
|
}
|
|
|
|
async function fetchTwitchUser(accessToken) {
|
|
const clientId = getSetting("twitch_client_id");
|
|
const response = await fetch("https://api.twitch.tv/helix/users", {
|
|
headers: {
|
|
"Client-Id": clientId || "",
|
|
Authorization: `Bearer ${accessToken}`
|
|
}
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error(`Twitch user fetch failed: ${response.status}`);
|
|
}
|
|
const data = await response.json();
|
|
return data.data?.[0] || null;
|
|
}
|
|
|
|
function buildYouTubeAuthUrl(state, redirectOverride, options = {}) {
|
|
const clientId = getSetting("youtube_client_id");
|
|
const redirectUri = redirectOverride || getSetting("youtube_redirect_uri");
|
|
const scopes = options.scopes || YOUTUBE_SCOPES;
|
|
const params = new URLSearchParams({
|
|
client_id: clientId || "",
|
|
redirect_uri: redirectUri || "",
|
|
response_type: "code",
|
|
scope: scopes.join(" "),
|
|
state,
|
|
access_type: "offline",
|
|
include_granted_scopes: "true"
|
|
});
|
|
if (options.prompt) {
|
|
params.set("prompt", options.prompt);
|
|
}
|
|
return `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`;
|
|
}
|
|
|
|
async function exchangeYouTubeCode(code, redirectOverride) {
|
|
const clientId = getSetting("youtube_client_id");
|
|
const clientSecret = getSetting("youtube_client_secret");
|
|
const redirectUri = redirectOverride || getSetting("youtube_redirect_uri");
|
|
const body = new URLSearchParams({
|
|
client_id: clientId || "",
|
|
client_secret: clientSecret || "",
|
|
grant_type: "authorization_code",
|
|
code,
|
|
redirect_uri: redirectUri || ""
|
|
});
|
|
const response = await fetch("https://oauth2.googleapis.com/token", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
body
|
|
});
|
|
if (!response.ok) {
|
|
throw new Error(`YouTube token exchange failed: ${response.status}`);
|
|
}
|
|
return response.json();
|
|
}
|
|
|
|
async function fetchYouTubeChannel(accessToken) {
|
|
const response = await fetch(
|
|
"https://www.googleapis.com/youtube/v3/channels?part=snippet&mine=true",
|
|
{ headers: { Authorization: `Bearer ${accessToken}` } }
|
|
);
|
|
if (!response.ok) {
|
|
throw new Error(`YouTube channel fetch failed: ${response.status}`);
|
|
}
|
|
const data = await response.json();
|
|
return data.items?.[0] || null;
|
|
}
|
|
|
|
module.exports = {
|
|
buildDiscordAuthUrl,
|
|
exchangeDiscordCode,
|
|
fetchDiscordUser,
|
|
fetchDiscordGuildMember,
|
|
buildTwitchAuthUrl,
|
|
exchangeTwitchCode,
|
|
fetchTwitchUser,
|
|
buildYouTubeAuthUrl,
|
|
exchangeYouTubeCode,
|
|
fetchYouTubeChannel
|
|
};
|