const express = require('express') const app = express() const rateLimit = require('express-rate-limit') const helmet = require('helmet') const bp = require('body-parser') const cookieParser = require('cookie-parser') const fs = require('fs') const path = require('path') const { readdirSync } = require('fs') const session = require('./src/session')() const routesConfig = require('./config/routes') const mime = { html: 'text/html', txt: 'text/plain', css: 'text/css', xml: 'text/xml', gif: 'image/gif', jpg: 'image/jpeg', png: 'image/png', webp: 'image/webp', avif: 'image/avif', ico: 'image/ico', svg: 'image/svg+xml', js: 'application/javascript', mp4: 'video/mp4', webm: 'video/webm', ttf: 'application/x-font-truetype', ttc: 'application/x-font-truetype', otf: 'application/x-font-otf', ots: 'application/x-font-otf', woff: 'application/font-woff', woff2: 'application/font-woff', pfb: 'application/vnd.ms-fontbook', pfm: 'application/vnd.ms-fontbook', gsf: 'application/vnd.ms-fontbook', swf: 'application/vnd.ms-fontbook' } const assetDir = () => { return readdirSync(`${__dirname}/assets`, { withFileTypes: true }) .filter(dir => dir.isDirectory()) .map(dir => dir.name) } /* const limiter = rateLimit({ windowMS: 30 * 1000, max: 100, message: '

Rate Limit Exceeded

You have exceeded the allowed number of requests. Please try again later.

' }) */ require('dotenv').config() const sitemap = require('./src/sitemap') const logger = require('./src/logger')({ baseURL: process.env.baseURL }) const controller = require('./src/controller')({ baseURL: process.env.baseURL }) const createLog = (req, res, next) => { const { cookies } = req const object = { queryString: '', exists: false } Object.entries(req.query).forEach(([key, value]) => { if (object.exists === false) { object.queryString += '?' } object.queryString += `${key}=${value}&` object.exists = true }) if (object.exists) object.queryString = object.queryString.slice(0, -1) logger.Info(`${req.method} ${req.path}${object.queryString} from ${req.ip}:${cookies.session_id ? cookies.session_id.replace('session_id', '') : 'n/a'}`) next() } const validateCookie = (req, res, next) => { const { cookies } = req if (cookies === undefined) { res.cookie('session_id', session.Create()) } else { if ('session_id' in cookies) { if (session.Exists(cookies.session_id.replace('session_id', ''))) { session.Expired() } else { res.clearCookie('session_id') res.cookie('session_id', session.Create()) } } else res.cookie('session_id', session.Create()) } next() } const openFile = x => { const data = { path: x.filePath.split('/'), exists: false, data: {} } if (assetDir().includes(data.path[1])) { this.path = `${__dirname}/assets/${data.path[1]}/${data.path[2]}` data.exists = fs.existsSync(this.path) data.data.mime = mime[path.extname(this.path).slice(1)] || 'text/plain' data.data.file = fs.createReadStream(this.path) .on('error', (err) => { return }) } else if (data.path[1] === 'favicon.ico' && (data.path.length === 2 || (data.path.length === 3 && data.path[2] === ''))) { data.data.file = fs.createReadStream(`${__dirname}/config/favicon.ico`) .on('error', (err) => { logger.Error(`'favicon.ico' does not exist. Please add it to the config.`) }) } if (data.exists) { x.res.set('Content-Type', data.data.mime) data.data.file .on('open', () => { data.data.file.pipe(x.res) }) .on('error', err => { logger.Error(err) }) } else { x.res.set('Content-Type', mime.html) x.res.status(404).send('File not found.') } } app.use(bp.json()) app.use(cookieParser()) app.use((req, res, next) => { let err = null try { decodeURIComponent(req.path) } catch (e) { err = e } if (err) { return res.redirect(['http://', req.get('Host'), '/404'].join('')) } next() }) const handleRoutes = (req, res, next) => { this.path = { split: req.path.split('/'), string: req.path } if(routes.has(this.path.string)) { const route = routes.get(this.path.string) if (route.req === req.method) { res.send(route.method()) } else { next() } } else { next() } } const routes = routesConfig({ app: app, validateCookie: validateCookie, log: createLog, mime: mime, session: session }) app.route(/(.*)/) .get(validateCookie, createLog, (req, res) => { this.path = { split: req.path.split('/'), string: req.path } if (assetDir().includes(this.path.split[1])) { openFile({ filePath: this.path.string, res: res }) } else { switch (this.path.split[1]) { case 'favicon.ico': openFile({ filePath: this.path.string, res: res }) break case 'sitemap.xml': const data = sitemap({baseURL: process.env.baseURL}) data.Sitemap().then(output => { res.send(output) }) break case 'rss': rss({ baseURL: process.env.baseURL }) break case 'deverror': break default: const response = controller.Init({ req: req, res: res, path: this.path.string, baseURL: process.env.baseURL }) res.send(response) break } } }) .post(createLog, (req, res) => {}) .put(createLog, (req, res) => {}) .delete(createLog, (req, res) => {}) .patch(createLog, (req, res) => {}) .all(createLog, (req, res) => { res.set('Content-Type', mime.html) res.status(404).send('You are not allowed to access this resource') }) app.listen(process.env.PORT, () => { logger.Info(`Listening on: ${process.env.baseURL}`) })