Ghost/core/server/services/permissions/public.js
2021-10-12 14:46:35 +01:00

77 lines
2.3 KiB
JavaScript

const _ = require('lodash');
const Promise = require('bluebird');
const errors = require('@tryghost/errors');
const tpl = require('@tryghost/tpl');
const parseContext = require('./parse-context');
const _private = {};
const messages = {
error: 'You do not have permission to retrieve {docName} with that status'
};
/**
* @TODO:
*
* - remove if we drop `extraFilters` (see e.g. post model)
* - we currently accept `?status={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) {
const err = new errors.NoPermissionError({message: tpl(messages.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);
}
};