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-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:46:18 +03:00
process . env . PUBLIC _HOST = process . env . API _EXTERNAL ; // the SvelteKit app expects `PUBLIC_HOST`
2022-09-06 22:30:28 +03:00
2022-09-06 22:46:18 +03:00
module . exports = async client => {
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 , {
2022-09-06 22:46:18 +03:00
callbackUri : ` ${ process . env . API _EXTERNAL } /auth/callback ` ,
2022-05-06 23:17:53 +03:00
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-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 ( ) ) {
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' ;
2022-09-06 22:46:18 +03:00
client . log . info . http ( short ( ` API ${ 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-09-06 22:46:18 +03:00
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 ) ;
2022-09-06 22:46:18 +03:00
2022-07-18 15:34:29 +03:00
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:46:18 +03:00
// start server
fastify . listen ( { port : process . env . API _BIND } , ( err , addr ) => {
if ( err ) client . log . error . http ( err ) ;
else client . log . success . http ( ` API Listening at ${ addr } ` ) ;
} ) ;
2022-09-06 22:30:28 +03:00
const express = require ( 'express' ) ( ) ;
const { handler } = await import ( '@discord-tickets/settings/build/handler.js' ) ;
express . get ( '/api/client' , ( req , res ) => {
res . end ( 'ok' ) ;
} ) ;
2022-09-06 22:46:18 +03:00
express . use ( ( req , res , next ) => {
next ( ) ;
// req.route?.path ?? '*'
client . log . verbose . http ( short ( ` SETTINGS ${ req . ip } ${ req . method } ${ req . path } ` ) ) ; // verbose because little information & SvelteKit is very spammy (lots of routes)
} ) ;
2022-09-06 22:30:28 +03:00
express . use ( handler ) ;
2022-09-06 22:46:18 +03:00
express . listen ( process . env . SETTINGS _BIND , ( ) => {
client . log . success . http ( ` SETTINGS Listening at ${ process . env . SETTINGS _BIND } ` ) ;
2022-07-18 15:34:29 +03:00
} ) ;
2022-05-06 02:01:19 +03:00
} ;