2022-05-06 02:01:19 +03:00
|
|
|
const fastify = require('fastify')();
|
2022-05-06 23:17:53 +03:00
|
|
|
const oauth = require('@fastify/oauth2');
|
2022-05-07 20:28:38 +03:00
|
|
|
// const { randomBytes } = require('crypto');
|
2022-05-06 02:12:38 +03:00
|
|
|
const { short } = require('leeks.js');
|
2022-05-06 02:01:19 +03:00
|
|
|
const { join } = require('path');
|
2022-07-18 15:34:29 +03:00
|
|
|
const { files } = require('node-dir');
|
2022-05-06 02:01:19 +03:00
|
|
|
|
2022-09-06 22:30:28 +03:00
|
|
|
process.env.PUBLIC_HOST = process.env.HTTP_EXTERNAL;
|
|
|
|
|
|
|
|
async function build(client) {
|
|
|
|
// await fastify.register(require('@fastify/express'));
|
|
|
|
|
2022-09-04 21:55:32 +03:00
|
|
|
// cors plugin
|
2022-07-16 01:19:42 +03:00
|
|
|
fastify.register(require('@fastify/cors'), {
|
|
|
|
credentials: true,
|
|
|
|
methods: ['DELETE', 'GET', 'PATCH', 'PUT', 'POST'],
|
|
|
|
origin: true,
|
|
|
|
});
|
|
|
|
|
2022-05-06 23:17:53 +03:00
|
|
|
// oauth2 plugin
|
|
|
|
fastify.register(oauth, {
|
|
|
|
callbackUri: `${process.env.HTTP_EXTERNAL}/auth/callback`,
|
|
|
|
credentials: {
|
|
|
|
auth: oauth.DISCORD_CONFIGURATION,
|
|
|
|
client: {
|
|
|
|
id: client.user.id,
|
|
|
|
secret: process.env.DISCORD_SECRET,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
name: 'discord',
|
|
|
|
scope: ['identify'],
|
|
|
|
startRedirectPath: '/auth/login',
|
|
|
|
});
|
|
|
|
|
|
|
|
// cookies plugin
|
|
|
|
fastify.register(require('@fastify/cookie'));
|
|
|
|
|
|
|
|
// jwt plugin
|
|
|
|
fastify.register(require('@fastify/jwt'), {
|
|
|
|
cookie: {
|
|
|
|
cookieName: 'token',
|
|
|
|
signed: false,
|
|
|
|
},
|
2022-05-07 20:28:38 +03:00
|
|
|
// secret: randomBytes(16).toString('hex'),
|
2022-07-16 01:19:42 +03:00
|
|
|
secret: process.env.ENCRYPTION_KEY,
|
2022-05-06 23:17:53 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
// auth
|
|
|
|
fastify.decorate('authenticate', async (req, res) => {
|
|
|
|
try {
|
|
|
|
const data = await req.jwtVerify();
|
2022-07-16 01:19:42 +03:00
|
|
|
// if (data.payload.expiresAt < Date.now()) res.redirect('/auth/login');
|
|
|
|
if (data.payload.expiresAt < Date.now()) {
|
|
|
|
return res.code(401).send({
|
|
|
|
error: 'Unauthorised',
|
|
|
|
message: 'You are not authenticated.',
|
|
|
|
statusCode: 401,
|
|
|
|
|
|
|
|
});
|
|
|
|
}
|
2022-05-06 23:17:53 +03:00
|
|
|
} catch (err) {
|
|
|
|
res.send(err);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2022-05-07 20:28:38 +03:00
|
|
|
fastify.decorate('isAdmin', async (req, res) => {
|
|
|
|
try {
|
|
|
|
const userId = req.user.payload.id;
|
|
|
|
const guildId = req.params.guild;
|
|
|
|
const guild = client.guilds.cache.get(guildId);
|
2022-07-16 01:19:42 +03:00
|
|
|
if (!guild) {
|
|
|
|
return res.code(404).send({
|
|
|
|
error: 'Not Found',
|
|
|
|
message: 'The requested resource could not be found.',
|
|
|
|
statusCode: 404,
|
2022-05-07 20:28:38 +03:00
|
|
|
|
2022-07-16 01:19:42 +03:00
|
|
|
});
|
|
|
|
}
|
|
|
|
const guildMember = await guild.members.fetch(userId);
|
2022-07-18 23:53:17 +03:00
|
|
|
const isAdmin = guildMember?.permissions.has('MANAGE_GUILD') || client.supers.includes(userId);
|
|
|
|
if (!isAdmin) {
|
2022-07-16 01:19:42 +03:00
|
|
|
return res.code(403).send({
|
|
|
|
error: 'Forbidden',
|
|
|
|
message: 'You are not permitted for this action.',
|
|
|
|
statusCode: 403,
|
2022-05-07 20:28:38 +03:00
|
|
|
|
|
|
|
});
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
res.send(err);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2022-07-18 23:53:17 +03:00
|
|
|
// body processing
|
|
|
|
fastify.addHook('preHandler', (req, res, done) => {
|
|
|
|
if (req.body && typeof req.body === 'object') {
|
|
|
|
for (const prop in req.body) {
|
|
|
|
if (typeof req.body[prop] === 'string') {
|
|
|
|
req.body[prop] = req.body[prop].trim();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
done();
|
|
|
|
});
|
|
|
|
|
2022-05-06 23:17:53 +03:00
|
|
|
// logging
|
2022-05-06 02:12:38 +03:00
|
|
|
fastify.addHook('onResponse', (req, res, done) => {
|
|
|
|
done();
|
|
|
|
const status = (res.statusCode >= 500
|
|
|
|
? '&4'
|
|
|
|
: res.statusCode >= 400
|
|
|
|
? '&6'
|
|
|
|
: res.statusCode >= 300
|
|
|
|
? '&3'
|
|
|
|
: res.statusCode >= 200
|
|
|
|
? '&2'
|
|
|
|
: '&f') + res.statusCode;
|
2022-09-04 21:55:32 +03:00
|
|
|
let responseTime = res.getResponseTime().toFixed(2);
|
|
|
|
responseTime = (responseTime >= 20
|
2022-05-06 02:12:38 +03:00
|
|
|
? '&c'
|
2022-09-04 21:55:32 +03:00
|
|
|
: responseTime >= 5
|
2022-05-06 02:12:38 +03:00
|
|
|
? '&e'
|
2022-09-04 21:55:32 +03:00
|
|
|
: '&a') + responseTime + 'ms';
|
|
|
|
client.log.info.http(short(`${req.ip} ${req.method} ${req.routerPath ?? '*'} &m-+>&r ${status}&b in ${responseTime}`));
|
2022-05-06 23:17:53 +03:00
|
|
|
done();
|
2022-05-06 02:12:38 +03:00
|
|
|
});
|
|
|
|
|
2022-05-06 23:17:53 +03:00
|
|
|
fastify.addHook('onError', async (req, res, err) => client.log.error.http(err));
|
|
|
|
|
|
|
|
// route loading
|
2022-05-06 02:01:19 +03:00
|
|
|
const dir = join(__dirname, '/routes');
|
2022-07-18 15:34:29 +03:00
|
|
|
files(dir, {
|
|
|
|
exclude: /^\./,
|
|
|
|
match: /.js$/,
|
|
|
|
sync: true,
|
|
|
|
}).forEach(file => {
|
|
|
|
const path = file
|
|
|
|
.substring(0, file.length - 3) // remove `.js`
|
|
|
|
.substring(dir.length) // remove higher directories
|
2022-08-26 01:35:17 +03:00
|
|
|
.replace(/\\/g, '/') // replace `\` with `/` because Windows is stupid
|
2022-07-18 15:34:29 +03:00
|
|
|
.replace(/\[(\w+)\]/gi, ':$1') // convert [] to :
|
|
|
|
.replace('/index', '') || '/'; // remove index
|
|
|
|
const route = require(file);
|
|
|
|
Object.keys(route).forEach(method => fastify.route({
|
|
|
|
config: { client },
|
|
|
|
method: method.toUpperCase(),
|
|
|
|
path,
|
|
|
|
...route[method](fastify),
|
|
|
|
})); // register route
|
|
|
|
});
|
2022-05-06 02:01:19 +03:00
|
|
|
|
2022-09-06 22:30:28 +03:00
|
|
|
// const { handler: app } = await import('@discord-tickets/settings/build/handler.js');
|
|
|
|
// fastify.use('/*', app);
|
|
|
|
// fastify.use(app);
|
|
|
|
|
|
|
|
return fastify;
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = async client => {
|
|
|
|
build(client)
|
|
|
|
.then(fastify => {
|
|
|
|
// start server
|
|
|
|
fastify.listen({ port: process.env.HTTP_BIND }, (err, addr) => {
|
|
|
|
if (err) client.log.error.http(err);
|
|
|
|
else client.log.success.http(`Listening at ${addr}`);
|
|
|
|
});
|
|
|
|
})
|
|
|
|
.catch(client.log.error.http);
|
|
|
|
|
|
|
|
const express = require('express')();
|
|
|
|
const { handler } = await import('@discord-tickets/settings/build/handler.js');
|
|
|
|
express.get('/api/client', (req, res) => {
|
|
|
|
res.end('ok');
|
|
|
|
});
|
|
|
|
express.use(handler);
|
|
|
|
express.listen(3000, () => {
|
|
|
|
console.log('listening on port 3000');
|
2022-07-18 15:34:29 +03:00
|
|
|
});
|
2022-05-06 02:01:19 +03:00
|
|
|
};
|