feat: oauth2 callback redirect (closes #333)

This commit is contained in:
Isaac 2023-03-10 23:46:24 +00:00
parent f55ee02ce5
commit aeb4450a56
No known key found for this signature in database
GPG Key ID: 0DE40AE37BBA5C33
2 changed files with 23 additions and 11 deletions

View File

@ -1,6 +1,6 @@
const fastify = require('fastify')({ trustProxy: process.env.HTTP_TRUST_PROXY === 'true' }); const fastify = require('fastify')({ trustProxy: process.env.HTTP_TRUST_PROXY === 'true' });
const oauth = require('@fastify/oauth2'); const oauth = require('@fastify/oauth2');
const { domain } = require('./lib/http'); const { randomBytes } = require('crypto');
const { short } = require('leeks.js'); const { short } = require('leeks.js');
const { join } = require('path'); const { join } = require('path');
const { files } = require('node-dir'); const { files } = require('node-dir');
@ -17,8 +17,16 @@ module.exports = async client => {
}); });
// oauth2 plugin // oauth2 plugin
fastify.states = new Map();
fastify.register(oauth, { fastify.register(oauth, {
callbackUri: `${process.env.HTTP_EXTERNAL}/auth/callback`, callbackUri: `${process.env.HTTP_EXTERNAL}/auth/callback`,
checkStateFunction: (state, callback) => {
if (fastify.states.has(state)) {
callback();
return;
}
callback(new Error('Invalid state'));
},
credentials: { credentials: {
auth: oauth.DISCORD_CONFIGURATION, auth: oauth.DISCORD_CONFIGURATION,
client: { client: {
@ -26,6 +34,11 @@ module.exports = async client => {
secret: process.env.DISCORD_SECRET, secret: process.env.DISCORD_SECRET,
}, },
}, },
generateStateFunction: req => {
const state = randomBytes(12).toString('hex');
fastify.states.set(state, req.query.r);
return state;
},
name: 'discord', name: 'discord',
scope: ['applications.commands.permissions.update', 'guilds', 'identify'], scope: ['applications.commands.permissions.update', 'guilds', 'identify'],
startRedirectPath: '/auth/login', startRedirectPath: '/auth/login',

View File

@ -3,15 +3,15 @@ const { domain } = require('../../lib/http');
module.exports.get = () => ({ module.exports.get = () => ({
handler: async function (req, res) { // MUST NOT use arrow function syntax handler: async function (req, res) { // MUST NOT use arrow function syntax
const { const {
access_token, access_token: accessToken,
expires_in, expires_in: expiresIn,
} = await this.discord.getAccessTokenFromAuthorizationCodeFlow(req); } = await this.discord.getAccessTokenFromAuthorizationCodeFlow(req);
const user = await (await fetch('https://discordapp.com/api/users/@me', { headers: { 'Authorization': `Bearer ${access_token}` } })).json(); const user = await (await fetch('https://discordapp.com/api/users/@me', { headers: { 'Authorization': `Bearer ${accessToken}` } })).json();
const payload = { const payload = {
access_token, accessToken,
avatar: `https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}.webp`, avatar: `https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}.webp`,
discriminator: user.discriminator, discriminator: user.discriminator,
expiresAt: Date.now() + (expires_in * 1000), expiresAt: Date.now() + (expiresIn * 1000),
id: user.id, id: user.id,
locale: user.locale, locale: user.locale,
username: user.username, username: user.username,
@ -20,15 +20,14 @@ module.exports.get = () => ({
const token = this.jwt.sign({ payload }); const token = this.jwt.sign({ payload });
res res
.setCookie('token', token, { .setCookie('token', token, {
domain: domain, domain,
httpOnly: true, httpOnly: true,
maxAge: 604800, // seconds, not milliseconds maxAge: expiresIn,
path: '/', path: '/',
sameSite: true, sameSite: true,
secure: false, secure: false,
}) })
// .redirect('/settings') .redirect(this.states.get(req.query.state) || '/');
.type('text/html') this.states.delete(req.query.state);
.send('<a href="/settings">/settings</a>'); // temp fix: redirecting causes weird discord<->callback loop, probably caching?
}, },
}); });