Deleted bookshelf access plugin

refs #9127

- permission checks can happen everywhere in the code base
  - we would like to create a context class
- global access to `options.context.is(...)`
- please read more about the access plugin in #9127 section "Model layer and the access plugin".
- removed the plugin and use direct context checks
This commit is contained in:
kirrg001 2018-01-25 17:54:28 +01:00
parent 20d1f86fb6
commit fe461da110
8 changed files with 18 additions and 119 deletions

View File

@ -30,9 +30,6 @@ ghostBookshelf = bookshelf(db.knex);
// Load the Bookshelf registry plugin, which helps us avoid circular dependencies
ghostBookshelf.plugin('registry');
// Load the Ghost access rules plugin, which handles passing permissions/context through the model layer
ghostBookshelf.plugin(plugins.accessRules);
// Load the Ghost filter plugin, which handles applying a 'filter' to findPage requests
ghostBookshelf.plugin(plugins.filter);

View File

@ -1,50 +0,0 @@
// # Access Rules
//
// Extends Bookshelf.Model.forge to take a 'context' option which provides information on how this query should
// be treated in terms of data access rules - currently just detecting public requests
module.exports = function (Bookshelf) {
var model = Bookshelf.Model,
Model;
Model = Bookshelf.Model.extend({
/**
* Cached copy of the context setup for this model instance
*/
_context: null,
/**
* ## Is Public Context?
* A helper to determine if this is a public request or not
* @returns {boolean}
*/
isPublicContext: function isPublicContext() {
return !!(this._context && this._context.public);
},
isInternalContext: function isInternalContext() {
return !!(this._context && this._context.internal);
}
},
{
/**
* ## Forge
* Ensure that context gets set as part of the forge
*
* @param {object} attributes
* @param {object} options
* @returns {Bookshelf.Model} model
*/
forge: function forge(attributes, options) {
var self = model.forge.apply(this, arguments);
if (options && options.context) {
self._context = options.context;
delete options.context;
}
return self;
}
});
Bookshelf.Model = Model;
};

View File

@ -145,8 +145,8 @@ filter = function filter(Bookshelf) {
options = options || {};
this._filters = filterUtils.combineFilters(
this.enforcedFilters(),
this.defaultFilters(),
this.enforcedFilters(options),
this.defaultFilters(options),
options.filter,
options.where
);

View File

@ -9,7 +9,7 @@ module.exports = function (Bookshelf) {
countQueryBuilder = {
tags: {
posts: function addPostCountToTags(model) {
posts: function addPostCountToTags(model, options) {
model.query('columns', 'tags.*', function (qb) {
qb.count('posts.id')
.from('posts')
@ -17,7 +17,7 @@ module.exports = function (Bookshelf) {
.whereRaw('posts_tags.tag_id = tags.id')
.as('count__posts');
if (model.isPublicContext()) {
if (options.context && options.context.public) {
// @TODO use the filter behavior for posts
qb.andWhere('posts.page', '=', false);
qb.andWhere('posts.status', '=', 'published');
@ -26,14 +26,14 @@ module.exports = function (Bookshelf) {
}
},
users: {
posts: function addPostCountToTags(model) {
posts: function addPostCountToTags(model, options) {
model.query('columns', 'users.*', function (qb) {
qb.count('posts.id')
.from('posts')
.whereRaw('posts.author_id = users.id')
.as('count__posts');
if (model.isPublicContext()) {
if (options.context && options.context.public) {
// @TODO use the filter behavior for posts
qb.andWhere('posts.page', '=', false);
qb.andWhere('posts.status', '=', 'published');
@ -56,7 +56,7 @@ module.exports = function (Bookshelf) {
options.withRelated = _.pull([].concat(options.withRelated), 'count.posts');
// Call the query builder
countQueryBuilder[tableName].posts(this);
countQueryBuilder[tableName].posts(this, options);
}
},
fetch: function () {

View File

@ -1,5 +1,4 @@
module.exports = {
accessRules: require('./access-rules'),
filter: require('./filter'),
includeCount: require('./include-count'),
pagination: require('./pagination'),

View File

@ -401,15 +401,15 @@ Post = ghostBookshelf.Model.extend({
return attrs;
},
enforcedFilters: function enforcedFilters() {
return this.isPublicContext() ? 'status:published' : null;
enforcedFilters: function enforcedFilters(options) {
return options.context && options.context.public ? 'status:published' : null;
},
defaultFilters: function defaultFilters() {
if (this.isInternalContext()) {
defaultFilters: function defaultFilters(options) {
if (options.context && options.context.internal) {
return null;
}
return this.isPublicContext() ? 'page:false' : 'page:false+status:published';
return options.context && options.context.public ? 'page:false' : 'page:false+status:published';
}
}, {
allowedFormats: ['mobiledoc', 'html', 'plaintext', 'amp'],

View File

@ -261,20 +261,20 @@ User = ghostBookshelf.Model.extend({
});
},
enforcedFilters: function enforcedFilters() {
if (this.isInternalContext()) {
enforcedFilters: function enforcedFilters(options) {
if (options.context && options.context.internal) {
return null;
}
return this.isPublicContext() ? 'status:[' + allStates.join(',') + ']' : null;
return options.context && options.context.public ? 'status:[' + allStates.join(',') + ']' : null;
},
defaultFilters: function defaultFilters() {
if (this.isInternalContext()) {
defaultFilters: function defaultFilters(options) {
if (options.context && options.context.internal) {
return null;
}
return this.isPublicContext() ? null : 'status:[' + allStates.join(',') + ']';
return options.context && options.context.public ? null : 'status:[' + allStates.join(',') + ']';
}
}, {
orderDefaultOptions: function orderDefaultOptions() {

View File

@ -1,47 +0,0 @@
var should = require('should'), // jshint ignore:line
sinon = require('sinon'),
// Thing we're testing
models = require('../../../../server/models'),
ghostBookshelf,
sandbox = sinon.sandbox.create();
describe('Access Rules', function () {
beforeEach(function () {
models.init();
ghostBookshelf = models.Base;
});
afterEach(function () {
sandbox.restore();
});
describe('Base Model', function () {
it('should assign isPublicContext to prototype', function () {
ghostBookshelf.Model.prototype.isPublicContext.should.be.a.Function();
});
it('should get called when a model is forged', function () {
ghostBookshelf.Model.forge(null, {context: 'test'})._context.should.eql('test');
});
describe('isPublicContext', function () {
it('should isPublicContext false if no context is set', function () {
ghostBookshelf.Model.forge().isPublicContext().should.be.false();
});
it('should return false if context has no `public` property', function () {
ghostBookshelf.Model.forge(null, {context: 'test'}).isPublicContext().should.be.false();
});
it('should return false if context.public is false', function () {
ghostBookshelf.Model.forge(null, {context: {public: false}}).isPublicContext().should.be.false();
});
it('should return true if context.public is true', function () {
ghostBookshelf.Model.forge(null, {context: {public: true}}).isPublicContext().should.be.true();
});
});
});
});