better access control for challenges

This commit is contained in:
Matteo Pagliazzi
2016-01-15 15:29:50 +01:00
parent e0b10d44ca
commit 50a85337a7
2 changed files with 24 additions and 8 deletions

View File

@@ -100,9 +100,9 @@ api.getChallenges = {
async handler (req, res) {
let user = res.locals.user;
let groups = user.guilds || [];
let groups = user.guilds.slice(0); // slice is used to clone the array so we don't modify it directly
if (user.party._id) groups.push(user.party._id);
groups.push('habitrpg'); // Public challenges
groups.push('habitrpg'); // tavern challenges
let challenges = await Challenge.find({
$or: [
@@ -143,11 +143,9 @@ api.getChallenge = {
let user = res.local.user;
let challengeId = req.params.challengeId;
let challenge = await Challenge.findOne({_id: challengeId}).exec(); // TODO populate
let challenge = await Challenge.findById(challengeId).exec();
// If the challenge does not exist, or if it exists but user is not a member, not the leader and not an admin -> throw error
// TODO support challenges in groups I'm a member of
if (!challenge || (user.challenges.indexOf(challengeId) === -1 && challenge.leader !== user._id && !user.contributor.admin)) { // eslint-disable-line no-extra-parens
if (!challenge || !challenge.hasAccess(user)) {
throw new NotFound(res.t('challengeNotFound'));
}
@@ -233,7 +231,7 @@ api.deleteChallenge = {
let challenge = await Challenge.findOne({_id: req.params.challengeId}).exec();
if (!challenge) throw new NotFound(res.t('challengeNotFound'));
if (challenge.leader !== user._id && !user.contributor.admin) throw new NotAuthorized(res.t('onlyLeaderDeleteChal'));
if (!challenge.canModify(user)) throw new NotAuthorized(res.t('onlyLeaderDeleteChal'));
res.respond(200, {});
// Close channel in background
@@ -264,7 +262,7 @@ api.selectChallengeWinner = {
let challenge = await Challenge.findOne({_id: req.params.challengeId}).exec();
if (!challenge) throw new NotFound(res.t('challengeNotFound'));
if (challenge.leader !== user._id && !user.contributor.admin) throw new NotAuthorized(res.t('onlyLeaderDeleteChal'));
if (!challenge.canModify(user)) throw new NotAuthorized(res.t('onlyLeaderDeleteChal'));
let winner = await User.findOne({_id: req.params.winnerId}).exec();
if (!winner || winner.challenges.indexOf(challenge._id) === -1) throw new NotFound(res.t('winnerNotFound', {userId: req.parama.winnerId}));

View File

@@ -31,6 +31,24 @@ schema.plugin(baseModel, {
noSet: ['_id', 'memberCount', 'challengeCount', 'tasksOrder'],
});
// Return true if user has access to the challenge
schema.methods.hasAccess = function hasAccessToChallenge (user) {
let userGroups = user.guilds.slice(0);
if (user.party._id) userGroups.push(user.party._id);
userGroups.push('habitrpg'); // tavern challenges
return this.leader === user._id || user.contributor.admin || userGroups.indexOf(this.groupId) !== -1;
};
// Return true if user is a member of the challenge
schema.methods.isMember = function isChallengeMember (user) {
return user.challenges.indexOf(this._id) !== -1;
};
// Return true if the user can modify (close, selectWinner, ...) the challenge
schema.methods.canModify = function canModifyChallenge (user) {
return user.contributor.admin || this.leader === user._id;
};
// Takes a Task document and return a plain object of attributes that can be synced to the user
function _syncableAttrs (task) {
let t = task.toObject(); // lodash doesn't seem to like _.omit on Document