Skip to content

Commit bf65c13

Browse files
committed
Move Public API behind labs flag
closes TryGhost#5941 - added UI to labs page - added method to determine if full authentication is required - updated public_api tests to enable public api first
1 parent 0c9befc commit bf65c13

8 files changed

Lines changed: 78 additions & 3 deletions

File tree

core/client/app/controllers/feature.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,9 @@ export default Ember.Controller.extend(Ember.PromiseProxyMixin, {
2525
}
2626

2727
return value;
28+
}),
29+
30+
publicAPI: Ember.computed('config.publicAPI', 'labs.publicAPI', function () {
31+
return this.get('config.publicAPI') || this.get('labs.publicAPI');
2832
})
2933
});

core/client/app/controllers/settings/labs.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export default Ember.Controller.extend({
99
ghostPaths: Ember.inject.service('ghost-paths'),
1010
notifications: Ember.inject.service(),
1111
session: Ember.inject.service(),
12+
feature: Ember.inject.controller(),
1213

1314
labsJSON: Ember.computed('model.labs', function () {
1415
return JSON.parse(this.get('model.labs') || {});
@@ -29,6 +30,16 @@ export default Ember.Controller.extend({
2930
});
3031
},
3132

33+
usePublicAPI: Ember.computed('feature.publicAPI', {
34+
get: function () {
35+
return this.get('feature.publicAPI');
36+
},
37+
set: function (key, value) {
38+
this.saveLabs('publicAPI', value);
39+
return value;
40+
}
41+
}),
42+
3243
actions: {
3344
onUpload: function (file) {
3445
var self = this,

core/client/app/templates/settings/labs.hbs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,19 @@
4242
</div>
4343
</fieldset>
4444
</form>
45+
<hr>
46+
<form>
47+
<fieldset>
48+
<div class="form-group for-checkbox">
49+
<label for="labs-publicAPI">Public API</label>
50+
<label class="checkbox" for="labs-publicAPI">
51+
{{input id="labs-publicAPI" name="labs[publicAPI]" type="checkbox" checked=usePublicAPI}}
52+
<span class="input-toggle-component"></span>
53+
<p>Enable public API access.</p>
54+
</label>
55+
<p>Allow access to the publicly available Ghost API using JavaScript.</p>
56+
</div>
57+
</fieldset>
58+
</form>
4559
</section>
4660
</section>

core/server/api/configuration.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ var _ = require('lodash'),
1010
function getValidKeys() {
1111
var validKeys = {
1212
fileStorage: config.fileStorage === false ? false : true,
13+
publicAPI: config.publicAPI === true ? true : false,
1314
apps: config.apps === true ? true : false,
1415
version: config.ghostVersion,
1516
environment: process.env.NODE_ENV,

core/server/middleware/auth.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ var _ = require('lodash'),
33
url = require('url'),
44
errors = require('../errors'),
55
config = require('../config'),
6+
api = require('../api'),
67
oauthServer,
78

89
auth;
@@ -130,6 +131,30 @@ auth = {
130131
}
131132
},
132133

134+
// ### Require user depending on public API being activated.
135+
requiresAuthorizedUserPublicAPI: function requiresAuthorizedUserPublicAPI(req, res, next) {
136+
return api.settings.read({key: 'labs', context: {internal: true}}).then(function (response) {
137+
var labs,
138+
labsValue;
139+
140+
labs = _.find(response.settings, function (setting) {
141+
return setting.key === 'labs';
142+
});
143+
144+
labsValue = JSON.parse(labs.value);
145+
146+
if (labsValue.publicAPI && labsValue.publicAPI === true) {
147+
return next();
148+
} else {
149+
if (req.user) {
150+
return next();
151+
} else {
152+
return errors.handleAPIError(new errors.NoPermissionError('Please Sign In'), req, res, next);
153+
}
154+
}
155+
});
156+
},
157+
133158
// ### Generate access token Middleware
134159
// register the oauth2orize middleware for password and refresh token grants
135160
generateAccessToken: function generateAccessToken(req, res, next) {

core/server/middleware/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ middleware = {
4343
authenticateClient: auth.authenticateClient,
4444
authenticateUser: auth.authenticateUser,
4545
requiresAuthorizedUser: auth.requiresAuthorizedUser,
46+
requiresAuthorizedUserPublicAPI: auth.requiresAuthorizedUserPublicAPI,
4647
generateAccessToken: auth.generateAccessToken,
4748
errorHandler: errors.handleAPIError
4849
}

core/server/routes/api.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ apiRoutes = function apiRoutes(middleware) {
88
// Authentication for public endpoints
99
authenticatePublic = [
1010
middleware.api.authenticateClient,
11-
middleware.api.authenticateUser
11+
middleware.api.authenticateUser,
12+
middleware.api.requiresAuthorizedUserPublicAPI
1213
],
1314
// Require user for private endpoints
1415
authenticatePrivate = [

core/test/functional/routes/api/public_api_spec.js

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,33 @@ var testUtils = require('../../../utils'),
1010
request;
1111

1212
describe('Public API', function () {
13+
var publicAPIaccessSetting = {
14+
settings: [
15+
{key: 'labs', value: {publicAPI: true}}
16+
]
17+
};
18+
1319
before(function (done) {
1420
// starting ghost automatically populates the db
1521
// TODO: prevent db init, and manage bringing up the DB with fixtures ourselves
1622
ghost().then(function (ghostServer) {
1723
request = supertest.agent(ghostServer.rootApp);
1824
}).then(function () {
1925
return testUtils.doAuth(request, 'posts', 'tags');
20-
}).then(function () {
21-
done();
26+
}).then(function (token) {
27+
// enable public API
28+
return request.put(testUtils.API.getApiQuery('settings/'))
29+
.set('Authorization', 'Bearer ' + token)
30+
.send(publicAPIaccessSetting)
31+
.expect('Content-Type', /json/)
32+
.expect('Cache-Control', testUtils.cacheRules.private)
33+
.expect(200)
34+
.end(function (err) {
35+
if (err) {
36+
return done(err);
37+
}
38+
done();
39+
});
2240
}).catch(done);
2341
});
2442

0 commit comments

Comments
 (0)