Finished upgrade logic

This commit is contained in:
rainbow napkin 2026-07-06 01:06:33 -04:00
parent d03e221891
commit 0dda73cd14
8 changed files with 230 additions and 32 deletions

View file

@ -31,52 +31,52 @@ module.exports.securityCheck = function(){
//Check Protocol
if(config.protocol.toLowerCase() != 'https'){
//If it's insecure then warn the admin
loggerUtil.consoleWarn("Starting in HTTP mode. This server should be used for development purposes only!");
loggerUtil.consoleShout("Starting in HTTP mode. This server should be used for development purposes only!");
}
//Check mail protocol
if(!config.mail.secure){
//If it's insecure then warn the admin
loggerUtil.consoleWarn("Mail transport security disabled! This server should be used for development purposes only!");
loggerUtil.consoleShout("Mail transport security disabled! This server should be used for development purposes only!");
}
//check password pepper
if(!validator.isStrongPassword(config.secrets.passwordSecret) || config.secrets.passwordSecret == "CHANGE_ME"){
loggerUtil.consoleWarn("Insecure Password Secret! Change Password Secret!");
loggerUtil.consoleShout("Insecure Password Secret! Change Password Secret!");
}
//check RememberMe pepper
if(!validator.isStrongPassword(config.secrets.rememberMeSecret) || config.secrets.rememberMeSecret == "CHANGE_ME"){
loggerUtil.consoleWarn("Insecure RememberMe Secret! Change RememberMe Secret!");
loggerUtil.consoleShout("Insecure RememberMe Secret! Change RememberMe Secret!");
}
//check session secret
if(!validator.isStrongPassword(config.secrets.sessionSecret) || config.secrets.sessionSecret == "CHANGE_ME"){
loggerUtil.consoleWarn("Insecure Session Secret! Change Session Secret!");
loggerUtil.consoleShout("Insecure Session Secret! Change Session Secret!");
}
//check altcha secret
if(!validator.isStrongPassword(config.secrets.altchaSecret) || config.secrets.altchaSecret == "CHANGE_ME"){
loggerUtil.consoleWarn("Insecure Altcha Secret! Change Altcha Secret!");
loggerUtil.consoleShout("Insecure Altcha Secret! Change Altcha Secret!");
}
//check ipHash secret
if(!validator.isStrongPassword(config.secrets.ipSecret) || config.secrets.ipSecret == "CHANGE_ME"){
loggerUtil.consoleWarn("Insecure IP Hashing Secret! Change IP Hashing Secret!");
loggerUtil.consoleShout("Insecure IP Hashing Secret! Change IP Hashing Secret!");
}
//check DB pass
if(!validator.isStrongPassword(config.db.pass) || config.db.pass == "CHANGE_ME" || config.db.pass == config.db.user){
loggerUtil.consoleWarn("Insecure Database Password! Change Database password!");
loggerUtil.consoleShout("Insecure Database Password! Change Database password!");
}
//check email pass
if(!validator.isStrongPassword(config.mail.pass) || config.mail.pass == "CHANGE_ME"){
loggerUtil.consoleWarn("Insecure Email Password! Change Email password!");
loggerUtil.consoleShout("Insecure Email Password! Change Email password!");
}
//check debug mode
if(config.debug){
loggerUtil.consoleWarn("Debug mode enabled! Understand the risks and security implications before enabling on production servers!");
loggerUtil.consoleShout("Debug mode enabled! Understand the risks and security implications before enabling on production servers!");
}
}

View file

