Problem with Meteor publish/subscribe

Hi Guys,

I have a project page with a unique Id (“Project” Collection). The user acess this page this way:

project/cEyuc3FEGvBLYy4CH

In this project I have some “scenes”. The user can create and delete scenes and I show to him all the scenes relative to that project. I select the scenes relative to the project in the client this way:

Scenes.find({project: Router.current().params._id});

I do that because in the publish I’m publishing all the scenes, this way:

Meteor.publish("scenes", function(){
  return Scenes.find({});
});

My question is: Is there a way to only publish scenes from the current project? Or the way how I’m doing is the only way?

I’m asking that because some projects are private, so I believe that is not cool that user have access to all the scenes.

Thanks for all,
Cheers,

You might wanna read through the topic in the meteor guide: https://guide.meteor.com/data-loading.html

Hi @hilty,

What I think you are trying to do is provide authorized access to a subset of your scenes collection.

Secure Access to authorized data

Ideally, in this scenario you would do this:

  1. Have some sort of an authorization code or set of codes associated with the data. It can be included in the collection.
  2. Each user also has a list of authorization codes that they have access to.

Lets assume I have created an account code for each user and their data then publish would look kind of like this:

Meteor.publish("scenes", function(){
  if(!this.userId) {
    this.ready();
    return;
  }
  let user = Meteor.users.FindOne({_id: this.userId});
  // user._auth.account contains the user account #
  return Scenes.find({account: user._auth.account}, {fields: {account: 0}});
});

On the client side, you can then assume that the client has all the data they are authorized for: So you can find your documents like this.

Scenes.find({});

Somewhere on your server code you would have set the account value in the Meteor.users collection.

Note: this works without the client side every knowing the account code. I used the field specifier to limit the fields that go down to the client. And they do not include the account ID.

Limit amount of data downloaded

Another reason to limit data download is to reduce the amount of data. Imagine your scenes were very large and on the client side they only interacted with one at a time. Then you can make use of the subscription argument to limit the data downloaded. And your publish would now look something like this:

Meteor.publish("scenes", function(sceneID){
  if(!this.userId) {
    this.ready();
    return;
  }
  let user = Meteor.users.FindOne({_id: this.userId});
  // user._auth.account contains the user account #
  return Scenes.find({account: user._auth.account, _id: sceneID});
});

On the client side you would reference the sceneID on your subscribe:

Meteor.subscribe('scenes', sceneID);

Passing arguments from the client side is not a good idea for security. An attacker could attempt to subscribe by varying the sceneID. But to limit the amount of data this user wants then it is perfectly appropriate because the security is taken care of completely by the server side.

Cheers!