CulturalMe / meteor-slingshot

Upload files directly to AWS S3, Google Cloud Storage and others in meteor
MIT License
594 stars 105 forks source link

What about downloads? #16

Open Gaelan opened 9 years ago

Gaelan commented 9 years ago

It doesn't look like there is a way to do downloads with Slingshot. Is there another package that does this? Do we just have to fend for ourselves? Could I send a pull request?

gsuess commented 9 years ago

Both AWS S3 and Google Cloud are are Cloud Storage Services for the web.

As such they offer excellent file hosting for HTTP (meaning downloads). Slingshot doesn't handle downloads, because it doesn't need to handle downloads. It just provides a download-URL - It is as simple as that.

I have updated the readme, to clarify this a bit more. Please look for downloadUrl in the code-snippets.

Other than that, you are most welcome to do pull-requests :)

bensmeets commented 9 years ago

I think (big assumption here) people mean that Slingshot doesn't provide any security if a user should be able to download the file. Just out of curiousity, would it be possible to use the same kind of signing technique used for uploading for downloading as well? Or is it smarter to just use a very hard to guess filename or url for that same purpose?

gsuess commented 9 years ago

I think (big assumption here) people mean that Slingshot doesn't provide any security if a user should be able to download the file. Just out of curiousity, would it be possible to use the same kind of signing technique used for uploading for downloading as well? Or is it smarter to just use a very hard to guess filename or url for that same purpose?

With Slingshot you can only alter the acl to restrict downloads. Using a hard to guess key is also a viable method. For other use-cases, using S3, you could use the aws-sdk to generate a URL that expires after a given time-period:

http://docs.aws.amazon.com/aws-sdk-php/latest/class-Aws.S3.S3Client.html#_getObjectUrl

AndyWilkinUK commented 9 years ago

Looks awesome, though do have a potential use case where it would be good if the Meteor app served out these signed / time restricted URLs - so +1 on that, where a tricky filename would not be sufficient.

If a user wanted to upload a video, would this work as well? Also are the transfers resumable if the connection times out?

gsuess commented 9 years ago

If a user wanted to upload a video, would this work as well? Also are the transfers resumable if the connection times out?

That is planned: #5

hamxiaoz commented 8 years ago

For anyone that's interested, the JavaScript example of creating a signed url is at: http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getSignedUrl-property

rpesciotta commented 8 years ago

Hi guys, I started using slingshot with Amazon S3 recently, and run into the same problem - files uploaded via my meteor app, should be only viewed by the user who uploaded it. I had a look at the link shared above, but I still think it would be really nice if such a function was integrated into the slingshot package.

Gaelan commented 8 years ago

@rpesciotta I have. Here's my (simplified) code. AWS.S3 comes from eluck:aws-sdk. Note that this code requires the S3 credentials to be stored in the environment (in the same place where Slingshot looks for them).

getSignedURL = (key) ->
    s3 = new AWS.S3
    url = Meteor.wrapAsync(s3.getSignedUrl, s3) 'getObject', Bucket: Meteor.settings.public.s3bucket, Key: key, Expires: 60
    url

Router.route "files_get",
    where: "server"
    path: "/files/:fileId/:store"
    action: ->
        # Authenticate the user. You will want to either pass a token to the HTTP request or store a token in a cookie (if you use `meteorhacks:fast-render`, this will already be done).
        file = Files.findOne @params.fileId
        key = file?.copies?[@params.store]?.key
        if key
            @response.writeHead 302, Location: getSignedURL key
            @response.end()
        else
            @response.writeHead 404
            @response.end "404 Not Found"
rpesciotta commented 8 years ago

@Gaelan : great stuff man, thanks for sharing. I'm adapting it to my app, we'll provide feedback ;)

rpesciotta commented 8 years ago

@Gaelan: sorry for the delay. I've implemented and it worked quite well - good stuff! In my case, my app uploads files to S3 (images), and I need to display them in the website as well. With the first implementation, I noticed that the signed request was generated for every request, which is a bad idea in my case. Everytime the user opens a form containing that image, it has to download again from S3. The immediate way I found to minimize this problem, was to generate the signed request, and store it for an amount of time. In case the user requests the image again within that period, the same URL is used, and therefore cached, so no file transfer. In addition, if other users (who should have access to the same file) request it within this time frame, the same URL is also provided to them. The downside of this, is that I have to keep this list of active signed URLs, and maintain (expire) requests periodically. Have you had similar requirements? I'd be very interested to discuss how you (or anyone else with similar problems) have solved this problem. In any case, the solution I have is acceptable, although not perfect, for that I already thank you for sharing the implementation 👍

Now, how nice would that be to add such a function in the package itself? :)

Gaelan commented 8 years ago

@rpesciotta I am building a private app without many users, so I have the luxury of not needing to fine-tune things like this.

smohantyCME commented 3 years ago

@Gaelan: sorry for the delay. I've implemented and it worked quite well - good stuff! In my case, my app uploads files to S3 (images), and I need to display them in the website as well. With the first implementation, I noticed that the signed request was generated for every request, which is a bad idea in my case. Everytime the user opens a form containing that image, it has to download again from S3. The immediate way I found to minimize this problem, was to generate the signed request, and store it for an amount of time. In case the user requests the image again within that period, the same URL is used, and therefore cached, so no file transfer. In addition, if other users (who should have access to the same file) request it within this time frame, the same URL is also provided to them. The downside of this, is that I have to keep this list of active signed URLs, and maintain (expire) requests periodically. Have you had similar requirements? I'd be very interested to discuss how you (or anyone else with similar problems) have solved this problem. In any case, the solution I have is acceptable, although not perfect, for that I already thank you for sharing the implementation 👍

Now, how nice would that be to add such a function in the package itself? :)

@rpeciotta Hi! I have the same problem you do in wanting to cache the signed urls till their expiration date. How did you solve it? I was playing around with storing the urls in Session Vars, but, doesn't seem right