@ -142,12 +142,20 @@ module.exports.socketCriticalExceptionHandler = function(socket, err){
return socket.disconnect();
}
/**
* Shouts into the server console
* @param {String} string - String to shout into to the console
*/
module.exports.consoleShout = function(string){
console.warn('\x1b[31m\x1b[4m%s\x1b[0m',string);
}
/**
* Prints warning text to server console
* @param {String} string - String to print to console
*/
module.exports.consoleWarn = function(string){
console.warn('\x1b[31m\x1b[4m%s\x1b[0m',string);
console.warn('\x1b[33m%s\x1b[0m',string);
}
/**
@ -208,7 +216,7 @@ module.exports.dumpLog = async function(content, name, subDir = '/', muzzle = fa
}catch(err){
if(!muzzle){
//Shout about it
module.exports.consoleWarn("Log folder missing, mking dir!")
module.exports.consoleShout("Log folder missing, mking dir!")
}
//Make it if doesn't
@ -223,17 +231,17 @@ module.exports.dumpLog = async function(content, name, subDir = '/', muzzle = fa
if(!muzzle){
//Whine about the error
module.exports.consoleWarn(`Warning: Unexpected Server Crash gracefully dumped to '${path}'... SOMETHING MAY BE VERY BROKEN!!!!`);
module.exports.consoleShout(`Warning: Unexpected Server Crash gracefully dumped to '${path}'... SOMETHING MAY BE VERY BROKEN!!!!`);
}
//If somethine went really really wrong
}catch(doubleErr){
if(!muzzle){
//Use humor to cope with the pain
module.exports.consoleWarn("Yo Dawg, I herd you like errors, so I put an error in your error dump, so you can dump while you dump:");
module.exports.consoleShout("Yo Dawg, I herd you like errors, so I put an error in your error dump, so you can dump while you dump:");
//Dump the original error to console
module.exports.consoleWarn(err);
module.exports.consoleShout(err);
//Dump the error we had saving that error to file to console
module.exports.consoleWarn(doubleErr);
module.exports.consoleShout(doubleErr);
}
}
}

View file

@ -18,6 +18,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.*/
const {validationResult, matchedData} = require('express-validator');
//Local Imports
const server = require('../server.js');
const config = require('../../config.json');
const {userModel} = require('../schemas/user/userSchema.js');
const userBanModel = require('../schemas/user/userBanSchema.js');
@ -187,6 +188,22 @@ module.exports.killSession = async function(session){
session.destroy();
}
module.exports.killAllSessions = function(){
//Grab the entire session store from the server
server.store.all((err, sessions) => {
//You guys ever hear of a 'not my' problem? Fucking y33tskies lmao, better use a try/catch
if(err){
throw err;
}
//crawl through active sessions
sessions.forEach((session) => {
//Fuckin' nukem!
server.store.destroy(session.seshid);
});
});
}
/**
* Returns how many failed login attempts within the past day or so since the last login has occured for a given user
* @param {String} user - User to check map against

177
src/utils/upgradeUtils.js Normal file
View file

@ -0,0 +1,177 @@
/*Canopy - The next generation of stoner streaming software
Copyright (C) 2024-2026 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/>.*/
//Config Imports
const package = require('../../package.json');
//Local Imports
const loggerUtils = require('./loggerUtils');
const sessionUtils = require('./sessionUtils');
const statModel = require('../schemas/statSchema');
const { userModel } = require('../schemas/user/userSchema');
const channelModel = require('../schemas/channel/channelSchema');
const archiveModel = require('../schemas/channel/media/archivedMediaSchema');
const { channelPlaylistModel } = require('../schemas/channel/media/playlist/playlistSchema');
const { userPlaylistModel } = require('../schemas/channel/media/playlist/playlistSchema');
const archivedMedia = require('../app/channel/media/archivedMedia');
/**
* Checks server for recent upgrades upon boot
*/
module.exports.upgradeCheck = async function(){
//Get the server statistics document from Database
const stats = await statModel.getStats();
//Throw this flag if an upgrade is initiated to automagically and silently initiate all upgrades after it
let upgradeStarted = false;
//If we're upgrading from Panama Red (or older)
if(stats.version == "<0.2.0"){
//Initiate upgrade procedure from Panama Red
await upgradePanamaRed();
//Throw upgrade started flag
upgradeStarted = true;
}
//If we upgraded
if(upgradeStarted){
//Update the statistics document to reflect the new version
stats.version = package.version;
//Write the statistics document to the DB
await stats.save();
}
loggerUtils.consoleShout(`Database Upgrading to ${package.canopyDisplayVersion} Complete!`);
}
/**
* Upgrades server database from Panama Red
* @param {Boolean} quiet - tells upgrade logic to STFU!
*/
async function upgradePanamaRed(quiet = false){
//If we're bein' loud
if(!quiet){
upgradeWarn("0.1-Alpha (Panama Red)");
}
//Warn of impending session death
loggerUtils.consoleWarn("Killing all active sessions!");
//Nuke existing sessions since the new version requires the user _id in there
sessionUtils.killAllSessions();
//Pull all channels into RAM
const channels = await channelModel.find();
//Pull all users into RAM
const users = await userModel.find();
//For every channel on the server
for(channel of channels){
//Create variables to track upgraded objects
let archived = 0;
let playlists = 0;
//log the migration
loggerUtils.consoleWarn(`Upgrading Channel '${channel.name}'..`);
//Iterate through the given channels media archive
for(entry of channel.media.archived){
//Re-hydrate archived media object
const mediaObject = archivedMedia.fromQueuedMedia(entry.rehydrate())
//Tattoo channel name into media object
mediaObject.channel = channel.name;
//Add media object to the site-wide media archive
await archiveModel.create(mediaObject);
//We could just pull the archvied array count, but this feels more honest XP
archived++;
}
//Iterate through the given channels playlists
for(playlist of channel.media.playlists){
//Create channel playlist in site-wide collection
await channelPlaylistModel.create({
name: playlist.name,
media: playlist.media,
defaultTitles: playlist.defaultTitles,
channel: channel._id
})
//We could just pull the playlists array count, but this feels more honest XP
playlists++;
}
//If we did anything
if(playlists > 0 || archived > 0){
//Clear out archived media from channel document
channel.media.archived = [];
//Clear out playlists from channel document
channel.media.playlists = [];
//Save updated channel document
await channel.save();
//log the migration
loggerUtils.consoleWarn(`Channel '${channel.name}; Upgrade Complete! Optimized ${playlists} Playlist(s), and ${archived} Media Object(s)!`);
}
}
//For each registered user on the server
for(user of users){
//Create variable to track upgraded playlist count
let playlists = 0;
//Iterate through users playlists
for(playlist of user.playlists){
//Create channel playlist in site-wide collection
await userPlaylistModel.create({
name: playlist.name,
media: playlist.media,
defaultTitles: playlist.defaultTitles,
user: user._id
})
//We could just pull the playlists array count, but this feels more honest XP
playlists++;
}
//If we did anything
if(playlists > 0){
//Clear out playlists from channel document
user.playlists = [];
//Save updated channel document
await user.save();
//log the migration
loggerUtils.consoleWarn(`User '${user.user}' Upgrade Complete! Optimized ${playlists} Playlist(s)!`);
}
}
}
/**
* Warns server admin of impending Database upgrades
* @param {String} versionString - Version we're upgrading from
*/
function upgradeWarn(versionString){
//Rise and Shout the ~~AlphaSmart's~~ upgrade's out!
//https://eeggs.com/images/items/2942.full.jpg
loggerUtils.consoleShout("Server Upgrade Detected!");
loggerUtils.consoleShout(`Upgrading Database from ${versionString} to ${package.canopyDisplayVersion}`);
}