Skip to content

Commit ca9b750

Browse files
committed
Merge pull request #684 from Marco129/client-class-creation
Add allowClientClassCreation option
2 parents 9142dec + 9748910 commit ca9b750

File tree

7 files changed

+83
-0
lines changed

7 files changed

+83
-0
lines changed

spec/RestCreate.spec.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,20 @@ describe('rest create', () => {
7373
});
7474
});
7575

76+
it('handles create on non-existent class when disabled client class creation', (done) => {
77+
var customConfig = Object.assign({}, config, {allowClientClassCreation: false});
78+
rest.create(customConfig, auth.nobody(customConfig), 'ClientClassCreation', {})
79+
.then(() => {
80+
fail('Should throw an error');
81+
done();
82+
}, (err) => {
83+
expect(err.code).toEqual(Parse.Error.OPERATION_FORBIDDEN);
84+
expect(err.message).toEqual('This user is not allowed to access ' +
85+
'non-existent class: ClientClassCreation');
86+
done();
87+
});
88+
});
89+
7690
it('handles user signup', (done) => {
7791
var user = {
7892
username: 'asdf',

spec/RestQuery.spec.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,20 @@ describe('rest query', () => {
9595
}).catch((error) => { console.log(error); });
9696
});
9797

98+
it('query non-existent class when disabled client class creation', (done) => {
99+
var customConfig = Object.assign({}, config, {allowClientClassCreation: false});
100+
rest.find(customConfig, auth.nobody(customConfig), 'ClientClassCreation', {})
101+
.then(() => {
102+
fail('Should throw an error');
103+
done();
104+
}, (err) => {
105+
expect(err.code).toEqual(Parse.Error.OPERATION_FORBIDDEN);
106+
expect(err.message).toEqual('This user is not allowed to access ' +
107+
'non-existent class: ClientClassCreation');
108+
done();
109+
});
110+
});
111+
98112
it('query with wrongly encoded parameter', (done) => {
99113
rest.create(config, nobody, 'TestParameterEncode', {foo: 'bar'}
100114
).then(() => {

src/Config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export class Config {
2626
this.fileKey = cacheInfo.fileKey;
2727
this.facebookAppIds = cacheInfo.facebookAppIds;
2828
this.enableAnonymousUsers = cacheInfo.enableAnonymousUsers;
29+
this.allowClientClassCreation = cacheInfo.allowClientClassCreation;
2930
this.database = DatabaseAdapter.getDatabaseConnection(applicationId);
3031
this.hooksController = cacheInfo.hooksController;
3132
this.filesController = cacheInfo.filesController;

src/RestQuery.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ RestQuery.prototype.execute = function() {
115115
return this.getUserAndRoleACL();
116116
}).then(() => {
117117
return this.redirectClassNameForKey();
118+
}).then(() => {
119+
return this.validateClientClassCreation();
118120
}).then(() => {
119121
return this.replaceSelect();
120122
}).then(() => {
@@ -161,6 +163,25 @@ RestQuery.prototype.redirectClassNameForKey = function() {
161163
});
162164
};
163165

166+
// Validates this operation against the allowClientClassCreation config.
167+
RestQuery.prototype.validateClientClassCreation = function() {
168+
if (this.config.allowClientClassCreation === false && !this.auth.isMaster) {
169+
return this.config.database.loadSchema().then((schema) => {
170+
return schema.hasClass(this.className)
171+
}).then((hasClass) => {
172+
if (hasClass === true) {
173+
return Promise.resolve();
174+
}
175+
176+
throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN,
177+
'This user is not allowed to access ' +
178+
'non-existent class: ' + this.className);
179+
});
180+
} else {
181+
return Promise.resolve();
182+
}
183+
};
184+
164185
// Replaces a $inQuery clause by running the subquery, if there is an
165186
// $inQuery clause.
166187
// The $inQuery clause turns into an $in with values that are just

src/RestWrite.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ function RestWrite(config, auth, className, query, data, originalData) {
5959
RestWrite.prototype.execute = function() {
6060
return Promise.resolve().then(() => {
6161
return this.getUserAndRoleACL();
62+
}).then(() => {
63+
return this.validateClientClassCreation();
6264
}).then(() => {
6365
return this.validateSchema();
6466
}).then(() => {
@@ -105,6 +107,25 @@ RestWrite.prototype.getUserAndRoleACL = function() {
105107
}
106108
};
107109

110+
// Validates this operation against the allowClientClassCreation config.
111+
RestWrite.prototype.validateClientClassCreation = function() {
112+
if (this.config.allowClientClassCreation === false && !this.auth.isMaster) {
113+
return this.config.database.loadSchema().then((schema) => {
114+
return schema.hasClass(this.className)
115+
}).then((hasClass) => {
116+
if (hasClass === true) {
117+
return Promise.resolve();
118+
}
119+
120+
throw new Parse.Error(Parse.Error.OPERATION_FORBIDDEN,
121+
'This user is not allowed to access ' +
122+
'non-existent class: ' + this.className);
123+
});
124+
} else {
125+
return Promise.resolve();
126+
}
127+
};
128+
108129
// Validates this operation against the schema.
109130
RestWrite.prototype.validateSchema = function() {
110131
return this.config.database.validateObject(this.className, this.data, this.query);

src/cli/cli-definitions.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,16 @@ export default {
8585
return false;
8686
}
8787
},
88+
"allowClientClassCreation": {
89+
env: "PARSE_SERVER_ALLOW_CLIENT_CLASS_CREATION",
90+
help: "Enable (or disable) client class creation, defaults to true",
91+
action: function(opt) {
92+
if (opt == "true" || opt == "1") {
93+
return true;
94+
}
95+
return false;
96+
}
97+
},
8898
"mountPath": {
8999
env: "PARSE_SERVER_MOUNT_PATH",
90100
help: "Mount path for the server, defaults to /parse",

src/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ function ParseServer({
8686
fileKey = 'invalid-file-key',
8787
facebookAppIds = [],
8888
enableAnonymousUsers = true,
89+
allowClientClassCreation = true,
8990
oauth = {},
9091
serverURL = requiredParameter('You must provide a serverURL!'),
9192
maxUploadSize = '20mb'
@@ -139,6 +140,7 @@ function ParseServer({
139140
loggerController: loggerController,
140141
hooksController: hooksController,
141142
enableAnonymousUsers: enableAnonymousUsers,
143+
allowClientClassCreation: allowClientClassCreation,
142144
oauth: oauth,
143145
};
144146

0 commit comments

Comments
 (0)