2023-06-22 19:36:52 +05:00
|
|
|
const router = require("express").Router();
|
|
|
|
const RL = require("express-rate-limit");
|
|
|
|
const safeStorage = require("assistants-safe-storage");
|
2023-06-19 12:35:11 +05:00
|
|
|
|
2023-06-22 19:36:52 +05:00
|
|
|
const DiscordOauth2 = require("discord-oauth2");
|
|
|
|
const oauth = new DiscordOauth2();
|
2023-06-19 12:35:11 +05:00
|
|
|
|
|
|
|
module.exports = (app, config, themeConfig) => {
|
2023-06-22 19:36:52 +05:00
|
|
|
const storage = new safeStorage(config.bot.config.token);
|
|
|
|
const scopes = config.guildAfterAuthorization?.use ? ["identify", "guilds", "guilds.join"] : ["identify", "guilds"];
|
|
|
|
|
|
|
|
const RateLimits = config.rateLimits || {};
|
|
|
|
const RateFunctions = {};
|
|
|
|
|
|
|
|
const NoRL = (req, res, next) => next();
|
|
|
|
|
|
|
|
if (RateLimits.discordOAuth2) {
|
|
|
|
RateFunctions.discordOAuth2 = RL.rateLimit({
|
|
|
|
windowMs: RateLimits.discordOAuth2.windowMs,
|
|
|
|
max: RateLimits.discordOAuth2.max,
|
|
|
|
message: RateLimits.discordOAuth2.message,
|
|
|
|
store: RateLimits.discordOAuth2.store || new RL.MemoryStore(),
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
router.get("/", (req, res) => {
|
|
|
|
const clientId = req.client.id;
|
|
|
|
const redirectUri = req.redirectUri;
|
|
|
|
|
|
|
|
let newPage = "/";
|
|
|
|
if (themeConfig.landingPage?.enabled) newPage = "/dash";
|
|
|
|
|
|
|
|
req.session.r = req.query.r || newPage;
|
|
|
|
|
|
|
|
const authorizeUrl = `https://discord.com/api/oauth2/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code&scope=${scopes.join("%20")}`;
|
|
|
|
|
|
|
|
res.redirect(authorizeUrl);
|
|
|
|
});
|
|
|
|
|
|
|
|
router.get("/status", async (req, res) => {
|
|
|
|
res.send(req.session?.discordAuthStatus);
|
|
|
|
});
|
|
|
|
|
|
|
|
router.get("/callback", RateFunctions.discordOAuth2 ? RateFunctions.discordOAuth2 : NoRL, async (req, res) => {
|
|
|
|
req.session.discordAuthStatus = {
|
|
|
|
loading: true,
|
|
|
|
success: null,
|
|
|
|
state: {
|
|
|
|
error: null,
|
|
|
|
data: null,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const clientId = req.client.id;
|
|
|
|
const clientSecret = req.client.secret;
|
|
|
|
const redirectUri = req.redirectUri;
|
|
|
|
|
|
|
|
const accessCode = req.query.code;
|
|
|
|
if (!accessCode) return res.redirect("/?error=NoAccessCodeReturnedFromDiscord");
|
|
|
|
|
|
|
|
res.redirect("/loading");
|
|
|
|
|
|
|
|
let OAuth2Response;
|
|
|
|
let OAuth2UserResponse;
|
|
|
|
let OAuth2GuildsResponse;
|
|
|
|
|
|
|
|
try {
|
|
|
|
req.session.discordAuthStatus = {
|
|
|
|
loading: true,
|
|
|
|
success: null,
|
|
|
|
state: {
|
|
|
|
error: null,
|
|
|
|
data: "Requesting token...",
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
req.session.save(function () {});
|
|
|
|
|
|
|
|
OAuth2Response = await oauth.tokenRequest({
|
|
|
|
clientId,
|
|
|
|
clientSecret,
|
|
|
|
|
|
|
|
code: accessCode,
|
|
|
|
scope: scopes.join(" "),
|
|
|
|
grantType: "authorization_code",
|
|
|
|
|
|
|
|
redirectUri,
|
|
|
|
});
|
|
|
|
} catch (err) {
|
|
|
|
console.log("Discord.js Route - OAuth2Response (line 88)\n" + err);
|
|
|
|
|
|
|
|
req.session.discordAuthStatus = {
|
|
|
|
loading: false,
|
|
|
|
success: false,
|
|
|
|
state: {
|
|
|
|
error: err,
|
|
|
|
data: null,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
req.session.save(function () {});
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Get User from Discord OAuth2 API using gained access_token and update its values with tag and avatarURL
|
|
|
|
*/
|
|
|
|
try {
|
|
|
|
req.session.discordAuthStatus = {
|
|
|
|
loading: true,
|
|
|
|
success: null,
|
|
|
|
state: {
|
|
|
|
error: null,
|
|
|
|
data: "Getting User...",
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
req.session.save(function () {});
|
|
|
|
|
|
|
|
OAuth2UserResponse = await oauth.getUser(OAuth2Response.access_token);
|
|
|
|
} catch (err) {
|
2023-06-26 17:41:52 +05:00
|
|
|
console.log("Discord.js Route - OAuth2UserResponse (line 123)\n" + err);
|
2023-06-22 19:36:52 +05:00
|
|
|
|
|
|
|
req.session.discordAuthStatus = {
|
|
|
|
loading: false,
|
|
|
|
success: false,
|
|
|
|
state: {
|
|
|
|
error: err,
|
|
|
|
data: null,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
req.session.save(function () {});
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
OAuth2UserResponse.tag = `${OAuth2UserResponse.username}#${OAuth2UserResponse.discriminator}`;
|
|
|
|
OAuth2UserResponse.avatarURL = OAuth2UserResponse.avatar ? `https://cdn.discordapp.com/avatars/${OAuth2UserResponse.id}/${OAuth2UserResponse.avatar}.png?size=1024` : null;
|
|
|
|
|
|
|
|
/*
|
|
|
|
Save user token in Assistants Secure Storage
|
|
|
|
*/
|
|
|
|
try {
|
|
|
|
storage.SaveUser(OAuth2UserResponse.id, OAuth2Response.access_token);
|
|
|
|
} catch (err) {
|
|
|
|
console.log("Discord.js Route - Assistants Secure Storage (line 147)\n" + err);
|
|
|
|
|
|
|
|
req.session.discordAuthStatus = {
|
|
|
|
loading: false,
|
|
|
|
success: false,
|
|
|
|
state: {
|
|
|
|
error: err,
|
|
|
|
data: null,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
req.session.save(function () {});
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Save user in session
|
|
|
|
*/
|
|
|
|
req.session.user = OAuth2UserResponse;
|
|
|
|
req.session.loggedInLastTime = true;
|
|
|
|
|
|
|
|
/*
|
|
|
|
Register user to DBD Stats and emit userLoggedIn event
|
|
|
|
*/
|
|
|
|
try {
|
|
|
|
req.DBDEvents.emit("userLoggedIn", OAuth2UserResponse);
|
|
|
|
} catch (err) {
|
|
|
|
console.log("Discord.js Route - DBDStats register and DBDEvent emit userLoggedIn (line 173)\n" + err);
|
|
|
|
|
|
|
|
req.session.discordAuthStatus = {
|
|
|
|
loading: false,
|
|
|
|
success: false,
|
|
|
|
state: {
|
|
|
|
error: err,
|
|
|
|
data: null,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
req.session.save(function () {});
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Gain and update session with user guilds
|
|
|
|
*/
|
|
|
|
try {
|
|
|
|
req.session.discordAuthStatus = {
|
|
|
|
loading: true,
|
|
|
|
success: null,
|
|
|
|
state: {
|
|
|
|
error: null,
|
|
|
|
data: "Getting List of User Guilds...",
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
req.session.save(function () {});
|
|
|
|
|
|
|
|
OAuth2GuildsResponse = await oauth.getUserGuilds(OAuth2Response.access_token);
|
|
|
|
} catch (err) {
|
2023-06-26 17:41:52 +05:00
|
|
|
req.config.reportError("Discord.js Route - OAuth2GuildsResponse (line 207)\n" + err);
|
2023-06-22 19:36:52 +05:00
|
|
|
|
|
|
|
req.session.discordAuthStatus = {
|
|
|
|
loading: false,
|
|
|
|
success: false,
|
|
|
|
state: {
|
|
|
|
error: err,
|
|
|
|
data: null,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
req.session.save(function () {});
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
req.session.guilds = OAuth2GuildsResponse || [];
|
|
|
|
|
|
|
|
/*
|
|
|
|
Loop and fetch each guild into bots cache
|
|
|
|
*/
|
|
|
|
if (!req.config.disableResolvingGuildCache) {
|
|
|
|
try {
|
|
|
|
req.session.discordAuthStatus = {
|
|
|
|
loading: true,
|
|
|
|
success: null,
|
|
|
|
state: {
|
|
|
|
error: null,
|
|
|
|
data: "Resolving guilds cache...",
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
req.session.save(function () {});
|
|
|
|
|
|
|
|
for (const g of OAuth2GuildsResponse) {
|
|
|
|
try {
|
|
|
|
await req.bot.guilds.fetch(g.id);
|
|
|
|
} catch (e) { /* ... */ }
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
console.log("Discord.js Route - OAuth2GuildsResponse Whole Loop (line 244)" + err);
|
|
|
|
|
|
|
|
req.session.discordAuthStatus = {
|
|
|
|
loading: false,
|
|
|
|
success: false,
|
|
|
|
state: {
|
|
|
|
error: err,
|
|
|
|
data: null,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
req.session.save(function () {});
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
If joining specific guild after authorization is enabled, do it
|
|
|
|
*/
|
|
|
|
|
|
|
|
if (req.guildAfterAuthorization.use == true) {
|
|
|
|
req.session.discordAuthStatus = {
|
|
|
|
loading: true,
|
|
|
|
success: null,
|
|
|
|
state: {
|
|
|
|
error: null,
|
|
|
|
data: "Authorizing user with guild...",
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
req.session.save(function () {});
|
|
|
|
|
|
|
|
try {
|
|
|
|
await oauth.addMember({
|
|
|
|
accessToken: OAuth2Response.access_token,
|
|
|
|
botToken: req.botToken,
|
|
|
|
guildId: req.guildAfterAuthorization.guildId,
|
|
|
|
userId: OAuth2UserResponse.id,
|
|
|
|
|
|
|
|
...(req.guildAfterAuthorization.options || {}),
|
|
|
|
/*
|
|
|
|
options?: {
|
|
|
|
nickname?: string,
|
|
|
|
roles?: [string],
|
|
|
|
mute?: boolean,
|
|
|
|
deaf?: boolean,
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
});
|
|
|
|
} catch (err) {
|
2023-06-26 17:41:52 +05:00
|
|
|
req.config.reportError("Discord.js Route - guildAfterAuthorization (line 297)" + err);
|
2023-06-22 19:36:52 +05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
req.session.discordAuthStatus = {
|
|
|
|
loading: false,
|
|
|
|
success: true,
|
|
|
|
state: {
|
|
|
|
error: null,
|
|
|
|
data: null,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
req.session.save(function () {});
|
|
|
|
|
|
|
|
return;
|
|
|
|
});
|
|
|
|
|
|
|
|
router.get("/logout", (req, res) => {
|
|
|
|
const r = req.query.r || "/";
|
|
|
|
req.session.destroy();
|
|
|
|
res.redirect(r);
|
|
|
|
});
|
|
|
|
|
|
|
|
router.get("/guilds/reload", async (req, res) => {
|
|
|
|
if (!req.session.user) return res.redirect("/discord");
|
|
|
|
|
|
|
|
/*
|
|
|
|
Fetch user token
|
|
|
|
*/
|
|
|
|
const access_token = storage.GetUser(req.session.user.id);
|
|
|
|
|
|
|
|
if (!access_token)
|
|
|
|
return res.send({
|
|
|
|
error: true,
|
|
|
|
message: "You don't have any access_token saved.",
|
|
|
|
login_again_text: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
/*
|
|
|
|
Gain and update session with user guilds
|
|
|
|
*/
|
|
|
|
let OAuth2GuildsResponse;
|
|
|
|
|
|
|
|
try {
|
|
|
|
OAuth2GuildsResponse = await oauth.getUserGuilds(access_token);
|
|
|
|
} catch (err) {
|
2023-06-26 17:41:52 +05:00
|
|
|
req.config.reportError("Discord.js Route - OAuth2GuildsResponse for ReloadGuilds (line 344)" + err);
|
2023-06-22 19:36:52 +05:00
|
|
|
|
|
|
|
return res.send({
|
|
|
|
error: true,
|
|
|
|
message: "An error occured. Access_token is wrong or you're being rate limited.",
|
|
|
|
login_again_text: true,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
req.session.guilds = OAuth2GuildsResponse || [];
|
|
|
|
|
|
|
|
/*
|
|
|
|
Loop and fetch each guild into bots cache
|
|
|
|
*/
|
|
|
|
try {
|
|
|
|
const Promises = [];
|
|
|
|
|
|
|
|
for (const g of OAuth2GuildsResponse) {
|
|
|
|
Promises.push(
|
|
|
|
// eslint-disable-next-line no-unused-vars, no-async-promise-executor
|
|
|
|
new Promise(async (resolve, reject) => {
|
|
|
|
try {
|
|
|
|
await req.bot.guilds.fetch(g.id);
|
|
|
|
} catch (e) { /* ... */ }
|
|
|
|
|
|
|
|
resolve(1);
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
try {
|
|
|
|
await Promises.all(Promises);
|
|
|
|
} catch (e) { /* ... */ }
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
console.log("Discord.js Route - OAuth2GuildsResponse Whole Loop for ReloadGuilds (line 375)" + err);
|
|
|
|
|
|
|
|
return res.send({
|
|
|
|
error: true,
|
|
|
|
message: "An error occured. Access_token is wrong or you're being rate limited.",
|
|
|
|
login_again_text: true,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Success
|
|
|
|
*/
|
|
|
|
return res.send({
|
|
|
|
error: false,
|
|
|
|
message: null,
|
|
|
|
login_again_text: false,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
return router;
|
|
|
|
};
|