2023-06-19 12:35:11 +05:00
|
|
|
const router = require("express").Router()
|
|
|
|
const fetch = require("node-fetch")
|
|
|
|
|
|
|
|
const DiscordOauth2 = require("discord-oauth2")
|
|
|
|
const oauth = new DiscordOauth2()
|
|
|
|
|
|
|
|
module.exports = (app, config, themeConfig) => {
|
|
|
|
const scopes = config.guildAfterAuthorization?.use
|
|
|
|
? ["identify", "guilds", "guilds.join"]
|
|
|
|
: ["identify", "guilds"]
|
|
|
|
const RL = require("express-rate-limit")
|
|
|
|
const RateLimits = config.rateLimits || {}
|
|
|
|
let 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
|
|
|
|
|
|
|
|
/*
|
|
|
|
Get Discord OAuth2 API Response with Access Code gained
|
|
|
|
*/
|
|
|
|
try {
|
|
|
|
req.session.discordAuthStatus = {
|
|
|
|
loading: true,
|
|
|
|
success: null,
|
|
|
|
state: {
|
|
|
|
error: null,
|
|
|
|
data: "Requesting token...",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
req.session.save(function (err) {})
|
|
|
|
OAuth2Response = await oauth.tokenRequest({
|
|
|
|
clientId,
|
|
|
|
clientSecret,
|
|
|
|
|
|
|
|
code: accessCode,
|
|
|
|
scope: scopes.join(" "),
|
|
|
|
grantType: "authorization_code",
|
|
|
|
|
|
|
|
redirectUri,
|
|
|
|
})
|
|
|
|
} catch (err) {
|
|
|
|
req.config.reportError(
|
|
|
|
"Discord.js Route - OAuth2Response (line 86)",
|
|
|
|
err
|
|
|
|
)
|
|
|
|
req.session.discordAuthStatus = {
|
|
|
|
loading: false,
|
|
|
|
success: false,
|
|
|
|
state: {
|
|
|
|
error: err,
|
|
|
|
data: null,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
req.session.save(function (err) {})
|
|
|
|
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 (err) {})
|
|
|
|
OAuth2UserResponse = await oauth.getUser(
|
|
|
|
OAuth2Response.access_token
|
|
|
|
)
|
|
|
|
} catch (err) {
|
|
|
|
req.config.reportError(
|
|
|
|
"Discord.js Route - OAuth2UserResponse (line 118)",
|
|
|
|
err
|
|
|
|
)
|
|
|
|
req.session.discordAuthStatus = {
|
|
|
|
loading: false,
|
|
|
|
success: false,
|
|
|
|
state: {
|
|
|
|
error: err,
|
|
|
|
data: null,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
req.session.save(function (err) {})
|
|
|
|
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 {
|
|
|
|
req.AssistantsSecureStorage.SaveUser(
|
|
|
|
OAuth2UserResponse.id,
|
|
|
|
OAuth2Response.access_token
|
|
|
|
)
|
|
|
|
} catch (err) {
|
|
|
|
req.config.reportError(
|
|
|
|
"Discord.js Route - Assistants Secure Storage (line 141)",
|
|
|
|
err
|
|
|
|
)
|
|
|
|
req.session.discordAuthStatus = {
|
|
|
|
loading: false,
|
|
|
|
success: false,
|
|
|
|
state: {
|
|
|
|
error: err,
|
|
|
|
data: null,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
req.session.save(function (err) {})
|
|
|
|
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) {
|
2023-06-19 14:10:17 +05:00
|
|
|
req.config.reportError("Discord.js Route - Register and DBDEvents emit userLoggedIn (line 170)", err)
|
2023-06-19 12:35:11 +05:00
|
|
|
req.session.discordAuthStatus = {
|
|
|
|
loading: false,
|
|
|
|
success: false,
|
|
|
|
state: {
|
|
|
|
error: err,
|
|
|
|
data: null,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
req.session.save(function (err) {})
|
|
|
|
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 (err) {})
|
|
|
|
OAuth2GuildsResponse = await oauth.getUserGuilds(
|
|
|
|
OAuth2Response.access_token
|
|
|
|
)
|
|
|
|
} catch (err) {
|
|
|
|
req.config.reportError(
|
|
|
|
"Discord.js Route - OAuth2GuildsResponse (line 201)",
|
|
|
|
err
|
|
|
|
)
|
|
|
|
req.session.discordAuthStatus = {
|
|
|
|
loading: false,
|
|
|
|
success: false,
|
|
|
|
state: {
|
|
|
|
error: err,
|
|
|
|
data: null,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
req.session.save(function (err) {})
|
|
|
|
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 (err) {})
|
|
|
|
for (let g of OAuth2GuildsResponse) {
|
|
|
|
try {
|
|
|
|
await req.bot.guilds.fetch(g.id)
|
|
|
|
} catch (err) {}
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
req.config.reportError(
|
|
|
|
"Discord.js Route - OAuth2GuildsResponse Whole Loop (line 239)",
|
|
|
|
err
|
|
|
|
)
|
|
|
|
req.session.discordAuthStatus = {
|
|
|
|
loading: false,
|
|
|
|
success: false,
|
|
|
|
state: {
|
|
|
|
error: err,
|
|
|
|
data: null,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
req.session.save(function (err) {})
|
|
|
|
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 (err) {})
|
|
|
|
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) {
|
|
|
|
req.config.reportError(
|
|
|
|
"Discord.js Route - guildAfterAuthorization (line 287)",
|
|
|
|
err
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
req.session.discordAuthStatus = {
|
|
|
|
loading: false,
|
|
|
|
success: true,
|
|
|
|
state: {
|
|
|
|
error: null,
|
|
|
|
data: null,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
req.session.save(function (err) {})
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
router.get("/logout", (req, res) => {
|
|
|
|
let 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 = req.AssistantsSecureStorage.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) {
|
|
|
|
req.config.reportError(
|
|
|
|
"Discord.js Route - OAuth2GuildsResponse for ReloadGuilds (line 335)",
|
|
|
|
err
|
|
|
|
)
|
|
|
|
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 (let g of OAuth2GuildsResponse) {
|
|
|
|
Promises.push(
|
|
|
|
new Promise(async (resolve, reject) => {
|
|
|
|
try {
|
|
|
|
await req.bot.guilds.fetch(g.id)
|
|
|
|
} catch (err) {}
|
|
|
|
resolve(1)
|
|
|
|
})
|
|
|
|
)
|
|
|
|
try {
|
|
|
|
await Promises.all(Promises)
|
|
|
|
} catch (err) {}
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
req.config.reportError(
|
|
|
|
"Discord.js Route - OAuth2GuildsResponse Whole Loop for ReloadGuilds (line 363)",
|
|
|
|
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
|
|
|
|
}
|