mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-11-28 14:03:48 +03:00
App Permissions from package.json
Progress on #2095 - Add new AppPermissions class with read() method - has default permissions to read and browse posts - uses default permissions if no package.json - uses default permissions if no ghost object in package.json - errors when reading malformed package.json - uses ghost.permissions if found in package.json
This commit is contained in:
parent
41cef386bc
commit
13d2d04c72
@ -6,6 +6,7 @@ var path = require('path'),
|
|||||||
config = require('../config'),
|
config = require('../config'),
|
||||||
AppSandbox = require('./sandbox'),
|
AppSandbox = require('./sandbox'),
|
||||||
AppDependencies = require('./dependencies'),
|
AppDependencies = require('./dependencies'),
|
||||||
|
AppPermissions = require('./permissions'),
|
||||||
loader;
|
loader;
|
||||||
|
|
||||||
// Get the full path to an app by name
|
// Get the full path to an app by name
|
||||||
@ -48,9 +49,21 @@ loader = {
|
|||||||
// Load a app and return the instantiated app
|
// Load a app and return the instantiated app
|
||||||
installAppByName: function (name) {
|
installAppByName: function (name) {
|
||||||
// Install the apps dependendencies first
|
// Install the apps dependendencies first
|
||||||
var deps = new AppDependencies(getAppAbsolutePath(name));
|
var appPath = getAppAbsolutePath(name),
|
||||||
return deps.install().then(function () {
|
deps = new AppDependencies(appPath);
|
||||||
var app = getAppByName(name);
|
|
||||||
|
return deps.install()
|
||||||
|
.then(function () {
|
||||||
|
// Load app permissions
|
||||||
|
var perms = new AppPermissions(appPath);
|
||||||
|
|
||||||
|
return perms.read().otherwise(function (err) {
|
||||||
|
// Provide a helpful error about which app
|
||||||
|
return when.reject(new Error("Error loading app named " + name + "; problem reading permissions: " + err.message));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.then(function (appPerms) {
|
||||||
|
var app = getAppByName(name, appPerms);
|
||||||
|
|
||||||
// Check for an install() method on the app.
|
// Check for an install() method on the app.
|
||||||
if (!_.isFunction(app.install)) {
|
if (!_.isFunction(app.install)) {
|
||||||
@ -68,7 +81,10 @@ loader = {
|
|||||||
|
|
||||||
// Activate a app and return it
|
// Activate a app and return it
|
||||||
activateAppByName: function (name) {
|
activateAppByName: function (name) {
|
||||||
var app = getAppByName(name);
|
var perms = new AppPermissions(getAppAbsolutePath(name));
|
||||||
|
|
||||||
|
return perms.read().then(function (appPerms) {
|
||||||
|
var app = getAppByName(name, appPerms);
|
||||||
|
|
||||||
// Check for an activate() method on the app.
|
// Check for an activate() method on the app.
|
||||||
if (!_.isFunction(app.activate)) {
|
if (!_.isFunction(app.activate)) {
|
||||||
@ -80,6 +96,7 @@ loader = {
|
|||||||
return when(app.activate(appProxy)).then(function () {
|
return when(app.activate(appProxy)).then(function () {
|
||||||
return when.resolve(app);
|
return when.resolve(app);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
75
core/server/apps/permissions.js
Normal file
75
core/server/apps/permissions.js
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
|
||||||
|
var fs = require('fs'),
|
||||||
|
when = require('when'),
|
||||||
|
path = require('path'),
|
||||||
|
parsePackageJson = require('../require-tree').parsePackageJson;
|
||||||
|
|
||||||
|
function AppPermissions(appPath) {
|
||||||
|
this.appPath = appPath;
|
||||||
|
this.packagePath = path.join(this.appPath, 'package.json');
|
||||||
|
}
|
||||||
|
|
||||||
|
AppPermissions.prototype.read = function () {
|
||||||
|
var self = this,
|
||||||
|
def = when.defer();
|
||||||
|
|
||||||
|
this.checkPackageContentsExists()
|
||||||
|
.then(function (exists) {
|
||||||
|
if (!exists) {
|
||||||
|
// If no package.json, return default permissions
|
||||||
|
return def.resolve(AppPermissions.DefaultPermissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read and parse the package.json
|
||||||
|
self.getPackageContents()
|
||||||
|
.then(function (parsed) {
|
||||||
|
// If no permissions in the package.json then return the default permissions.
|
||||||
|
if (!(parsed.ghost && parsed.ghost.permissions)) {
|
||||||
|
return def.resolve(AppPermissions.DefaultPermissions);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Validation on permissions object?
|
||||||
|
|
||||||
|
def.resolve(parsed.ghost.permissions);
|
||||||
|
})
|
||||||
|
.otherwise(def.reject);
|
||||||
|
})
|
||||||
|
.otherwise(def.reject);
|
||||||
|
|
||||||
|
return def.promise;
|
||||||
|
};
|
||||||
|
|
||||||
|
AppPermissions.prototype.checkPackageContentsExists = function () {
|
||||||
|
// Mostly just broken out for stubbing in unit tests
|
||||||
|
var def = when.defer();
|
||||||
|
|
||||||
|
fs.exists(this.packagePath, function (exists) {
|
||||||
|
def.resolve(exists);
|
||||||
|
});
|
||||||
|
|
||||||
|
return def.promise;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get the contents of the package.json in the appPath root
|
||||||
|
AppPermissions.prototype.getPackageContents = function () {
|
||||||
|
var messages = {
|
||||||
|
errors: [],
|
||||||
|
warns: []
|
||||||
|
};
|
||||||
|
|
||||||
|
return parsePackageJson(this.packagePath, messages)
|
||||||
|
.then(function (parsed) {
|
||||||
|
if (!parsed) {
|
||||||
|
return when.reject(new Error(messages.errors[0].message));
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Default permissions for an App.
|
||||||
|
AppPermissions.DefaultPermissions = {
|
||||||
|
posts: ['browse', 'read']
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = AppPermissions;
|
@ -5,13 +5,15 @@ var fs = require('fs'),
|
|||||||
should = require('should'),
|
should = require('should'),
|
||||||
sinon = require('sinon'),
|
sinon = require('sinon'),
|
||||||
_ = require('lodash'),
|
_ = require('lodash'),
|
||||||
|
when = require('when'),
|
||||||
helpers = require('../../server/helpers'),
|
helpers = require('../../server/helpers'),
|
||||||
filters = require('../../server/filters'),
|
filters = require('../../server/filters'),
|
||||||
|
|
||||||
// Stuff we are testing
|
// Stuff we are testing
|
||||||
appProxy = require('../../server/apps/proxy'),
|
appProxy = require('../../server/apps/proxy'),
|
||||||
AppSandbox = require('../../server/apps/sandbox'),
|
AppSandbox = require('../../server/apps/sandbox'),
|
||||||
AppDependencies = require('../../server/apps/dependencies');
|
AppDependencies = require('../../server/apps/dependencies'),
|
||||||
|
AppPermissions = require('../../server/apps/permissions');
|
||||||
|
|
||||||
describe('Apps', function () {
|
describe('Apps', function () {
|
||||||
|
|
||||||
@ -189,4 +191,127 @@ describe('Apps', function () {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Permissions', function () {
|
||||||
|
var noGhostPackageJson = {
|
||||||
|
"name": "myapp",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "My example app",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "Ghost",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ghost-app": "0.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
validGhostPackageJson = {
|
||||||
|
"name": "myapp",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "My example app",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "Ghost",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ghost-app": "0.0.1"
|
||||||
|
},
|
||||||
|
"ghost": {
|
||||||
|
"permissions": {
|
||||||
|
"posts": ["browse", "read", "edit", "add", "delete"],
|
||||||
|
"users": ["browse", "read", "edit", "add", "delete"],
|
||||||
|
"settings": ["browse", "read", "edit", "add", "delete"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
it('has default permissions to read and browse posts', function () {
|
||||||
|
should.exist(AppPermissions.DefaultPermissions);
|
||||||
|
|
||||||
|
should.exist(AppPermissions.DefaultPermissions.posts);
|
||||||
|
|
||||||
|
AppPermissions.DefaultPermissions.posts.should.contain('browse');
|
||||||
|
AppPermissions.DefaultPermissions.posts.should.contain('read');
|
||||||
|
|
||||||
|
// Make it hurt to add more so additional checks are added here
|
||||||
|
_.keys(AppPermissions.DefaultPermissions).length.should.equal(1);
|
||||||
|
});
|
||||||
|
it('uses default permissions if no package.json', function (done) {
|
||||||
|
var perms = new AppPermissions("test");
|
||||||
|
|
||||||
|
// No package.json in this directory
|
||||||
|
sandbox.stub(perms, "checkPackageContentsExists").returns(when.resolve(false));
|
||||||
|
|
||||||
|
perms.read().then(function (readPerms) {
|
||||||
|
should.exist(readPerms);
|
||||||
|
|
||||||
|
readPerms.should.equal(AppPermissions.DefaultPermissions);
|
||||||
|
|
||||||
|
done();
|
||||||
|
}).otherwise(done);
|
||||||
|
});
|
||||||
|
it('uses default permissions if no ghost object in package.json', function (done) {
|
||||||
|
var perms = new AppPermissions("test"),
|
||||||
|
noGhostPackageJsonContents = JSON.stringify(noGhostPackageJson, null, 2);
|
||||||
|
|
||||||
|
// package.json IS in this directory
|
||||||
|
sandbox.stub(perms, "checkPackageContentsExists").returns(when.resolve(true));
|
||||||
|
// no ghost property on package
|
||||||
|
sandbox.stub(perms, "getPackageContents").returns(when.resolve(noGhostPackageJsonContents));
|
||||||
|
|
||||||
|
perms.read().then(function (readPerms) {
|
||||||
|
should.exist(readPerms);
|
||||||
|
|
||||||
|
readPerms.should.equal(AppPermissions.DefaultPermissions);
|
||||||
|
|
||||||
|
done();
|
||||||
|
}).otherwise(done);
|
||||||
|
});
|
||||||
|
it('rejects when reading malformed package.json', function (done) {
|
||||||
|
var perms = new AppPermissions("test");
|
||||||
|
|
||||||
|
// package.json IS in this directory
|
||||||
|
sandbox.stub(perms, "checkPackageContentsExists").returns(when.resolve(true));
|
||||||
|
// malformed JSON on package
|
||||||
|
sandbox.stub(perms, "getPackageContents").returns(when.reject(new Error('package.json file is malformed')));
|
||||||
|
|
||||||
|
perms.read().then(function (readPerms) {
|
||||||
|
done(new Error('should not resolve'));
|
||||||
|
}).otherwise(function () {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('reads from package.json in root of app directory', function (done) {
|
||||||
|
var perms = new AppPermissions("test"),
|
||||||
|
validGhostPackageJsonContents = validGhostPackageJson;
|
||||||
|
|
||||||
|
// package.json IS in this directory
|
||||||
|
sandbox.stub(perms, "checkPackageContentsExists").returns(when.resolve(true));
|
||||||
|
// valid ghost property on package
|
||||||
|
sandbox.stub(perms, "getPackageContents").returns(when.resolve(validGhostPackageJsonContents));
|
||||||
|
|
||||||
|
perms.read().then(function (readPerms) {
|
||||||
|
should.exist(readPerms);
|
||||||
|
|
||||||
|
readPerms.should.not.equal(AppPermissions.DefaultPermissions);
|
||||||
|
|
||||||
|
should.exist(readPerms.posts);
|
||||||
|
readPerms.posts.length.should.equal(5);
|
||||||
|
|
||||||
|
should.exist(readPerms.users);
|
||||||
|
readPerms.users.length.should.equal(5);
|
||||||
|
|
||||||
|
should.exist(readPerms.settings);
|
||||||
|
readPerms.settings.length.should.equal(5);
|
||||||
|
|
||||||
|
_.keys(readPerms).length.should.equal(3);
|
||||||
|
|
||||||
|
done();
|
||||||
|
}).otherwise(done);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user