6

how do I restrict a folder, so only those who logged in into my Meteor app can download files?

I looked into multiple ways of doing this, but the main problem is that I can't access ( I get null.) with:

Meteor.user() or this.userId()

I tried:

__meteor_bootstrap__.app
    .use(connect.query())
    .use(function(req, res, next) {
        Fiber(function () {  

          // USER HERE?

        }).run();
    });

or

__meteor_bootstrap__.app.stack.unshift({

    route: "/protected/secret_document.doc", // only users can download this

    handle: function(req, res) { Fiber(function() {

        // CHECK USER HERE ?

        // IF NOT LOGGED IN:
        res.writeHead(403, {'Content-Type': 'text/html'});
        var content = '<html><body>403 Forbidden</body></html>';
        res.end(content, 'utf-8');
    }).run() }
});
vladikoff
  • 1,496
  • 1
  • 14
  • 25

2 Answers2

3

You could try storing the files in mongodb, which would mean that they would then be hooked into your collection system and be queryable on the client and server. Then, just publish the relevant data to the client for specific users, or use Meteor.methods to expose information that way.

Example:

Assuming files are stored in MongoDB, let's first publish them to the client:

Meteor.publish("files", function(folder) {
  if (!this.userId) return;
  // the userHasAccessToFolder method checks whether
  // this user is allowed to see files in this folder
  if (userHasAccessToFolder(this.userId, folder))
    // if so, return the files for that folder
    // (filter the results however you need to)
    return Files.find({folder: folder});
});

Then on the client, we autosubscribe to the published channel so that whenever it changes, it gets refreshed:

Meteor.startup(function() {
  Meteor.autosubscribe(function() {
    // send the current folder to the server, 
    // which will return the files in the folder
    // only if the current user is allowed to see it
    Meteor.subscribe("files", Session.get("currentFolder"));
  });
});

NB. I haven't tested above code so consider it pseudocode, but it should point you in the general direction for solving this problem. The hard part is storing the files in mongodb!

Community
  • 1
  • 1
Rahul
  • 12,181
  • 5
  • 43
  • 64
  • How do I publish my file as XML or JSON without rendering the rest of the template stuff? – vladikoff Dec 25 '12 at 20:22
  • What do you mean? If your file is in mongo, you can just retrieve it from the database (if you allow access) with the collection API. Eg. `Files.find({filename: "myfile.jpg"});` – Rahul Dec 25 '12 at 20:30
  • Maybe you can post an example? Issue is I can't control access. – vladikoff Dec 25 '12 at 21:59
  • It took a while, but I posted an example! – Rahul Jan 01 '13 at 04:06
  • There is some indication amongst the mailing lists and issue tracking discussions that this is the direction Meteor is moving towards and may become the framework recommended approach to these types of issues. – AbigailW Jan 20 '13 at 14:39
2

i'd be more concerned as to why Meteor.user() isn't working.

a few questions:

  • are you on meteor 0.5.0?
  • have you added accounts-base to your meteor project?
  • have you used one of meteor's login systems (accounts-password, accounts-facebook, etc)? (optional - accounts-ui for ease of use?)
  • have you still got autopublish on? or have you set up publishing / subscription properly?

Meteor.user() should be the current user, and Meteor.users should be a Meteor Collection of all previous logged in users.

stef
  • 1,446
  • 1
  • 17
  • 26
  • Hey, thanks for the answer. Auth works perfectly fine from the inside the application. But when I do a straight request to one of the files then there's no way auth can check if the user is logged in or not. From the things I tried, in most cases I get ""Meteor.userId can only be invoked in method calls. Use this.userId in publish functions."" And of course, I tried the ".userId" in multiple ways. – vladikoff Dec 28 '12 at 20:03
  • if auth's working ok from your main application, you could try using something like [Meteor Router](https://github.com/tmeasday/meteor-router) - you can check the url parameters to see if the file exists, and check the logged in user has the right permissions, set the headers to the right content type, then read and deliver the file (like a normal node.js http server) – stef Dec 29 '12 at 10:43
  • to be honest, though, that's not a very good solution - it won't handle well for large files, and it feels like a workaround. i'm going to put in a feature request for this, and failing that, write a module for it. (i'd rather it was built in - it feels like it's something that should be part of the core meteor server) – stef Dec 29 '12 at 10:44
  • Thanks stef, could you link the feature request here if you don't mind? – vladikoff Dec 29 '12 at 19:22