finish security rehaul

This commit is contained in:
Yaman Qalieh 2016-10-28 22:24:09 -04:00
parent fcc89a7b60
commit 106f72f1e9

View File

@ -124,7 +124,7 @@ Security.permit(['insert', 'update', 'remove']).collections([schools, classes, w
var errors = [ var errors = [
["unauthorized", "Sorry, you are not authorized to complete this action."], // 0 "Success.", // 0
["unauthorized", "You have too many unverified classes right now. Try again later."], ["unauthorized", "You have too many unverified classes right now. Try again later."],
["matching", "The school you have requested does not exist."], ["matching", "The school you have requested does not exist."],
["matching", "This teacher is already teaching a class elsewhere!"], ["matching", "This teacher is already teaching a class elsewhere!"],
@ -142,7 +142,9 @@ var errors = [
["trivial", "You are already enrolled in this class."], // 15 ["trivial", "You are already enrolled in this class."], // 15
["trivial", "This request is too long."], ["trivial", "This request is too long."],
["trivial", "Not a valid work type"], ["trivial", "Not a valid work type"],
["unauthorized", "This class has not been approved yet"],
["unauthorized", "Sorry, you are not authorized to complete this action."],
["other", "Error could not be processed"] ["other", "Error could not be processed"]
]; ];
@ -160,11 +162,11 @@ function securityCheck(checklist, input) {
switch (checkpoint) { switch (checkpoint) {
// Superadmin // Superadmin
case -1: case -1:
if (!Roles.userIsInRole(Meteor.userId(), ['superadmin'])) error = 0; if (!Roles.userIsInRole(Meteor.userId(), ['superadmin'])) error = errors.length - 2;
break; break;
// Any admin // Any admin
case 1: case 1:
if (Roles.userIsInRole(Meteor.userId(), ['superadmin', 'admin'])) error = 0; if (Roles.userIsInRole(Meteor.userId(), ['superadmin', 'admin'])) error = errors.length - 2;
break; break;
// Unverified classes // Unverified classes
case 2: case 2:
@ -181,7 +183,7 @@ function securityCheck(checklist, input) {
break; break;
// Class admin // Class admin
case 5: case 5:
if (input.admin !== Meteor.userId) error = 4; if (input.admin !== Meteor.userId()) error = 4;
break; break;
// Not banned // Not banned
case 8: case 8:
@ -200,15 +202,15 @@ function securityCheck(checklist, input) {
break; break;
// Name too long // Name too long
case 11: case 11:
if (input.name > 50) error = 10; if (typeof input.name !== "string" || input.name.length > 50) error = 10;
break; break;
// Description too long // Description too long
case 12: case 12:
if (input.description > 150) error = 11; if (typeof input.description !== "string" || input.description.length > 150) error = 11;
break; break;
// Moderator or admin // Moderator of class
case 13: case 13:
if (!_.contains(input.moderators.concat(input.admin)), Meteor.userId()) error = 4; if (!_.contains(input.moderators, Meteor.userId())) error = 4;
break; break;
// Creator of work // Creator of work
case 14: case 14:
@ -216,7 +218,7 @@ function securityCheck(checklist, input) {
break; break;
// Comment too long // Comment too long
case 15: case 15:
if (input.comment > 200) error = 13; if (typeof input.comment !== "string" || input.comment > 200) error = 13;
break; break;
// Private class // Private class
case 16: case 16:
@ -224,20 +226,40 @@ function securityCheck(checklist, input) {
break; break;
// Code is wrong // Code is wrong
case 17: case 17:
if (input.code !== pass && input.privacy) error = 14; if (input.code !== input.pass && input.privacy) error = 14;
break; break;
// Check if user is already enrolled // Check if user is already enrolled
case 18: case 18:
if (_.contains(input.classes, input.classId)) error = 15; if (_.contains(input.subscribers, input.userId)) error = 15;
break; break;
// Request too long // Request too long
case 19: case 19:
if (input.content.length > 500) error = 16; if (typeof input.request !== "string" || input.request.length > 500) error = 16;
break; break;
// Is valid work type // Is valid work type
case 20: case 20:
if (!_.contains(worktype, input.type)) error = 17; if (!_.contains(worktype, input.type)) error = 17;
break; break;
// Tracking in moderators or banned
case 21:
if (!_.contains(["moderators", "banned"], input.userlist)) error = errors.length - 1;
break;
// Editing list moderators
case 22:
if (input.userlist === "moderators") error = errors.length - 2;
break;
// Toggling possible toggleWork
case 23:
if(_.contains(["confirmations", "reports", "done"], input.toggle)) error = errors.length - 1;
break;
// Class is approved
case 24:
if (!input.status) error = 18;
break;
// User is logged in
case 25:
if (Meteor.userId === null) error = errors.length - 1;
break;
} }
results.push(error); results.push(error);
} }
@ -269,44 +291,33 @@ Meteor.methods({
// Ability to create schools for selections // Ability to create schools for selections
'createSchool': function(schoolname) { 'createSchool': function(schoolname) {
if (Roles.userIsInRole(Meteor.userId(), ['superadmin', 'admin'])) { var security = securityCheck([1, true]);
if (!security) {
schools.insert({ schools.insert({
name: schoolname name: schoolname
}); });
} else { } else {
throw new Meteor.Error("unauthorized", "You are not authorized to complete this action."); throw new Meteor.Error(errors[security]);
} }
}, },
// Deletes school // Deletes school
'deleteSchool': function(schoolId) { 'deleteSchool': function(schoolId) {
if (Roles.userIsInRole(Meteor.userId(), ['superadmin', 'admin'])) { var security = securityCheck([1, true]);
if (!security) {
schools.remove({ schools.remove({
_id: schoolId _id: schoolId
}); });
} else { } else {
throw new Meteor.Error("unauthorized", "You are not authorized to complete this action."); throw new Meteor.Error(errors[security]);
} }
}, },
// Class Functions // Class Functions
'createClass': function(input) { 'createClass': function(input) {
classes.schema.validate(input); classes.schema.validate(input);
if (Meteor.user() && var security = securityCheck([2, 3, 4, true],
classes.find({ input);
status: false, if (!security) {
admin: Meteor.userId()
}).fetch().length < 5 &&
schools.findOne({
name: input.school
})) {
if (classes.find({
status: true,
privacy: false,
teacher: input.teacher,
hour: input.hour
}).fetch().length < 1 ||
input.teacher === "" ||
input.hour === "") {
input.status = Roles.userIsInRole(Meteor.userId(), ['superadmin', 'admin']); input.status = Roles.userIsInRole(Meteor.userId(), ['superadmin', 'admin']);
input.admin = Meteor.userId(); input.admin = Meteor.userId();
Meteor.call('genCode', function(error, result) { Meteor.call('genCode', function(error, result) {
@ -323,15 +334,12 @@ Meteor.methods({
Meteor.call('joinClass', [result, input.code]); Meteor.call('joinClass', [result, input.code]);
}); });
} else { } else {
throw new Meteor.Error("overlap", "This teacher is already teaching a class elsewhere!"); throw new Meteor.Error(errors[security]);
}
} else {
throw new Meteor.Error("unauthorized", "You are not authorized to complete this action.");
} }
}, },
'approveClass': function(classId) { 'approveClass': function(classId) {
if (Roles.userIsInRole(Meteor.userId(), ['superadmin', 'admin'])) { var security = securityCheck([1, true]);
if (!security) {
var currentclass = classes.findOne({ var currentclass = classes.findOne({
_id: classId _id: classId
}); });
@ -343,6 +351,8 @@ Meteor.methods({
status: !currentclass.status status: !currentclass.status
} }
}); });
} else {
throw new Meteor.Error(errors[security]);
} }
}, },
// For class admins to get code // For class admins to get code
@ -350,10 +360,11 @@ Meteor.methods({
var foundclass = classes.findOne({ var foundclass = classes.findOne({
_id: classId _id: classId
}); });
if (foundclass !== undefined && foundclass.admin === Meteor.userId()) { var security = securityCheck([5, true], foundclass);
if (!security) {
return (foundclass.code === '') ? "None" : foundclass.code; return (foundclass.code === '') ? "None" : foundclass.code;
} else { } else {
throw new Meteor.Error("unauthorized", "You are not authorized to complete this action."); throw new Meteor.Error(errors[security]);
} }
}, },
'changeAdmin': function(input) { 'changeAdmin': function(input) {
@ -365,12 +376,9 @@ Meteor.methods({
var foundclass = classes.find({ var foundclass = classes.find({
_id: classId _id: classId
}); });
if (Roles.userIsInRole(Meteor.userId(), ['superadmin', 'admin']) || var security = securityCheck([1, [5, 8, 9, true], false],
Object.assign(foundclass || {}, {userId: found._id}));
(found && foundclass && foundclass.admin == Meteor.userId() && if (!security) {
!_.contains(foundclass.banned, userId) &&
_.contains(foundclass.subscribers, userId)
)) {
classes.update({ classes.update({
_id: classId _id: classId
}, { }, {
@ -379,51 +387,43 @@ Meteor.methods({
} }
}); });
} else { } else {
throw new Meteor.Error("unauthorized", "You are not authorized to complete this action."); throw new Meteor.Error(errors[security]);
} }
}, },
// Allows someone to manage the class // Allows someone to manage the class
'trackUserInClass': function(input) { 'trackUserInClass': function(input) {
var userId = input[0]; var userId = input[0];
var classId = input[1]; var classId = input[1];
var userlist = input[2]; var userlist = input[2];
var dowhat = input[3];
var foundclass = classes.findOne({ var foundclass = classes.findOne({
_id: classId _id: classId
}); });
classlist = foundclass[userlist]; var security = securityCheck([1, [[5, [13, 22, true], false], 9, 21, true], false],
var index = ["moderators", "banned"].indexOf(userlist); Object.assign(foundclass, {userlist: userlist}));
var set = foundclass; if (!security) {
var presence = false; if (_.contains(foundclass[userlist], userId)) {
if (dowhat) { foundclass[userlist] = _.without(foundclass[userlist], userId);
set[userlist] = set[userlist].concat(userId);
presence = true;
} else { } else {
set[userlist] = _.without(set[userlist], userId); foundclass[userlist] = foundclass[userlist].concat(userId);
} }
if (Roles.userIsInRole(Meteor.userId(), ['superadmin', 'admin']) ||
(foundclass && foundclass.admin == Meteor.userId() && index !== -1 &&
(index === 0 ^ _.contains(foundclass.moderators, Meteor.userId())) &&
(!_.contains(classlist, userId) ^ presence))) {
classes.update({ classes.update({
_id: classId _id: classId
}, { }, {
$set: set $set: foundclass
}); });
} else { } else {
throw new Meteor.Error("unauthorized", "You are not authorized to complete this action."); throw new Meteor.Error(errors[security]);
} }
}, },
'deleteClass': function(classid) { 'deleteClass': function(classid) {
var found = classes.findOne({ var found = classes.findOne({
_id: classid _id: classid
}); });
if (Meteor.user() && found && var security = securityCheck([1, 5, false],
(found.admin === Meteor.user()._id || Roles.userIsInRole(Meteor.userId(), ['superadmin', 'admin']))) { found);
if (!security) {
for (var i = 0; i < found.subscribers.length; i++) { for (var i = 0; i < found.subscribers.length; i++) {
var current = Meteor.users.findOne({ var current = Meteor.users.findOne({
_id: found.subscribers[i] _id: found.subscribers[i]
@ -442,7 +442,7 @@ Meteor.methods({
_id: classid _id: classid
}); });
} else { } else {
throw new Meteor.Error("unauthorized", "You are not authorized to complete this action."); throw new Meteor.Error(errors[security]);
} }
}, },
@ -464,27 +464,15 @@ Meteor.methods({
}, },
'editWork': function(change) { 'editWork': function(change) {
var ref = new Date();
ref.setHours(0, 0, 0, 0);
ref = ref.getTime();
var currentwork = work.findOne({ var currentwork = work.findOne({
_id: change._id _id: change._id
}); });
var currentclass = classes.findOne({ var currentclass = classes.findOne({
_id: currentwork.class _id: currentwork.class
}); });
if (Roles.userIsInRole(Meteor.userId(), ['superadmin', 'admin'])) { var security = securityCheck([[1, 16, 13, 5, false], 11, 12, 10, 20, true],
work.update({ Object.assign(currentclass, currentwork, {description: change.description, name: change.name, dueDate: change.dueDate, type: change.type}));
_id: currentwork._id if (!security) {
}, {
$set: change
});
} else if ((currentwork.class === Meteor.userId() ||
_.contains(currentclass.moderators.concat(currentclass.admin), Meteor.userId()) ||
Meteor.userId() === currentwork.creator) &&
change.name.length <= 50 && change.description.length <= 150 &&
change.dueDate instanceof Date && change.dueDate.getTime() >= ref &&
_.contains(worktype, change.type)) {
work.update({ work.update({
_id: change._id _id: change._id
}, { }, {
@ -497,7 +485,7 @@ Meteor.methods({
} }
}); });
} else { } else {
throw new Meteor.Error("unauthorized", "You are not authorized to complete this action."); throw new Meteor.Error(errors[security]);
} }
}, },
'addComment': function(input) { 'addComment': function(input) {
@ -509,10 +497,9 @@ Meteor.methods({
_id: workobject.class _id: workobject.class
}); });
var user = Meteor.userId(); var user = Meteor.userId();
if (typeof comment === "string" && comment.length <= 200 && var security = securityCheck([15, [16, [8, 9, true], false]],
(workobject.class === Meteor.userId() || Object.assign(workobject, currentclass, {userId: Meteor.userId(), comment: comment}));
(_.contains(currentclass.subscribers, Meteor.userId()) && if (!security) {
!_.contains(currentclass.banned, Meteor.userId())))) {
var commentInfo = { var commentInfo = {
"comment": input[0], "comment": input[0],
"user": user, "user": user,
@ -527,7 +514,7 @@ Meteor.methods({
} }
}); });
} else { } else {
throw new Meteor.Error("unauthorized", "You are not authorized to complete this action."); throw new Meteor.Error(errors[security]);
} }
}, },
@ -538,7 +525,9 @@ Meteor.methods({
var currentclass = classes.findOne({ var currentclass = classes.findOne({
_id: workobject.class _id: workobject.class
}); });
if ((Meteor.userId() === workobject.class || _.contains(currentclass.subscribers, Meteor.userId())) && _.contains(["confirmations", "reports", "done"], input[1])) { var security = securityCheck([[16, 9, false], 23],
Object.assign(workobject, currentclass, {userId: Meteor.userId(), toggle: input[1]}));
if (!security) {
var userindex = workobject[input[1]].indexOf(Meteor.userId()); var userindex = workobject[input[1]].indexOf(Meteor.userId());
if (userindex === -1) { if (userindex === -1) {
workobject[input[1]] = workobject[input[1]].concat(Meteor.userId()); workobject[input[1]] = workobject[input[1]].concat(Meteor.userId());
@ -558,7 +547,7 @@ Meteor.methods({
$set: workobject $set: workobject
}); });
} else { } else {
throw new Meteor.Error("unauthorized", "You are not authorized to complete this action."); throw new Meteor.Error(errors[security]);
} }
}, },
'deleteWork': function(workId) { 'deleteWork': function(workId) {
@ -568,14 +557,13 @@ Meteor.methods({
var currentclass = classes.findOne({ var currentclass = classes.findOne({
_id: currentwork.class _id: currentwork.class
}); });
if (Roles.userIsInRole(Meteor.userId(), ['superadmin', 'admin']) || var security = securityCheck([1, 16, 13, 5]);
currentwork.class === Meteor.userId() || if (!security) {
_.contains(currentclass.moderators.concat(currentclass.admin), Meteor.userId()) || Meteor.userId() === currentwork.class) {
work.remove({ work.remove({
_id: workId _id: workId
}); });
} else { } else {
throw new Meteor.Error("unauthorized", "You are not authorized to complete this action."); throw new Meteor.Error(errors[security]);
} }
}, },
@ -596,7 +584,7 @@ Meteor.methods({
if (current.description && current.description.length > 50) { if (current.description && current.description.length > 50) {
current.description = current.description.slice(0, 50); current.description = current.description.slice(0, 50);
} }
if (current.grade <= refyear || current.grade >= refyear + 4) { if ((current.grade <= refyear || current.grade >= refyear + 4) && current.grade != "Faculty") {
current.grade = refyear; current.grade = refyear;
} }
Meteor.users.update({ Meteor.users.update({
@ -620,7 +608,7 @@ Meteor.methods({
} }
}); });
} else { } else {
throw new Meteor.Error("unauthorized", "You are not authorized to complete this action."); throw new Meteor.Error(errors[errors.length - 1]);
} }
}, },
'createProfile': function(userId) { 'createProfile': function(userId) {
@ -654,15 +642,12 @@ Meteor.methods({
'joinClass': function(input) { 'joinClass': function(input) {
var change = input[0]; var change = input[0];
var pass = input[1]; var pass = input[1];
var prof = Meteor.user().profile;
var found = classes.findOne({ var found = classes.findOne({
_id: change _id: change
}); });
if (Meteor.user() !== null && var security = securityCheck([17, [5, 24, false], 18, true],
found !== null && Object.assign(found, {userId: Meteor.userId(), pass: pass}));
(pass === found.code || found.privacy === false) && if (!security) {
(found.status || found.admin === Meteor.userId()) &&
!_.contains(prof.classes, change)) {
var foundsubs = found.subscribers; var foundsubs = found.subscribers;
classes.update({ classes.update({
_id: found._id _id: found._id
@ -682,7 +667,7 @@ Meteor.methods({
}); });
return true; return true;
} else { } else {
throw new Meteor.Error("unauthorized", "You are not authorized to complete this action."); throw new Meteor.Error(errors[security]);
} }
}, },
'joinPrivateClass': function(input) { 'joinPrivateClass': function(input) {
@ -711,7 +696,7 @@ Meteor.methods({
}); });
return true; return true;
} else { } else {
throw new Meteor.Error("unauthorized", "You are not authorized to complete this action."); throw new Meteor.Error(errors[14]);
} }
}, },
'leaveClass': function(change) { 'leaveClass': function(change) {
@ -740,34 +725,37 @@ Meteor.methods({
subscribers: newstudents subscribers: newstudents
} }
}); });
return true;
} else { } else {
throw new Meteor.Error("unauthorized", "You are currently the admin of this class. Transfer ownership in order to leave this class."); throw new Meteor.Error("unauthorized", "You are currently the admin of this class. Transfer ownership in order to leave this class.");
} }
} }
} else { } else {
throw new Meteor.Error("unauthorized", "You are not authorized to complete this action."); throw new Meteor.Error(errors[errors.length - 1]);
} }
}, },
// Admin Functions // Admin Functions
'createAdmin': function(userId) { 'createAdmin': function(userId) {
if (Roles.userIsInRole(Meteor.user()._id, ['superadmin'])) { var security = securityCheck([-1, true]);
if (!security) {
Roles.addUsersToRoles(userId, ['admin']); Roles.addUsersToRoles(userId, ['admin']);
} else { } else {
throw new Meteor.Error("unauthorized", "You are not authorized to complete this action."); throw new Meteor.Error(errors[security]);
} }
}, },
'deleteAdmin': function(userId) { 'deleteAdmin': function(userId) {
if (Roles.userIsInRole(Meteor.user()._id, ['superadmin'])) { var security = securityCheck([-1, true]);
if (!security) {
Roles.removeUsersToRoles(userId, ['admin']); Roles.removeUsersToRoles(userId, ['admin']);
} else { } else {
throw new Meteor.Error("unauthorized", "You are not authorized to complete this action."); throw new Meteor.Error(errors[security]);
} }
}, },
'createRequest': function(request) { 'createRequest': function(request) {
if (request.content.length <= 500 && Meteor.userId() !== null) { var security = securityCheck([19, 25, true],
request);
if (!security) {
requests.insert({ requests.insert({
requestor: Meteor.userId(), requestor: Meteor.userId(),
request: request.content, request: request.content,
@ -775,16 +763,17 @@ Meteor.methods({
timeRequested: new Date() timeRequested: new Date()
}); });
} else { } else {
throw new Meteor.Error("unauthorized", "You are not authorized to complete this action."); throw new Meteor.Error(errors[security]);
} }
}, },
'deleteRequest': function(requestId) { 'deleteRequest': function(requestId) {
if (Roles.userIsInRole(Meteor.userId(), ['superadmin', 'admin'])) { var security = securityCheck([1, true]);
if (!security) {
requests.remove({ requests.remove({
_id: requestId _id: requestId
}); });
} else { } else {
throw new Meteor.Error("unauthorized", "You are not authorized to complete this action."); throw new Meteor.Error(errors[security]);
} }
} }
}); });