Set rules on collection publications

How can I set rules to certain publications?

For example: My user profile contains the field isAdmin.
I want to check this field in my publications so that I will be able to know if he is an admin or not.

This is what I have so far and it is not working:

Meteor.publish('users', function(){
	if(Meteor.user()['profile']['isAdmin']){
		return Meteor.users.find({}, {fields:{username:1, profile:1, createdAt: 1, role:1}})
	}else{
		this.ready();
	}
});

Meteor.user() works anywhere except publications.

you’d have to fetch the subscribing user first, and then do all your checks.
Here’s an example:

Meteor.publish('users', function() {

   check(this.userId, String); /* this.userId is exposed in publications; this check would see if user's even logged in */
   var subscriber = Meteor.users.findOne(this.userId, { fields: { 'profile.isAdmin': 1 } }); /* get only one field for optimization */
   if (!subscriber || !subscriber.profile.isAdmin) {
     this.ready();
     return;
   }  

   return Meteor.users.find({}, {fields: { username: 1, profile: 1, createdAt: 1, role: 1 });   

});

For a complete, robust solution, I’d also guard the isAdmin access by using a deep find utility, so you don’t get an error if subscriber.profile isn’t an object.

For a complete, robust solution, I’d also guard the isAdmin access by using a deep find utility, so you don’t get an error if subscriber.profile isn’t an object.

How do you do this?

You could optimize it more

if(! Meteor.users.find({_id: this.userId, 'profile.isAdmin': true}).count()) {
    throw new Meteor.error(500, 'Access denied');
}
1 Like

manually, you’d have to do this:

if (!subscriber || !subscriber.profile || !subscriber.profile.isAdmin)

alternatively, I recommend Underscore deep. It’s available as a package (practicalmeteor:underscore-deep):

if (!subscriber, _.deep(subscriber, 'profile.isAdmin'))

@mrzafod’s answer is even better.

Anyone implementing the examples:

A security warning about storing sensitive state inside the profile object: it is writable by the user by default (http://docs.meteor.com/#/full/meteor_user).

So the user would be able to pop open the console and modify their isAdmin value.

2 Likes

these are publication examples, which means they execute on the server

a user can’t modify the execution in console, unless they actually send an update command to the server
that said, it’s trivial to say you should always remove the insecure package from a project before exposing it to public users, and apply tight restrictions on collection CRUD