Skip to content

Commit 92e51ab

Browse files
committed
Merge pull request #747 from ParsePlatform/nlutsenko.schema.middleware
Add promise-based master-key enforce middleware and move SchemasRouter, FeaturesRouter to use it.
2 parents a79fb3a + fb4a252 commit 92e51ab

File tree

5 files changed

+49
-63
lines changed

5 files changed

+49
-63
lines changed

spec/features.spec.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
var features = require('../src/features')
1+
'use strict';
2+
3+
var features = require('../src/features');
4+
const request = require("request");
25

36
describe('features', () => {
47
it('set and get features', (done) => {
@@ -23,4 +26,19 @@ describe('features', () => {
2326
expect(_features.test).toBeUndefined();
2427
done();
2528
});
29+
30+
it('requires the master key to get all schemas', done => {
31+
request.get({
32+
url: 'http://localhost:8378/1/features',
33+
json: true,
34+
headers: {
35+
'X-Parse-Application-Id': 'test',
36+
'X-Parse-REST-API-Key': 'rest'
37+
}
38+
}, (error, response, body) => {
39+
expect(response.statusCode).toEqual(403);
40+
expect(body.error).toEqual('unauthorized: master key is required');
41+
done();
42+
});
43+
});
2644
});

spec/schemas.spec.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ describe('schemas', () => {
9898
json: true,
9999
headers: restKeyHeaders,
100100
}, (error, response, body) => {
101-
expect(response.statusCode).toEqual(401);
102-
expect(body.error).toEqual('master key not specified');
101+
expect(response.statusCode).toEqual(403);
102+
expect(body.error).toEqual('unauthorized: master key is required');
103103
done();
104104
});
105105
});
@@ -110,8 +110,8 @@ describe('schemas', () => {
110110
json: true,
111111
headers: restKeyHeaders,
112112
}, (error, response, body) => {
113-
expect(response.statusCode).toEqual(401);
114-
expect(body.error).toEqual('master key not specified');
113+
expect(response.statusCode).toEqual(403);
114+
expect(body.error).toEqual('unauthorized: master key is required');
115115
done();
116116
});
117117
});
@@ -206,8 +206,8 @@ describe('schemas', () => {
206206
className: 'MyClass',
207207
},
208208
}, (error, response, body) => {
209-
expect(response.statusCode).toEqual(401);
210-
expect(body.error).toEqual('master key not specified');
209+
expect(response.statusCode).toEqual(403);
210+
expect(body.error).toEqual('unauthorized: master key is required');
211211
done();
212212
});
213213
});

src/Routers/FeaturesRouter.js

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,13 @@
11
import PromiseRouter from '../PromiseRouter';
2-
import {getFeatures} from '../features';
3-
4-
let masterKeyRequiredResponse = () => {
5-
return Promise.resolve({
6-
status: 401,
7-
response: {error: 'master key not specified'},
8-
})
9-
}
2+
import * as middleware from "../middlewares";
3+
import { getFeatures } from '../features';
104

