-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d8f0fb2
commit b64d623
Showing
10 changed files
with
592 additions
and
394 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,53 +1,15 @@ | ||
import BaseMiddleware from "../../Server/BaseMiddleware"; | ||
import { Response } from "express"; | ||
import { isNull } from "@riniya.ts/types"; | ||
import { CustomRequest, CustomResponse } from '../index' | ||
import DiscordAccount from '@riniya.ts/database/Social/DiscordAccount' | ||
import Discord from '../utils/Discord' | ||
import Riniya from '@riniya.ts' | ||
import { MessageEmbed } from 'discord.js' | ||
import moment from 'moment/moment' | ||
|
||
export default class CAuthMiddleware extends BaseMiddleware { | ||
|
||
public constructor() { | ||
super("ClientAuthentication", "Authentication middleware for the website") | ||
} | ||
|
||
public async handle(request: CustomRequest, response: CustomResponse, next) { | ||
if (isNull(request.session.accountId)) { | ||
return response.redirect("https://www.riniya.uk/user/login") | ||
} else { | ||
const account = await DiscordAccount.findOne({ _id: request.session.accountId }) | ||
if (isNull(account)) { | ||
return response.redirect("https://www.riniya.uk") | ||
} | ||
const tokens = await Discord.getAccessToken(account.userId, account.tokens) | ||
if (isNull(tokens.access_token)) { | ||
// Deleting the account because the refresh token is invalidated. | ||
await DiscordAccount.deleteOne({ _id: account._id }) | ||
} | ||
|
||
await Riniya.instance.users.fetch(account.userId).then(user => { | ||
user.send({ | ||
embeds: [ | ||
new MessageEmbed() | ||
.setTitle("Dashboard Login detected.") | ||
.setColor("RED") | ||
.setDescription(`New login at ${moment(Date.now())}. If this action has been made on your behalf. Please terminate this session.`) | ||
], | ||
components: [ | ||
{ | ||
type: 1, | ||
components: [ | ||
Riniya.instance.buttonManager.createLinkButton("Terminate", "https://api.riniya.uk/api/security/invalidate/" + account._id) | ||
] | ||
} | ||
] | ||
}) | ||
}) | ||
|
||
next() | ||
} | ||
if (request.isAuthenticated()) { | ||
next() | ||
} else { | ||
return response.redirect("https://www.riniya.uk/user/login") | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import { Express, NextFunction } from 'express' | ||
import DiscordPassport from "passport-discord"; | ||
import Refresh from "passport-oauth2-refresh"; | ||
import passport from "passport"; | ||
import DiscordAccount ,{ DiscordAccount as DAccount } from '@riniya.ts/database/Social/DiscordAccount' | ||
import { isNull } from '@riniya.ts/types' | ||
import Discord from '../utils/Discord' | ||
|
||
const scopes = ['identify', 'email', 'guilds', 'guilds.join'] | ||
|
||
export interface User { | ||
internal: string; | ||
userId: string; | ||
username: string; | ||
email: string; | ||
} | ||
|
||
export interface IUser { | ||
user: User; | ||
avatar: string; | ||
guilds: DiscordPassport.GuildInfo[] | ||
} | ||
|
||
export default class Passport { | ||
public init(app: Express) { | ||
app.use(passport.initialize()) | ||
app.use(passport.authenticate('session')) | ||
|
||
const discordStrategy = new DiscordPassport.Strategy({ | ||
clientID: process.env["DISCORD_CLIENT_ID"], | ||
clientSecret: process.env["DISCORD_CLIENT_SECRET"], | ||
callbackURL: process.env["DISCORD_REDIRECT_URI"], | ||
scope: scopes | ||
},async function(accessToken, refreshToken, profile, cb) { | ||
const account = await DiscordAccount?.exists({ userId: profile.id }) | ||
if (isNull(account)) { | ||
new DiscordAccount({ | ||
userId: profile.id, | ||
username: profile.username, | ||
email: profile.email, | ||
tokens: { | ||
expires_at: 0, | ||
expires_in: 0, | ||
refresh_token: refreshToken, | ||
access_token: accessToken | ||
} | ||
}).save().then(r => cb(null, { | ||
user: { | ||
internal: r._id, | ||
userId: profile.id, | ||
username: profile.username, | ||
email: profile.email | ||
}, | ||
avatar: profile.avatar, | ||
guilds: profile.guilds | ||
})).catch(err => cb(err)) | ||
} else { | ||
Refresh.requestNewAccessToken('discord', refreshToken, async function(err, accessToken, refreshToken) { | ||
if (err) { | ||
throw err | ||
} | ||
|
||
await DiscordAccount.updateOne({ userId: profile.id }, { | ||
$set: { | ||
userId: profile.id, | ||
username: profile.username, | ||
email: profile.email, | ||
tokens: { | ||
expires_at: 0, | ||
expires_in: 0, | ||
refresh_token: refreshToken, | ||
access_token: accessToken | ||
} | ||
} | ||
}).then(r => cb(null, { | ||
user: { | ||
internal: r.upsertedId, | ||
userId: profile.id, | ||
username: profile.username, | ||
email: profile.email | ||
}, | ||
avatar: profile.avatar, | ||
guilds: profile.guilds | ||
})) | ||
}); | ||
} | ||
}) | ||
|
||
passport.use(discordStrategy) | ||
Refresh.use(discordStrategy) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,108 +1,15 @@ | ||
import AbstractRoutes from '../../Server/AbstractRoutes' | ||
import Discord from '../utils/Discord' | ||
import { v4 } from 'uuid' | ||
import { isNull } from '@riniya.ts/types' | ||
import DiscordAccount from '@riniya.ts/database/Social/DiscordAccount' | ||
import { CustomRequest, CustomResponse } from '../index' | ||
import { JSONCookie } from 'cookie-parser' | ||
import passport from 'passport' | ||
|
||
export default class Auth extends AbstractRoutes { | ||
async register () { | ||
this.router.get('/user/login', async function (req: CustomRequest, res) { | ||
|
||
let clientState = v4() | ||
|
||
const oauthURL = await Discord.getOAuthUrl({ | ||
userUUID: clientState | ||
}) | ||
|
||
res.cookie('clientState', clientState, { | ||
maxAge: 1000 * 60 * 5, | ||
signed: true | ||
}); | ||
res.redirect(oauthURL.url.toString()) | ||
}) | ||
|
||
this.router.get('/user/callback', async function (req: CustomRequest, res: CustomResponse) { | ||
req.session.destroy(err => {}) | ||
const code = String(req.query.code); | ||
const discordState = String(req.query.state); | ||
// make sure the state parameter exists | ||
const clientState = req.signedCookies['clientState']; | ||
|
||
if (clientState !== discordState) { | ||
console.error('State verification failed.'); | ||
return res.status(403).json({ | ||
status: false, | ||
error: "INVALID_CLIENT_STATE", | ||
message: 'The client state value is unexpected.' | ||
}) | ||
} | ||
await Discord.getOAuthTokens(code).then(async result => { | ||
if (isNull(result)) { | ||
return res.status(403).json({ | ||
status: false, | ||
error: "INVALID_STRUCT", | ||
message: 'The request structure is invalid.' | ||
}) | ||
} | ||
|
||
await Discord.getUserData(result).then(async user => { | ||
if (isNull(user)) { | ||
return res.status(403).json({ | ||
status: false, | ||
error: "INVALID_STRUCT", | ||
message: 'Cannot fetch the user data.' | ||
}) | ||
} | ||
const userId = user.user.id; | ||
|
||
const account = await DiscordAccount.findOne({ userId: userId }, { tokens: -1, __v: -1}) | ||
|
||
if (isNull(account._id)) { | ||
await new DiscordAccount({ | ||
userId: userId, | ||
email: user.user.email, | ||
username: user.user.username, | ||
tokens: { | ||
access_token: result.access_token, | ||
refresh_token: result.refresh_token, | ||
expires_in: result.expires_in, | ||
expires_at: Date.now() + result.expires_in * 1000 | ||
}, | ||
uuid: discordState | ||
}).save().then(r => { | ||
req.session.account = r | ||
req.session.accountId = r._id | ||
req.session.save() | ||
}) | ||
} else { | ||
await DiscordAccount.updateOne({ | ||
userId: userId | ||
}, { | ||
$set: { | ||
userId: userId, | ||
email: user.user.email, | ||
username: user.user.username, | ||
tokens: { | ||
access_token: result.access_token, | ||
refresh_token: result.refresh_token, | ||
expires_in: result.expires_in, | ||
expires_at: Date.now() + result.expires_in * 1000 | ||
}, | ||
uuid: discordState | ||
} | ||
}) | ||
|
||
req.session.account = account | ||
req.session.accountId = account._id | ||
req.session.save() | ||
} | ||
|
||
res.status(200).redirect("https://www.riniya.uk/dashboard") | ||
}) | ||
this.router.get('/user/login', passport.authenticate("discord")); | ||
this.router.get('/user/callback', passport.authenticate('discord', { | ||
failureRedirect: '/', | ||
}), function(req, res) { | ||
res.render('dashboard', { | ||
user: req.user | ||
}) | ||
}) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
section.ui.container.fluid | ||
a.ui.red.label=user.username | ||
a.ui.yellow.label=user.email | ||
a.ui.red.label=user.user.username | ||
a.ui.yellow.label=user.user.email | ||
a.ui.red.label Welcome! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.