0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-06 22:40:14 -05:00

Add apps permissable checks in posts and users

Closes #2738

- Re-introduce the TargetModel.permissable interface check in the
regular permission flow path
- Pass loadedPermissions, hasUserPermission and hasAppPermission to
permissable interface to reduce logic necessary
- Refactor recursive call to pass original arguments but with actual
model
- Refactor canThis(this.user) use in api/posts.js to just canThis(this)
This commit is contained in:
Jacob Gable 2014-05-13 20:49:07 -05:00
parent cdb98241cf
commit 0dc6dc29a7
4 changed files with 42 additions and 23 deletions

View file

@ -82,7 +82,7 @@ posts = {
var self = this, var self = this,
include; include;
return canThis(self.user).edit.post(postData.id).then(function () { return canThis(this).edit.post(postData.id).then(function () {
return checkPostData(postData).then(function (checkedPostData) { return checkPostData(postData).then(function (checkedPostData) {
if (postData.include) { if (postData.include) {
@ -115,7 +115,7 @@ posts = {
include; include;
// **returns:** a promise for the resulting post in a json object // **returns:** a promise for the resulting post in a json object
return canThis(this.user).create.post().then(function () { return canThis(this).create.post().then(function () {
return checkPostData(postData).then(function (checkedPostData) { return checkPostData(postData).then(function (checkedPostData) {
if (postData.include) { if (postData.include) {
include = prepareInclude(postData.include); include = prepareInclude(postData.include);
@ -141,7 +141,7 @@ posts = {
destroy: function destroy(args) { destroy: function destroy(args) {
var self = this; var self = this;
// **returns:** a promise for a json response with the id of the deleted post // **returns:** a promise for a json response with the id of the deleted post
return canThis(this.user).remove.post(args.id).then(function () { return canThis(this).remove.post(args.id).then(function () {
// TODO: Would it be good to get rid of .call()? // TODO: Would it be good to get rid of .call()?
return posts.read.call({user: self.user}, {id : args.id, status: 'all'}).then(function (result) { return posts.read.call({user: self.user}, {id : args.id, status: 'all'}).then(function (result) {
return dataProvider.Post.destroy(args.id).then(function () { return dataProvider.Post.destroy(args.id).then(function () {
@ -165,7 +165,7 @@ posts = {
// **takes:** a string to generate the slug from // **takes:** a string to generate the slug from
generateSlug: function generateSlug(args) { generateSlug: function generateSlug(args) {
return canThis(this.user).slug.post().then(function () { return canThis(this).slug.post().then(function () {
return dataProvider.Base.Model.generateSlug(dataProvider.Post, args.title, {status: 'all'}).then(function (slug) { return dataProvider.Base.Model.generateSlug(dataProvider.Post, args.title, {status: 'all'}).then(function (slug) {
if (slug) { if (slug) {
return slug; return slug;

View file

@ -473,21 +473,31 @@ Post = ghostBookshelf.Model.extend({
}); });
}, },
permissable: function (postModelOrId, context) { permissable: function (postModelOrId, context, loadedPermissions, hasUserPermission, hasAppPermission) {
var self = this, var self = this,
userId = context.user, postModel = postModelOrId,
postModel = postModelOrId; origArgs;
// If we passed in an id instead of a model, get the model // If we passed in an id instead of a model, get the model
// then check the permissions // then check the permissions
if (_.isNumber(postModelOrId) || _.isString(postModelOrId)) { if (_.isNumber(postModelOrId) || _.isString(postModelOrId)) {
// Grab the original args without the first one
origArgs = _.toArray(arguments).slice(1);
// Get the actual post model
return this.findOne({id: postModelOrId, status: 'all'}).then(function (foundPostModel) { return this.findOne({id: postModelOrId, status: 'all'}).then(function (foundPostModel) {
return self.permissable(foundPostModel, context); // Build up the original args but substitute with actual model
var newArgs = [foundPostModel].concat(origArgs);
return self.permissable.apply(self, newArgs);
}, errors.logAndThrowError); }, errors.logAndThrowError);
} }
// If this is the author of the post, allow it. if (postModel) {
if (postModel && userId === postModel.get('author_id')) { // If this is the author of the post, allow it.
hasUserPermission = hasUserPermission || context.user === postModel.get('author_id');
}
if (hasUserPermission && hasAppPermission) {
return when.resolve(); return when.resolve();
} }

View file

@ -172,23 +172,34 @@ User = ghostBookshelf.Model.extend({
}, },
permissable: function (userModelOrId, context) { permissable: function (userModelOrId, context, loadedPermissions, hasUserPermission, hasAppPermission) {
var self = this, var self = this,
userId = context.user, userModel = userModelOrId,
userModel = userModelOrId; origArgs;
// If we passed in an id instead of a model, get the model // If we passed in an id instead of a model, get the model
// then check the permissions // then check the permissions
if (_.isNumber(userModelOrId) || _.isString(userModelOrId)) { if (_.isNumber(userModelOrId) || _.isString(userModelOrId)) {
// Grab the original args without the first one
origArgs = _.toArray(arguments).slice(1);
// Get the actual post model
return this.findOne({id: userModelOrId}).then(function (foundUserModel) { return this.findOne({id: userModelOrId}).then(function (foundUserModel) {
return self.permissable(foundUserModel, context); // Build up the original args but substitute with actual model
var newArgs = [foundUserModel].concat(origArgs);
return self.permissable.apply(self, newArgs);
}, errors.logAndThrowError); }, errors.logAndThrowError);
} }
// If this is the same user that requests the operation allow it. if (userModel) {
if (userModel && userId === userModel.get('id')) { // If this is the same user that requests the operation allow it.
hasUserPermission = hasUserPermission || context.user === userModel.get('id');
}
if (hasUserPermission && hasAppPermission) {
return when.resolve(); return when.resolve();
} }
return when.reject(); return when.reject();
}, },

View file

@ -120,16 +120,14 @@ CanThisResult.prototype.buildObjectTypeHandlers = function (obj_types, act_type,
hasAppPermission = _.any(appPermissions, checkPermission); hasAppPermission = _.any(appPermissions, checkPermission);
} }
// Offer a chance for the TargetModel to override the results
if (TargetModel && _.isFunction(TargetModel.permissable)) {
return TargetModel.permissable(modelId, context, loadedPermissions, hasUserPermission, hasAppPermission);
}
if (hasUserPermission && hasAppPermission) { if (hasUserPermission && hasAppPermission) {
return when.resolve(); return when.resolve();
} }
return when.reject();
}).otherwise(function () {
// Check for special permissions on the model directly
if (TargetModel && _.isFunction(TargetModel.permissable)) {
return TargetModel.permissable(modelId, context);
}
return when.reject(); return when.reject();
}); });
}; };