115
export class FeaturesRouter extends PromiseRouter {
12-
136
mountRoutes() {
14-
this.route('GET','/features', (req) => {
15-
return this.handleGET(req);
16-
});
17-
}
18-
19-
handleGET(req) {
20-
if (!req.auth.isMaster) {
21-
return masterKeyRequiredResponse();
22-
}
23-
24-
return Promise.resolve({
25-
response: {
7+
this.route('GET','/features', middleware.promiseEnforceMasterKeyAccess, () => {
8+
return { response: {
269
results: [getFeatures()]
27-
}
10+
} };
2811
});
2912
}
3013
}
31-
32-
export default FeaturesRouter;

src/Routers/SchemasRouter.js

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,7 @@ var express = require('express'),
55
Schema = require('../Schema');
66

77
import PromiseRouter from '../PromiseRouter';
8-
9-
// TODO: refactor in a SchemaController at one point...
10-
function masterKeyRequiredResponse() {
11-
return Promise.resolve({
12-
status: 401,
13-
response: {error: 'master key not specified'},
14-
})
15-
}
8+
import * as middleware from "../middlewares";
169

1710
function classNameMismatchResponse(bodyClass, pathClass) {
1811
return Promise.resolve({
@@ -45,9 +38,6 @@ function mongoSchemaToSchemaAPIResponse(schema) {
4538
}
4639

4740
function getAllSchemas(req) {
48-
if (!req.auth.isMaster) {
49-
return masterKeyRequiredResponse();
50-
}
5141
return req.config.database.collection('_SCHEMA')
5242
.then(coll => coll.find({}).toArray())
5343
.then(schemas => ({response: {
@@ -56,9 +46,6 @@ function getAllSchemas(req) {
5646
}
5747

5848
function getOneSchema(req) {
59-
if (!req.auth.isMaster) {
60-
return masterKeyRequiredResponse();
61-
}
6249
return req.config.database.collection('_SCHEMA')
6350
.then(coll => coll.findOne({'_id': req.params.className}))
6451
.then(schema => ({response: mongoSchemaToSchemaAPIResponse(schema)}))
@@ -72,9 +59,6 @@ function getOneSchema(req) {
7259
}
7360

7461
function createSchema(req) {
75-
if (!req.auth.isMaster) {
76-
return masterKeyRequiredResponse();
77-
}
7862
if (req.params.className && req.body.className) {
7963
if (req.params.className != req.body.className) {
8064
return classNameMismatchResponse(req.body.className, req.params.className);
@@ -100,10 +84,6 @@ function createSchema(req) {
10084
}
10185

10286
function modifySchema(req) {
103-
if (!req.auth.isMaster) {
104-
return masterKeyRequiredResponse();
105-
}
106-
10787
if (req.body.className && req.body.className != req.params.className) {
10888
return classNameMismatchResponse(req.body.className, req.params.className);
10989
}
@@ -168,10 +148,6 @@ var removeJoinTables = (database, mongoSchema) => {
168148
};
169149

170150
function deleteSchema(req) {
171-
if (!req.auth.isMaster) {
172-
return masterKeyRequiredResponse();
173-
}
174-
175151
if (!Schema.classNameIsValid(req.params.className)) {
176152
throw new Parse.Error(Parse.Error.INVALID_CLASS_NAME, Schema.invalidClassNameMessage(req.params.className));
177153
}
@@ -214,11 +190,11 @@ function deleteSchema(req) {
214190

215191
export class SchemasRouter extends PromiseRouter {
216192
mountRoutes() {
217-
this.route('GET', '/schemas', getAllSchemas);
218-
this.route('GET', '/schemas/:className', getOneSchema);
219-
this.route('POST', '/schemas', createSchema);
220-
this.route('POST', '/schemas/:className', createSchema);
221-
this.route('PUT', '/schemas/:className', modifySchema);
222-
this.route('DELETE', '/schemas/:className', deleteSchema);
193+
this.route('GET', '/schemas', middleware.promiseEnforceMasterKeyAccess, getAllSchemas);
194+
this.route('GET', '/schemas/:className', middleware.promiseEnforceMasterKeyAccess, getOneSchema);
195+
this.route('POST', '/schemas', middleware.promiseEnforceMasterKeyAccess, createSchema);
196+
this.route('POST', '/schemas/:className', middleware.promiseEnforceMasterKeyAccess, createSchema);
197+
this.route('PUT', '/schemas/:className', middleware.promiseEnforceMasterKeyAccess, modifySchema);
198+
this.route('DELETE', '/schemas/:className', middleware.promiseEnforceMasterKeyAccess, deleteSchema);
223199
}
224200
}

src/middlewares.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,16 @@ function enforceMasterKeyAccess(req, res, next) {
194194
next();
195195
}
196196

197+
function promiseEnforceMasterKeyAccess(request) {
198+
if (!request.auth.isMaster) {
199+
let error = new Error();
200+
error.status = 403;
201+
error.message = "unauthorized: master key is required";
202+
throw error;
203+
}
204+
return Promise.resolve();
205+
}
206+
197207
function invalidRequest(req, res) {
198208
res.status(403);
199209
res.end('{"error":"unauthorized"}');
@@ -204,5 +214,6 @@ module.exports = {
204214
allowMethodOverride: allowMethodOverride,
205215
handleParseErrors: handleParseErrors,
206216
handleParseHeaders: handleParseHeaders,
207-
enforceMasterKeyAccess: enforceMasterKeyAccess
217+
enforceMasterKeyAccess: enforceMasterKeyAccess,
218+
promiseEnforceMasterKeyAccess
208219
};

0 commit comments

Comments
 (0)