248 lines
8.1 KiB
JavaScript
248 lines
8.1 KiB
JavaScript
/*Canopy - The next generation of stoner streaming software
|
|
Copyright (C) 2024-2025 Rainbownapkin and the TTN Community
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as
|
|
published by the Free Software Foundation, either version 3 of the
|
|
License, or (at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.*/
|
|
|
|
//Define global crypto variable for altcha
|
|
globalThis.crypto = require('node:crypto').webcrypto;
|
|
|
|
//Define NODE imports
|
|
const https = require('https');
|
|
const fs = require('fs');
|
|
|
|
//Define NPM imports
|
|
const express = require('express');
|
|
const session = require('express-session');
|
|
const {createServer } = require('http');
|
|
const cookieParser = require('cookie-parser');
|
|
const { Server } = require('socket.io');
|
|
const path = require('path');
|
|
const mongoStore = require('connect-mongo');
|
|
const mongoose = require('mongoose');
|
|
|
|
//Define Local Imports
|
|
//Application
|
|
const channelManager = require('./app/channel/channelManager');
|
|
const pmHandler = require('./app/pm/pmHandler');
|
|
//Util
|
|
const configCheck = require('./utils/configCheck');
|
|
const scheduler = require('./utils/scheduler');
|
|
const {errorMiddleware} = require('./utils/loggerUtils');
|
|
const sessionUtils = require('./utils/sessionUtils');
|
|
//Validator
|
|
const accountValidator = require('./validators/accountValidator');
|
|
//DB Model
|
|
const statModel = require('./schemas/statSchema');
|
|
const flairModel = require('./schemas/flairSchema');
|
|
const emoteModel = require('./schemas/emoteSchema');
|
|
const tokeModel = require('./schemas/tokebot/tokeSchema');
|
|
const tokeCommandModel = require('./schemas/tokebot/tokeCommandSchema');
|
|
const migrationModel = require('./schemas/user/migrationSchema');
|
|
//Controller
|
|
const fileNotFoundController = require('./controllers/404Controller');
|
|
//Router
|
|
//Humie-Friendly
|
|
const indexRouter = require('./routers/indexRouter');
|
|
const aboutRouter = require('./routers/aboutRouter');
|
|
const registerRouter = require('./routers/registerRouter');
|
|
const loginRouter = require('./routers/loginRouter');
|
|
const profileRouter = require('./routers/profileRouter');
|
|
const adminPanelRouter = require('./routers/adminPanelRouter');
|
|
const channelRouter = require('./routers/channelRouter');
|
|
const newChannelRouter = require('./routers/newChannelRouter');
|
|
const passwordResetRouter = require('./routers/passwordResetRouter');
|
|
const emailChangeRouter = require('./routers/emailChangeController');
|
|
const migrateRouter = require('./routers/migrateRouter');
|
|
//Panel
|
|
const panelRouter = require('./routers/panelRouter');
|
|
//Popup
|
|
//const popupRouter = require('./routers/popupRouter');
|
|
//Tooltip
|
|
const tooltipRouter = require('./routers/tooltipRouter');
|
|
//Api
|
|
const apiRouter = require('./routers/apiRouter');
|
|
|
|
//Define Config variables
|
|
const config = require('../config.json');
|
|
const port = config.port;
|
|
const dbUrl = `mongodb://${config.db.user}:${config.db.pass}@${config.db.address}:${config.db.port}/${config.db.database}`;
|
|
|
|
//Define express
|
|
const app = express();
|
|
|
|
//Define session-store (exported so we can kill sessions from user schema)
|
|
module.exports.store = mongoStore.create({mongoUrl: dbUrl});
|
|
|
|
//define sessionMiddleware
|
|
const sessionMiddleware = session({
|
|
secret: config.secrets.sessionSecret,
|
|
resave: false,
|
|
saveUninitialized: false,
|
|
store: module.exports.store,
|
|
cookie: {
|
|
sameSite: "strict",
|
|
secure: config.protocol.toLowerCase() == "https"
|
|
}
|
|
});
|
|
|
|
//Declare web server
|
|
let webServer = null;
|
|
|
|
//If we're using HTTPS
|
|
if(config.protocol.toLowerCase() == "https"){
|
|
try{
|
|
//Read key/cert files and store contents
|
|
const httpsOptions = {
|
|
key: fs.readFileSync(config.ssl.key),
|
|
cert: fs.readFileSync(config.ssl.cert)
|
|
};
|
|
|
|
//Start HTTPS Server
|
|
webServer = https.createServer(httpsOptions, app);
|
|
}catch(err){
|
|
//If the error has a path
|
|
if(err.path != null && err.path != ""){
|
|
//Tell the user to fix their shit
|
|
console.log(`Error opening key/cert file: ${err.path}`);
|
|
//Otherwise
|
|
}else{
|
|
//Shit our pants
|
|
console.log("Unknown error occured while starting HTTPS server! Bailing out!");
|
|
console.log(err);
|
|
}
|
|
|
|
//and run for the hills
|
|
process.exit();
|
|
}
|
|
|
|
//Otherwise
|
|
}else{
|
|
//Default to HTTP
|
|
webServer = createServer(app)
|
|
}
|
|
const io = new Server(webServer, {});
|
|
|
|
//Connect mongoose to the database
|
|
mongoose.set("sanitizeFilter", true).connect(dbUrl).then(() => {
|
|
console.log("Connected to DB");
|
|
}).catch((err) => {
|
|
console.error("Unable to connecto to DB: ");
|
|
console.error(err);
|
|
process.exit();
|
|
});
|
|
|
|
//Static File Server, set this up first to avoid middleware running on top of it
|
|
//Serve client-side libraries
|
|
app.use('/lib/bootstrap-icons',express.static(path.join(__dirname, '../node_modules/bootstrap-icons'))); //Icon set
|
|
app.use('/lib/altcha',express.static(path.join(__dirname, '../node_modules/altcha/dist_external'))); //Self-Hosted PoW-based Captcha
|
|
app.use('/lib/hls.js',express.static(path.join(__dirname, '../node_modules/hls.js/dist'))); //HLS Media Handler
|
|
//Server public 'www' folder
|
|
app.use(express.static(path.join(__dirname, '../www')));
|
|
|
|
//Set View Engine
|
|
app.set('view engine', 'ejs');
|
|
app.set('views', __dirname + '/views');
|
|
|
|
//Middlware
|
|
//Enable Express
|
|
app.use(express.json());
|
|
|
|
//Enable Express Ccokie-Parser
|
|
app.use(cookieParser());
|
|
|
|
//Enable Express-Sessions
|
|
app.use(sessionMiddleware);
|
|
|
|
//Enable Express-Session w/ Socket.IO
|
|
io.engine.use(sessionMiddleware);
|
|
|
|
//Use rememberMe validators accross all requests.
|
|
app.use(accountValidator.rememberMeID());
|
|
app.use(accountValidator.rememberMeToken());
|
|
|
|
//Use remember me middleware
|
|
app.use(sessionUtils.rememberMeMiddleware);
|
|
|
|
//Routes
|
|
//Humie-Friendly
|
|
app.use('/', indexRouter);
|
|
app.use('/about', aboutRouter);
|
|
app.use('/register', registerRouter);
|
|
app.use('/login', loginRouter);
|
|
app.use('/profile', profileRouter);
|
|
app.use('/adminPanel', adminPanelRouter);
|
|
app.use('/c', channelRouter);
|
|
app.use('/newChannel', newChannelRouter);
|
|
app.use('/passwordReset', passwordResetRouter);
|
|
app.use('/emailChange', emailChangeRouter);
|
|
app.use('/migrate', migrateRouter);
|
|
//Panel
|
|
app.use('/panel', panelRouter);
|
|
//tooltip
|
|
app.use('/tooltip', tooltipRouter);
|
|
//Bot-Ready
|
|
app.use('/api', apiRouter);
|
|
|
|
//Handle error checking
|
|
app.use(errorMiddleware);
|
|
|
|
//Basic 404 handler
|
|
app.use(fileNotFoundController);
|
|
|
|
asyncKickStart();
|
|
|
|
/*Asyncronous Kickstarter function
|
|
Allows us to force server startup to wait on the DB to be ready.
|
|
Might be better if she kicked off everything at once, and ran a while loop to check when they where all done.
|
|
This runs once at server startup, and most startups will run fairly quickly so... Not worth it?*/
|
|
async function asyncKickStart(){
|
|
//Lettum fuckin' know wassup
|
|
console.log(`${config.instanceName}(Powered by Canopy) is booting up!`);
|
|
|
|
//Run legacy migration
|
|
await migrationModel.ingestLegacyDump();
|
|
|
|
//Build migration cache
|
|
await migrationModel.buildMigrationCache();
|
|
|
|
//Calculate Toke Map
|
|
await tokeModel.calculateTokeMap();
|
|
|
|
//Load default toke commands
|
|
await tokeCommandModel.loadDefaults();
|
|
|
|
//Load default flairs
|
|
await flairModel.loadDefaults();
|
|
|
|
//Load default emotes
|
|
await emoteModel.loadDefaults();
|
|
|
|
//Kick off scheduled-jobs
|
|
scheduler.kickoff();
|
|
|
|
//Check for insecure config
|
|
configCheck.securityCheck();
|
|
|
|
//Increment launch counter
|
|
await statModel.incrementLaunchCount();
|
|
|
|
//Hand over general-namespace socket.io connections to the channel manager
|
|
module.exports.channelManager = new channelManager(io)
|
|
module.exports.pmHandler = new pmHandler(io, module.exports.channelManager);
|
|
|
|
//Listen Function
|
|
webServer.listen(port, () => {
|
|
console.log(`Tokes up on port \x1b[4m\x1b[35m${port}\x1b[0m!\n`);
|
|
});
|
|
} |