diff --git a/src/app/channel/commandPreprocessor.js b/src/app/channel/commandPreprocessor.js index 28fafb6..bb5f9b4 100644 --- a/src/app/channel/commandPreprocessor.js +++ b/src/app/channel/commandPreprocessor.js @@ -189,4 +189,80 @@ class commandProcessor{ //throw send flag return true; } + + async kick(preprocessor){ + //Get the current channel from the database + const chanDB = await channelModel.findOne({name: preprocessor.socket.chan}); + + //Check if the user has permission, and publicly shame them if they don't (lmao) + if(await chanDB.permCheck(preprocessor.socket.user, 'kickUser')){ + //Get username from argument array + const username = preprocessor.argumentArray[1]; + + //Get channel + const channel = this.server.activeChannels.get(preprocessor.socket.chan); + + //get initiator and target user objects + const initiator = channel.userList.get(preprocessor.socket.user.user); + const target = channel.userList.get(username); + + //get initiator and target override abilities + const override = await permissionModel.overrideCheck(preprocessor.socket.user, 'kickUser'); + const targetOverride = await permissionModel.overrideCheck(target, 'kickUser'); + + //If there is no user + if(target == null){ + //silently drop the command + return false; + } + + + //If the user is capable of overriding this permission based on site permissions + if(override || targetOverride){ + //If the site rank is equal + if(permissionModel.rankToNum(initiator.rank) == permissionModel.rankToNum(target.rank)){ + //compare chan rank + if(permissionModel.rankToNum(initiator.chanRank) <= permissionModel.rankToNum(target.chanRank)){ + //shame the person running it + return true; + } + //otherwise + }else{ + //compare site rank + if(permissionModel.rankToNum(initiator.rank) <= permissionModel.rankToNum(target.rank)){ + //shame the person running it + return true; + } + } + }else{ + //If the target has a higher chan rank than the initiator + if(permissionModel.rankToNum(initiator.chanRank) <= permissionModel.rankToNum(target.chanRank)){ + //shame the person running it + return true; + } + } + + + //Splice out kick + preprocessor.commandArray.splice(0,4) + + //Get collect reason + var reason = preprocessor.commandArray.join(''); + + //If no reason was given + if(reason == ''){ + //Fill in a generic reason + reason = "You have been kicked from the channel!"; + } + + //Kick the user + target.disconnect(reason); + + //throw send flag + return false; + } + + //throw send flag + return true; + } } \ No newline at end of file diff --git a/src/controllers/api/channel/banController.js b/src/controllers/api/channel/banController.js index ecddfeb..de3ea21 100644 --- a/src/controllers/api/channel/banController.js +++ b/src/controllers/api/channel/banController.js @@ -60,18 +60,47 @@ module.exports.post = async function(req, res){ const targetDB = await userModel.findOne({user}); const chanDB = await channelModel.findOne({name: chanName}); - const initiatorRank = await chanDB.getChannelRankByUserDoc(initiatorDB); - const targetRank = await chanDB.getChannelRankByUserDoc(targetDB); + //get initiator and target override abilities + const override = await permissionModel.overrideCheckByUserDoc(initiatorDB, 'banUser'); + const targetOverride = await permissionModel.overrideCheckByUserDoc(targetDB, 'banUser'); + //Get channel ranks + const initiatorChanRank = await chanDB.getChannelRankByUserDoc(initiatorDB); + const targetChanRank = await chanDB.getChannelRankByUserDoc(targetDB); + + //If we're targeting a null user if(targetDB == null){ //If the user is null, scream and shout return errorHandler(res, `User not found.`, 'Bad Query', 400); + //if self ban }else if(targetDB.user == req.session.user.user){ //If some smart-ass is trying to self-ban return errorHandler(res, `Keep it up, maybe I will ban you!`, 'Unauthorized', 401); - }else if(permissionModel.rankToNum(targetRank) >= permissionModel.rankToNum(initiatorRank)){ - //If the user is trying to ban a peer/outranking user - return errorHandler(res, 'You cannot ban peer/outranking users', 'Unauthorized', 401); + //otherwise + }else{ + //If someone involved has the ability to override + if(override || targetOverride){ + //If the site rank is equal + if(permissionModel.rankToNum(initiatorDB.rank) == permissionModel.rankToNum(targetDB.rank)){ + //compare chan rank + if(permissionModel.rankToNum(initiatorChanRank) <= permissionModel.rankToNum(targetChanRank)){ + //error out over bad chan rank + return errorHandler(res, 'You cannot ban peer/outranking users', 'Unauthorized', 401); + } + //otherwise + }else{ + //compare site rank + if(permissionModel.rankToNum(initiatorDB.rank) <= permissionModel.rankToNum(targetDB.rank)){ + //shame the person running it + return errorHandler(res, 'You cannot ban this user due to site-wide permissions override policies.', 'Unauthorized', 401); + } + } + }else{ + if(permissionModel.rankToNum(targetChanRank) >= permissionModel.rankToNum(initiatorChanRank)){ + //If the user is trying to ban a peer/outranking user + return errorHandler(res, 'You cannot ban peer/outranking users', 'Unauthorized', 401); + } + } } await chanDB.banByUserDoc(targetDB, expirationDays, banAlts); diff --git a/src/schemas/channel/channelSchema.js b/src/schemas/channel/channelSchema.js index baaefd1..6a12d24 100644 --- a/src/schemas/channel/channelSchema.js +++ b/src/schemas/channel/channelSchema.js @@ -120,7 +120,7 @@ channelSchema.pre('save', async function (next){ if(chanDB != null){ //If we're removing one if(chanDB.rankList.length > this.rankList.length){ - //Child/Parent is *WAY* to atomic family for my tastes :P + //Child/Parent is *WAY* tooo atomic family for my tastes :P var top = chanDB; var bottom = this; }else{ @@ -133,18 +133,26 @@ channelSchema.pre('save', async function (next){ await top.populate('rankList.user'); + //For each rank in the dommy-top copy of the rank list top.rankList.forEach((topObj) => { //Create empty variable for the matched rank var matchedRank = null; - //For each rank in the old copy of the rank list + //For each rank in the subby-bottom copy of the rank list bottom.rankList.forEach((bottomObj) => { + //So long as both users exist (we're not working with deleted users) + if(topObj.user != null && bottomObj.user != null){ + //If it's the same user if(topObj.user._id.toString() == bottomObj.user._id.toString()){ + //matched rank found matchedRank = bottomObj; } + } }); + //If matched rank is null or isn't the topObject rank if(matchedRank == null || matchedRank.rank != topObj.rank){ + //Set top object to found rank foundRank = topObj; } diff --git a/src/schemas/permissionSchema.js b/src/schemas/permissionSchema.js index 5e8c3d5..fea601d 100644 --- a/src/schemas/permissionSchema.js +++ b/src/schemas/permissionSchema.js @@ -161,6 +161,43 @@ permissionSchema.statics.permCheckByUserDoc = async function(user, perm){ } } +permissionSchema.statics.overrideCheck = async function(user, perm){ + //Check if the user is null + if(user != null){ + //This specific call is why we export the userModel the way we do + //Someone will yell at me for circular dependencies but the fucking interpreter isn't :P + const userDB = await userModel.userModel.findOne({user: user.user}); + return await this.overrideCheckByUserDoc(userDB, perm); + }else{ + return await this.overrideCheckByUserDoc(null, perm); + } +} + +permissionSchema.statics.overrideCheckByUserDoc = async function(user, perm){ + //Get permission list + const perms = (await this.getPerms()).channelOverrides; + + //Set user to anon rank if no rank was found for the given user + if(user == null || user.rank == null){ + user ={ + rank: "anon" + }; + } + + //Check if this permission exists + if(perms[perm] != null){ + //if so get required rank as a number + requiredRank = this.rankToNum(perms[perm]) + //if so get user rank as a number + userRank = user ? this.rankToNum(user.rank) : 0; + //return whether or not the user is equal to or higher than the required rank for this permission + return (userRank >= requiredRank); + }else{ + //if not scream and shout + throw new Error(`Permission check '${perm}' not found!`); + } +} + //Middleware for rank checks permissionSchema.statics.reqPermCheck = function(perm){ return (req, res, next)=>{