diff --git a/core/client/app/controllers/feature.js b/core/client/app/controllers/feature.js index b584296653..5aa36375eb 100644 --- a/core/client/app/controllers/feature.js +++ b/core/client/app/controllers/feature.js @@ -25,5 +25,9 @@ export default Ember.Controller.extend(Ember.PromiseProxyMixin, { } return value; + }), + + publicAPI: Ember.computed('config.publicAPI', 'labs.publicAPI', function () { + return this.get('config.publicAPI') || this.get('labs.publicAPI'); }) }); diff --git a/core/client/app/controllers/settings/labs.js b/core/client/app/controllers/settings/labs.js index 42b29a2238..2a70142721 100644 --- a/core/client/app/controllers/settings/labs.js +++ b/core/client/app/controllers/settings/labs.js @@ -9,6 +9,7 @@ export default Ember.Controller.extend({ ghostPaths: Ember.inject.service('ghost-paths'), notifications: Ember.inject.service(), session: Ember.inject.service(), + feature: Ember.inject.controller(), labsJSON: Ember.computed('model.labs', function () { return JSON.parse(this.get('model.labs') || {}); @@ -29,6 +30,16 @@ export default Ember.Controller.extend({ }); }, + usePublicAPI: Ember.computed('feature.publicAPI', { + get: function () { + return this.get('feature.publicAPI'); + }, + set: function (key, value) { + this.saveLabs('publicAPI', value); + return value; + } + }), + actions: { onUpload: function (file) { var self = this, diff --git a/core/client/app/templates/settings/labs.hbs b/core/client/app/templates/settings/labs.hbs index 8494c7c8b7..96baf4df1e 100644 --- a/core/client/app/templates/settings/labs.hbs +++ b/core/client/app/templates/settings/labs.hbs @@ -42,5 +42,19 @@ +
+
+
+
+ + +

Allow access to the publicly available Ghost API using JavaScript.

+
+
+
diff --git a/core/server/api/configuration.js b/core/server/api/configuration.js index 3b1067db6f..9bcf48a612 100644 --- a/core/server/api/configuration.js +++ b/core/server/api/configuration.js @@ -10,6 +10,7 @@ var _ = require('lodash'), function getValidKeys() { var validKeys = { fileStorage: config.fileStorage === false ? false : true, + publicAPI: config.publicAPI === true ? true : false, apps: config.apps === true ? true : false, version: config.ghostVersion, environment: process.env.NODE_ENV, diff --git a/core/server/middleware/auth.js b/core/server/middleware/auth.js index 59100b34e3..79ff74826e 100644 --- a/core/server/middleware/auth.js +++ b/core/server/middleware/auth.js @@ -3,6 +3,7 @@ var _ = require('lodash'), url = require('url'), errors = require('../errors'), config = require('../config'), + api = require('../api'), oauthServer, auth; @@ -130,6 +131,30 @@ auth = { } }, + // ### Require user depending on public API being activated. + requiresAuthorizedUserPublicAPI: function requiresAuthorizedUserPublicAPI(req, res, next) { + return api.settings.read({key: 'labs', context: {internal: true}}).then(function (response) { + var labs, + labsValue; + + labs = _.find(response.settings, function (setting) { + return setting.key === 'labs'; + }); + + labsValue = JSON.parse(labs.value); + + if (labsValue.publicAPI && labsValue.publicAPI === true) { + return next(); + } else { + if (req.user) { + return next(); + } else { + return errors.handleAPIError(new errors.NoPermissionError('Please Sign In'), req, res, next); + } + } + }); + }, + // ### Generate access token Middleware // register the oauth2orize middleware for password and refresh token grants generateAccessToken: function generateAccessToken(req, res, next) { diff --git a/core/server/middleware/index.js b/core/server/middleware/index.js index 41aa34c9f8..3846e2529f 100644 --- a/core/server/middleware/index.js +++ b/core/server/middleware/index.js @@ -43,6 +43,7 @@ middleware = { authenticateClient: auth.authenticateClient, authenticateUser: auth.authenticateUser, requiresAuthorizedUser: auth.requiresAuthorizedUser, + requiresAuthorizedUserPublicAPI: auth.requiresAuthorizedUserPublicAPI, generateAccessToken: auth.generateAccessToken, errorHandler: errors.handleAPIError } diff --git a/core/server/routes/api.js b/core/server/routes/api.js index b8b0baa993..ac2b875619 100644 --- a/core/server/routes/api.js +++ b/core/server/routes/api.js @@ -8,7 +8,8 @@ apiRoutes = function apiRoutes(middleware) { // Authentication for public endpoints authenticatePublic = [ middleware.api.authenticateClient, - middleware.api.authenticateUser + middleware.api.authenticateUser, + middleware.api.requiresAuthorizedUserPublicAPI ], // Require user for private endpoints authenticatePrivate = [ diff --git a/core/test/functional/routes/api/public_api_spec.js b/core/test/functional/routes/api/public_api_spec.js index 6a388a5b1d..ff541fb68d 100644 --- a/core/test/functional/routes/api/public_api_spec.js +++ b/core/test/functional/routes/api/public_api_spec.js @@ -10,6 +10,12 @@ var testUtils = require('../../../utils'), request; describe('Public API', function () { + var publicAPIaccessSetting = { + settings: [ + {key: 'labs', value: {publicAPI: true}} + ] + }; + before(function (done) { // starting ghost automatically populates the db // TODO: prevent db init, and manage bringing up the DB with fixtures ourselves @@ -17,8 +23,20 @@ describe('Public API', function () { request = supertest.agent(ghostServer.rootApp); }).then(function () { return testUtils.doAuth(request, 'posts', 'tags'); - }).then(function () { - done(); + }).then(function (token) { + // enable public API + return request.put(testUtils.API.getApiQuery('settings/')) + .set('Authorization', 'Bearer ' + token) + .send(publicAPIaccessSetting) + .expect('Content-Type', /json/) + .expect('Cache-Control', testUtils.cacheRules.private) + .expect(200) + .end(function (err) { + if (err) { + return done(err); + } + done(); + }); }).catch(done); });