First commit

This commit is contained in:
2023-12-07 20:35:55 +01:00
parent 3480f2ab05
commit ea881e2403
18 changed files with 668 additions and 0 deletions

26
api/modules/database.js Normal file
View File

@@ -0,0 +1,26 @@
import mysql from 'mysql2';
const connection = mysql.createConnection({
host: process.env.DATABASE_HOST,
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE_NAME,
});
const pool = mysql.createPool({
host: process.env.DATABASE_HOST,
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE_NAME,
}).promise();
function createPool(host, user, password, db) {
const newPool = mysql.createPool({
host: host,
user: user,
password: password,
database: db,
}).promise();
return newPool;
}
export { connection, pool, createPool };

19
api/modules/log.js Normal file
View File

@@ -0,0 +1,19 @@
import pino from 'pino';
const logger = pino();
export function log(x) {
logger.info(x);
}
export function debug(x) {
logger.debug(x);
}
export function warn(x) {
logger.warn(x);
}
export function error(x) {
logger.error(x);
}

20
api/modules/random.js Normal file
View File

@@ -0,0 +1,20 @@
export function random(x, y) {
return crypto.randomInt(x, y + 1);
}
export function random2(min, max) {
const range = max - min + 1;
const byteLength = Math.ceil(Math.log2(range) / 8);
let randomValue;
do {
const randomBytes = crypto.randomBytes(byteLength);
randomValue = parseInt(randomBytes.toString('hex'), 16);
} while (randomValue >= range);
return randomValue + min;
}
export function randomHEX(x) {
return crypto.randomBytes(x).toString('hex');
}

View File

@@ -0,0 +1,54 @@
import rateLimit from 'express-rate-limit';
import slowDown from 'express-slow-down';
import http from 'http';
import os from 'os';
const requestLimiter = rateLimit({
windowMs: 60 * 1000,
max: 5,
standardHeaders: true,
legacyHeaders: false,
message: 'Too many requests from this IP, please try again later',
});
const speedLimiter = slowDown({
windowMs: 60 * 1000,
delayAfter: 5,
delayMs: (hits) => hits * 100,
});
function checkSystemLoad(req, res, next) {
const load = os.loadavg()[0];
const cores = os.cpus().length;
const threshold = cores * 0.7;
if (load > threshold) {
return respondWithStatus(res, 503, 'API Unavailable - System Overloaded!');
}
return next();
}
function respondWithStatus(res, statusCode, message) {
const response = { status: statusCode, message: message };
if (statusCode >= 400 && statusCode <= 599) {
response.error = http.STATUS_CODES[statusCode];
}
return res.status(statusCode).json(response);
}
function respondWithStatusJSON(res, statusCode, JSON) {
const response = { status: statusCode, JSON };
if (statusCode >= 400 && statusCode <= 599) {
response.error = http.STATUS_CODES[statusCode];
}
return res.status(statusCode).json(response);
}
export {
requestLimiter,
speedLimiter,
checkSystemLoad,
respondWithStatus,
respondWithStatusJSON,
};

52
api/modules/token.js Normal file
View File

@@ -0,0 +1,52 @@
/* eslint-disable no-undef */
import jwt from 'jsonwebtoken';
import { Level } from 'level';
import { respondWithStatus } from './requestHandler';
import { pool } from './database';
// Set up LevelDB instance
const db = new Level('./tokensDB');
// Generate a new JWT
const generateToken = async (userId, password) => {
const token = jwt.sign({ userId: userId, password: password }, process.env.JWT_SECRET, { expiresIn: '7d' });
await db.put(token);
return token;
};
// Middleware to verify the JWT and set req.userId
const verifyToken = async (req, res, next) => {
const token = req.headers.authorization;
if (!token) return await respondWithStatus(res, 401, 'No token provided');
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.userId = decoded.userId;
const [rows] = await pool.execute(
'SELECT * FROM users WHERE id = ? LIMIT 1', [req.userId],
);
if (!rows.length) return await respondWithStatus(res, 404, 'User not found!');
const passwordMatch = await Bun.password.verify(decoded.password, rows[0].password);
if (!passwordMatch) return await respondWithStatus(res, 401, 'Token is invalid');
const now = Date.now().valueOf() / 1000;
if (decoded.exp - now < 36000) {
const newToken = generateToken(req.userId, decoded.password);
res.cookie('token', newToken, {
expires: new Date(Date.now() + 14 * 24 * 60 * 60 * 1000),
httpOnly: true,
secure: true,
sameSite: 'strict',
});
res.set('Authorization', newToken);
}
next();
}
catch (error) {
return await respondWithStatus(res, 401, 'Invalid user');
}
};
export { generateToken, verifyToken };