mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-19 15:48:04 +01:00
better access control for challenges
This commit is contained in:
@@ -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}));
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user