mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-22 10:21:36 +03:00
273e220327
refs 829e8ed010
- i18n is used everywhere but only requires shared or external packages, therefore it's a good candidate for living in shared
- this reduces invalid requires across frontend and server, and lets us use it everywhere until we come up with a better option
113 lines
4.2 KiB
JavaScript
113 lines
4.2 KiB
JavaScript
const debug = require('ghost-ignition').debug('api:canary:utils:permissions');
|
|
const Promise = require('bluebird');
|
|
const _ = require('lodash');
|
|
const permissions = require('../../../services/permissions');
|
|
const i18n = require('../../../../shared/i18n');
|
|
const errors = require('@tryghost/errors');
|
|
|
|
/**
|
|
* @description Handle requests, which need authentication.
|
|
*
|
|
* @param {Object} apiConfig - Docname & method of API ctrl
|
|
* @param {Object} frame
|
|
* @return {Promise}
|
|
*/
|
|
const nonePublicAuth = (apiConfig, frame) => {
|
|
debug('check admin permissions');
|
|
|
|
let singular;
|
|
if (apiConfig.docName.match(/ies$/)) {
|
|
singular = apiConfig.docName.replace(/ies$/, 'y');
|
|
} else {
|
|
singular = apiConfig.docName.replace(/s$/, '');
|
|
}
|
|
let permissionIdentifier = frame.options.id;
|
|
|
|
// CASE: Target ctrl can override the identifier. The identifier is the unique identifier of the target resource
|
|
// e.g. edit a setting -> the key of the setting
|
|
// e.g. edit a post -> post id from url param
|
|
// e.g. change user password -> user id inside of the body structure
|
|
if (apiConfig.identifier) {
|
|
permissionIdentifier = apiConfig.identifier(frame);
|
|
}
|
|
|
|
let unsafeAttrObject = apiConfig.unsafeAttrs && _.has(frame, `data.[${apiConfig.docName}][0]`) ? _.pick(frame.data[apiConfig.docName][0], apiConfig.unsafeAttrs) : {};
|
|
|
|
if (apiConfig.unsafeAttrsObject) {
|
|
unsafeAttrObject = apiConfig.unsafeAttrsObject(frame);
|
|
}
|
|
|
|
const permsPromise = permissions.canThis(frame.options.context)[apiConfig.method][singular](permissionIdentifier, unsafeAttrObject);
|
|
|
|
return permsPromise.then((result) => {
|
|
/*
|
|
* Allow the permissions function to return a list of excluded attributes.
|
|
* If it does, omit those attrs from the data passed through
|
|
*
|
|
* NOTE: excludedAttrs differ from unsafeAttrs in that they're determined by the model's permissible function,
|
|
* and the attributes are simply excluded rather than throwing a NoPermission exception
|
|
*
|
|
* TODO: This is currently only needed because of the posts model and the contributor role. Once we extend the
|
|
* contributor role to be able to edit existing tags, this concept can be removed.
|
|
*/
|
|
if (result && result.excludedAttrs && _.has(frame, `data.[${apiConfig.docName}][0]`)) {
|
|
frame.data[apiConfig.docName][0] = _.omit(frame.data[apiConfig.docName][0], result.excludedAttrs);
|
|
}
|
|
}).catch((err) => {
|
|
if (err instanceof errors.NoPermissionError) {
|
|
err.message = i18n.t('errors.api.utils.noPermissionToCall', {
|
|
method: apiConfig.method,
|
|
docName: apiConfig.docName
|
|
});
|
|
return Promise.reject(err);
|
|
}
|
|
|
|
if (errors.utils.isIgnitionError(err)) {
|
|
return Promise.reject(err);
|
|
}
|
|
|
|
return Promise.reject(new errors.GhostError({
|
|
err: err
|
|
}));
|
|
});
|
|
};
|
|
|
|
// @TODO: https://github.com/TryGhost/Ghost/issues/10735
|
|
module.exports = {
|
|
/**
|
|
* @description Handle permission stage for canary API.
|
|
*
|
|
* @param {Object} apiConfig - Docname & method of target ctrl.
|
|
* @param {Object} frame
|
|
* @return {Promise}
|
|
*/
|
|
handle(apiConfig, frame) {
|
|
debug('handle');
|
|
|
|
// @TODO: https://github.com/TryGhost/Ghost/issues/10099
|
|
frame.options.context = permissions.parseContext(frame.options.context);
|
|
|
|
// CASE: Content API access
|
|
if (frame.options.context.public) {
|
|
debug('check content permissions');
|
|
|
|
// @TODO: Remove when we drop v0.1
|
|
// @TODO: https://github.com/TryGhost/Ghost/issues/10733
|
|
return permissions.applyPublicRules(apiConfig.docName, apiConfig.method, {
|
|
status: frame.options.status,
|
|
id: frame.options.id,
|
|
uuid: frame.options.uuid,
|
|
slug: frame.options.slug,
|
|
data: {
|
|
status: frame.data.status,
|
|
id: frame.data.id,
|
|
uuid: frame.data.uuid,
|
|
slug: frame.data.slug
|
|
}
|
|
});
|
|
}
|
|
|
|
return nonePublicAuth(apiConfig, frame);
|
|
}
|
|
};
|