Ghost/core/server/services/permissions/public.js
Katharina Irrgang 9d7c3bd726
🐛 Fixed all known filter limitations (#10159)
refs #10105, closes #10108, closes https://github.com/TryGhost/Ghost/issues/9950, refs https://github.com/TryGhost/Ghost/issues/9923, refs https://github.com/TryGhost/Ghost/issues/9916, refs https://github.com/TryGhost/Ghost/issues/9574, refs https://github.com/TryGhost/Ghost/issues/6345, refs https://github.com/TryGhost/Ghost/issues/6309, refs https://github.com/TryGhost/Ghost/issues/6158, refs https://github.com/TryGhost/GQL/issues/16

- removed GQL dependency
- replaced GQL with our brand new NQL implementation
- fixed all known filter limitations
- GQL suffered from some underlying filter bugs, which NQL tried to fix
- the bugs were mostly in how we query the database for relation filtering
- the underlying problem was caused by a too simple implementation of querying the relations
- mongo-knex has implemented a more robust and complex filtering mechanism for relations
- replaced logic in our bookshelf filter plugin
- we pass the custom, default and override filters from Ghost to NQL, which then are getting parsed and merged into a mongo JSON object. The mongo JSON is getting attached by mongo-knex.

NQL: https://github.com/NexesJS/NQL
mongo-knex: https://github.com/NexesJS/mongo-knex
2018-12-11 11:53:40 +01:00

73 lines
2.3 KiB
JavaScript

var _ = require('lodash'),
Promise = require('bluebird'),
common = require('../../lib/common'),
parseContext = require('./parse-context'),
_private = {};
/**
* @TODO:
*
* - remove if we drop `extraFilters` (see e.g. post model)
* - we currently accept `?status={value}` in the API
* - we currently accept `?staticPages={value}` in the API
* - but instead people should use the `?filter=status:{value}`
*
* This function protects against:
*
* - public context cannot fetch draft/scheduled posts
*/
_private.applyStatusRules = function applyStatusRules(docName, method, opts) {
var err = new common.errors.NoPermissionError({message: common.i18n.t('errors.permissions.applyStatusRules.error', {docName: docName})});
// Enforce status 'active' for users
if (docName === 'users') {
if (!opts.status) {
return 'all';
}
}
// Enforce status 'published' for posts
if (docName === 'posts') {
if (!opts.status) {
return 'published';
} else if (
method === 'read'
&& (opts.status === 'draft' || opts.status === 'all')
&& _.isString(opts.uuid) && _.isUndefined(opts.id) && _.isUndefined(opts.slug)
) {
// public read requests can retrieve a draft, but only by UUID
return opts.status;
} else if (opts.status !== 'published') {
// any other parameter would make this a permissions error
throw err;
}
}
return opts.status;
};
/**
* API Public Permission Rules
* This method enforces the rules for public requests
* @param {String} docName
* @param {String} method (read || browse)
* @param {Object} options
* @returns {Object} options
*/
module.exports = function applyPublicRules(docName, method, options) {
try {
// If this is a public context
if (parseContext(options.context).public === true) {
if (method === 'browse') {
options.status = _private.applyStatusRules(docName, method, options);
} else if (method === 'read') {
options.data.status = _private.applyStatusRules(docName, method, options.data);
}
}
return Promise.resolve(options);
} catch (err) {
return Promise.reject(err);
}
};