141 lines
4.5 KiB
JavaScript
141 lines
4.5 KiB
JavaScript
/*
|
|
______ __ ______
|
|
/ \ / | / \
|
|
/$$$$$$ | _______ _$$ |_ ______ ______ /$$$$$$ | ______ _____ ____
|
|
$$ |__$$ | / |/ $$ | / \ / \ $$ | $$/ / \ / \/ \
|
|
$$ $$ |/$$$$$$$/ $$$$$$/ /$$$$$$ |/$$$$$$ |$$ | /$$$$$$ |$$$$$$ $$$$ |
|
|
$$$$$$$$ |$$ \ $$ | __ $$ | $$/ $$ | $$ |$$ | __ $$ | $$ |$$ | $$ | $$ |
|
|
$$ | $$ | $$$$$$ | $$ |/ |$$ | $$ \__$$ |$$ \__/ |$$ \__$$ |$$ | $$ | $$ |
|
|
$$ | $$ |/ $$/ $$ $$/ $$ | $$ $$/ $$ $$/ $$ $$/ $$ | $$ | $$ |
|
|
$$/ $$/ $$$$$$$/ $$$$/ $$/ $$$$$$/ $$$$$$/ $$$$$$/ $$/ $$/ $$/
|
|
|
|
Made with <3 by Chris Chrome and the rest of the AstroCom team
|
|
*/
|
|
|
|
require("dotenv").config();
|
|
const { execSync } = require('child_process');
|
|
const express = require('express');
|
|
const expressSession = require('express-session');
|
|
const ejs = require("ejs")
|
|
const mariadb = require('mariadb');
|
|
const bcrypt = require("bcrypt")
|
|
const crypto = require("crypto")
|
|
const app = express();
|
|
const path = require('path');
|
|
const fs = require('fs');
|
|
const port = process.env.SERVER_PORT || 3000;
|
|
|
|
const pool = mariadb.createPool({
|
|
host: process.env.DB_HOST || '127.0.0.1',
|
|
port: process.env.DB_PORT || 3306,
|
|
user: process.env.DB_USER || 'root',
|
|
password: process.env.DB_PASSWORD || '',
|
|
database: process.env.DB_NAME || 'astrocom',
|
|
connectionLimit: 10
|
|
});
|
|
const saltRounds = 10;
|
|
|
|
global.db_pool = pool; // Make the pool global so we can use it in other files
|
|
|
|
const analytics = require("./analytics");
|
|
|
|
// Run migrations and reset admin user if desired
|
|
pool.getConnection().then((conn) => {
|
|
require("./migrations")(pool).then(() => {
|
|
conn.query("SELECT * FROM users WHERE id = 1").then((row) => {
|
|
if (!row || process.env.RESET_ADMIN == "true") {
|
|
// delete all users (The big scary one lol)
|
|
conn.query("DELETE FROM users").then(() => {
|
|
// Generate 32 char random string
|
|
const passwd = crypto.randomBytes(32).toString('hex');
|
|
bcrypt.hash(passwd, 10).then((hash) => {
|
|
conn.query("INSERT INTO users (id, username, passwordHash) VALUES (1, 'admin', ?)",
|
|
[hash]).then(() => {
|
|
console.log(`Created admin user with password: ${passwd}`);
|
|
});
|
|
});
|
|
});
|
|
}
|
|
});
|
|
}).finally(() => {
|
|
conn.release();
|
|
});
|
|
});
|
|
|
|
const gitCommitHashShort = execSync('git rev-parse --short HEAD').toString().trim();
|
|
const branch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim();
|
|
const version = `${gitCommitHashShort}-${branch}`;
|
|
|
|
console.log(`Version: ${version}`);
|
|
|
|
app.use(express.json());
|
|
app.use(express.urlencoded({ extended: true }));
|
|
|
|
app.use(expressSession({
|
|
store: expressSession.MemoryStore(),
|
|
secret: process.env.SESSION_SECRET || 'default_secret',
|
|
resave: false,
|
|
saveUninitialized: false,
|
|
cookie: {
|
|
secure: process.env.NODE_ENV === 'production',
|
|
maxAge: 24 * 60 * 60 * 1000 // 24 hours
|
|
}
|
|
}));
|
|
|
|
app.set('view engine', 'ejs');
|
|
app.set('views', __dirname + '/views');
|
|
// Static files
|
|
app.use(express.static('public'));
|
|
|
|
|
|
app.use((req, res, next) => {
|
|
if (req.path.startsWith("/api/v1")) {
|
|
analytics.addAnalytic("apiCalls");
|
|
};
|
|
next();
|
|
})
|
|
|
|
|
|
// Other public endpoints that need special handling
|
|
discordInviteCache = { time: 0, url: "" };
|
|
|
|
app.get("/discord", (req, res) => {
|
|
// fetch from process.env.WIDGET_URL, get json body, redirect to body.instant_invite. Cache url for 5 minutes
|
|
if (Date.now() - discordInviteCache.time < 300000) {
|
|
res.redirect(discordInviteCache.url);
|
|
return;
|
|
}
|
|
fetch(process.env.WIDGET_URL)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
discordInviteCache.time = Date.now();
|
|
discordInviteCache.url = data.instant_invite;
|
|
res.redirect(data.instant_invite);
|
|
})
|
|
.catch(error => {
|
|
console.error('Error fetching discord invite:', error);
|
|
res.status(500).send('Internal server error');
|
|
});
|
|
});
|
|
|
|
app.get("/footer", (req, res) => {
|
|
res.render("footer", { version });
|
|
});
|
|
|
|
const startup = () => {
|
|
// Load all route modules from the 'routes' folder
|
|
const routesPath = path.join(__dirname, 'routes');
|
|
fs.readdirSync(routesPath).forEach((file) => {
|
|
const route = require(path.join(routesPath, file));
|
|
const routeName = `/${file.replace('.js', '')}`; // Use filename as route base
|
|
app.use(routeName, route);
|
|
console.log(`Using ${routeName}`)
|
|
});
|
|
|
|
// Start server
|
|
app.listen(port, () => {
|
|
console.log(`Listening on port ${port}`);
|
|
});
|
|
}
|
|
|
|
startup(); |