Skip to content

Commit

Permalink
Access control for default collection mutators
Browse files Browse the repository at this point in the history
- A new `insecure` package reproduces the experience we had
  before this change, in which all collections are by default
  totally open to all changes
- With or without the `insecure` package, you can now call
  collection.allow() to define which calls to the default
  mutator methods should be allowed
  • Loading branch information
avital authored and n1mmy committed Jul 24, 2012
1 parent 0e31087 commit b227d59
Show file tree
Hide file tree
Showing 8 changed files with 740 additions and 68 deletions.
1 change: 1 addition & 0 deletions app/meteor/skel/.meteor/packages
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
# but you can also edit it by hand.

autopublish
insecure
53 changes: 14 additions & 39 deletions examples/todos/server/access_control.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,19 @@
// This is a quick and dirty access control mechanism. There will be a
// cleaner way to do this soon, along with an easier way to turn off the
// default object mutator methods (insert/update/remove).
//
// A more general way to perform access control is to use custom methods
// for each write operation. Methods can access this.userId() to perform
// any access checking they like.

Meteor.startup(function() {
// which collections to control.
var collectionMap = {todos: Todos};

_.each(collectionMap, function(collection, collectionName) {
_.each(['update', 'remove'], function(method) {
var methodName = '/' + collectionName + '/' + method;
var originalMethodHandler = Meteor.default_server.method_handlers[methodName];

Meteor.default_server.method_handlers[methodName] = function() {
var id = arguments[0];

// Only allow selectors that affect a single object.
//
// One way to get multi-object validation (ie accepting complex
// selectors here) would be to add
// '$in: {privateTo: [null, this.userId()]}' to the selector.
// This would restrict any matched documents to only those that
// could be modified by this user. However, this gets
// complicated if the selector is more complex.
if (typeof id !== 'string') {
throw new Meteor.Error("Access denied. Mutators method must modify an object by id, not selector.");
}
var canModify = function(userId, tasks) {
return _.all(tasks, function(task) {
return !task.privateTo || task.privateTo === userId;
});
};

var obj = collection.findOne(id);
if (!obj)
return;
Todos.allow({
insert: function () { return true; },
update: canModify,
remove: canModify,
fetch: ['privateTo']
});

if (!obj.privateTo || obj.privateTo === this.userId())
originalMethodHandler.apply(this, arguments);
else
throw new Meteor.Error("Access denied");
};
});
Lists.allow({
insert: function () { return true; }
// can't update or remove
});
});
1 change: 1 addition & 0 deletions packages/insecure/insecure.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Meteor.Collection.insecure = true;
8 changes: 8 additions & 0 deletions packages/insecure/package.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Package.describe({
summary: "Allow all database writes by default",
internal: false
});

Package.on_use(function (api) {
api.add_files(['insecure.js'], 'server');
});
Loading

0 comments on commit b227d59

Please sign in to comment.