import fs from 'fs'; import path from 'path'; import cors from 'cors'; import https from 'https'; import helmet from 'helmet'; import logger from 'morgan'; import express from 'express'; import cookieParser from 'cookie-parser'; import { fileExist } from './modules/fileManager'; import { log, error } from './modules/logManager'; import { speedLimiter, requestLimiter, checkSystemLoad, respondWithStatus } from './modules/requestHandler'; import testRouter from './routes/test'; import usersRouter from './routes/users'; import rolesRouter from './routes/roles'; import doctorsRouter from './routes/doctors'; import patientsRouter from './routes/patients'; import servicesRouter from './routes/services'; import companiesRouter from './routes/companies'; import hospitalsRouter from './routes/hospitals'; // create logs directory if it doesn't exist const logsDir = path.join(import.meta.dir, 'logs'); if (!fs.existsSync(logsDir)) fs.mkdirSync(logsDir); const app = express(); if (process.env.BEHIND_PROXY == 'true') app.set('trust proxy', ['loopback', 'linklocal', 'uniquelocal']); app.use(cors({ origin: '*' })); app.use(express.json()); app.use(cookieParser()); // Security app.use(helmet()); app.disable('x-powered-by'); // Rate limiting and anti DoS if (!process.env.DISABLE_ANTI_SPAM == 'true') app.use(speedLimiter); if (!process.env.DISABLE_ANTI_DOS == 'true') app.use(requestLimiter); app.use(checkSystemLoad); // Logging app.use(logger('dev')); app.use(logger('combined', { stream: fs.createWriteStream(path.join(import.meta.dir, 'logs/access.log'), { flags: 'a' }) })); app.use(express.static('public')); // routes app.use('/api/test', testRouter); app.use('/api/users', usersRouter); app.use('/api/roles', rolesRouter); app.use('/api/doctors', doctorsRouter); app.use('/api/patients', patientsRouter); app.use('/api/services', servicesRouter); app.use('/api/companies', companiesRouter); app.use('/api/hospitals', hospitalsRouter); app.use((req, res) => { return respondWithStatus(res, 404, 'Nothing\'s here!'); }); app.use((err, req, res) => { error(err.stack); return respondWithStatus(res, 500, 'Internal server error'); }); // run the API server if (process.env.ENABLE_HTTPS == 'true') { const certsDir = path.join(import.meta.dir, 'certs'); if (!fs.existsSync(certsDir)) fs.mkdirSync(certsDir); if (!fileExist(path.join(certsDir, process.env.HTTPS_KEY)) || !fileExist(path.join(certsDir, process.env.HTTPS_CERT))) { error('Missing HTTPS key or certificate'); process.exit(1); } const options = { key: fs.readFileSync(path.join(certsDir, process.env.HTTPS_KEY)), cert: fs.readFileSync(path.join(certsDir, process.env.HTTPS_CERT)), maxVersion: 'TLSv1.3', minVersion: 'TLSv1.2', ciphers: 'TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256', ecdhCurve: 'P-521:P-384', sigalgs: 'ecdsa_secp384r1_sha384', honorCipherOrder: true, }; https.createServer(options, app).listen(process.env.HTTPS_PORT, async () => { log('running in HTTPS mode'); log(`running at port ${process.env.HTTPS_PORT}`); }); } else { app.listen(process.env.PORT, async () => { log('running in HTTP mode'); log(`running at port ${process.env.PORT}`); }); }