Git Product home page Git Product logo

meteor-slingshot's Introduction

meteor-slingshot

Gitter

Direct and secure file-uploads to AWS S3, Google Cloud Storage and others.

Install

meteor add edgee:slingshot

Why?

There are many many packages out there that allow file uploads to S3, Google Cloud and other cloud storage services, but they usually rely on the meteor apps' server to relay the files to the cloud service, which puts the server under unnecessary load.

meteor-slingshot uploads the files directly to the cloud service from the browser without ever exposing your secret access key or any other sensitive data to the client and without requiring public write access to cloud storage to the entire public.

File uploads can not only be restricted by file-size and file-type, but also by other stateful criteria such as the current meteor user.

Quick Example

Client side

On the client side we can now upload files through to the bucket:

var uploader = new Slingshot.Upload("myFileUploads");

uploader.send(document.getElementById('input').files[0], function (error, downloadUrl) {
  if (error) {
    // Log service detailed response.
    console.error('Error uploading', uploader.xhr.response);
    alert (error);
  }
  else {
    Meteor.users.update(Meteor.userId(), {$push: {"profile.files": downloadUrl}});
  }
});

Client and Server

These file upload restrictions are validated on the client and then appended to the directive on the server side to enforce them:

Slingshot.fileRestrictions("myFileUploads", {
  allowedFileTypes: ["image/png", "image/jpeg", "image/gif"],
  maxSize: 10 * 1024 * 1024 // 10 MB (use null for unlimited).
});

Important: The fileRestrictions must be declared before the the directive is instantiated.

Server side

On the server we declare a directive that controls upload access rules:

Slingshot.createDirective("myFileUploads", Slingshot.S3Storage, {
  bucket: "mybucket",

  acl: "public-read",

  authorize: function () {
    //Deny uploads if user is not logged in.
    if (!this.userId) {
      var message = "Please login before posting files";
      throw new Meteor.Error("Login Required", message);
    }

    return true;
  },

  key: function (file) {
    //Store file into a directory by the user's username.
    var user = Meteor.users.findOne(this.userId);
    return user.username + "/" + file.name;
  }
});

With the directive above, no other files than images will be allowed. The policy is directed by the meteor app server and enforced by AWS S3.

Note: If your bucket is created in any region other than US Standard, you will need to set the region key in the directive. Refer the AWS Slingshot Storage Directives

Storage services

The client side is agnostic to which storage service is used. All it needs for the file upload to work, is a directive name.

There is no limit imposed on how many directives can be declared for each storage service.

Storage services are pluggable in Slingshot and you can add support for own storage service as described in a section below.

Progress bars

You can create file upload progress bars as follows:

<template name="progressBar">
  <div class="progress">
    <div class="progress-bar" role="progressbar" aria-valuenow="{{progress}}" aria-valuemin="0" aria-valuemax="100" style="width: {{progress}}%;">
      <span class="sr-only">{{progress}}% Complete</span>
    </div>
  </div>
</template>

Using the Slingshot.Upload instance read and react to the progress:

Template.progressBar.helpers({
  progress: function () {
    return Math.round(this.uploader.progress() * 100);
  }
});

Show uploaded file before it is uploaded (latency compensation)

<template name="myPicture">
  <img src={{url}}/>
</template>
Template.myPicture.helpers({
  url: function () {
    //If we are uploading an image, pass true to download the image into cache.
    //This will preload the image before using the remote image url.
    return this.uploader.url(true);
  }
});

This to show the image from the local source until it is uploaded to the server. If Blob URL's are not available it will attempt to use FileReader to generate a base64-encoded url representing the data as a fallback.

Add meta-context to your uploads

You can add meta-context to your file-uploads, to make your requests more specific on where the files are to be uploaded.

Consider the following example...

We have an app that features picture albums. An album belongs to a user and only that user is allowed to upload picture to it. In the cloud each album has its own directory where its pictures are stored.

We declare our client-side uploader as follows:

var metaContext = {albumId: album._id}
var uploadToMyAlbum = new Slingshot.Upload("picturealbum", metaContext);

On the server side the directive can now set the key accordingly and check if the user is allowed post pictures to the given album:

Slingshot.createDirective("picturealbum", Slingshot.GoogleCloud, {
  acl: "public-read",

  authorize: function (file, metaContext) {
    var album = Albums.findOne(metaContext.albumId);

    //Denied if album doesn't exist or if it is not owned by the current user.
    return album && album.userId === this.userId;
  },

  key: function (file, metaContext) {
    return metaContext.albumId + "/" + Date.now() + "-" + file.name;
  }
});

Manual Client Side validation

You can check if a file uploadable according to file-restrictions as follows:

var uploader = new Slingshot.Upload("myFileUploads");

var error = uploader.validate(document.getElementById('input').files[0]);
if (error) {
  console.error(error);
}

The validate method will return null if valid and returns an Error instance if validation fails.

AWS S3

You will need aAWSAccessKeyId and AWSSecretAccessKey in Meteor.settings and a bucket with the following CORS configuration:

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
    <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>HEAD</AllowedMethod>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
        <AllowedHeader>*</AllowedHeader>
    </CORSRule>
</CORSConfiguration>

Declare AWS S3 Directives as follows:

Slingshot.createDirective("aws-s3-example", Slingshot.S3Storage, {
  //...
});

S3 with temporary AWS Credentials (Advanced)

For extra security you can use temporary credentials to sign upload requests.

var sts = new AWS.STS(); // Using the AWS SDK to retrieve temporary credentials.

Slingshot.createDirective('myUploads', Slingshot.S3Storage.TempCredentials, {
  bucket: 'myBucket',
  temporaryCredentials: Meteor.wrapAsync(function (expire, callback) {
    //AWS dictates that the minimum duration must be 900 seconds:
    var duration = Math.max(Math.round(expire / 1000), 900);

    sts.getSessionToken({
        DurationSeconds: duration
    }, function (error, result) {
      callback(error, result && result.Credentials);
    });
  })
});

If you are running slingshot on an EC2 instance, you can conveniantly retreive your access keys with AWS.EC2MetadataCredentials:

var credentials = new AWS.EC2MetadataCredentials();

var updateCredentials = Meteor.wrapAsync(credentials.get, credentials);

Slingshot.createDirective('myUploads', Slingshot.S3Storage.TempCredentials, {
  bucket: 'myBucket',
  temporaryCredentials: function () {
    if (credentials.needsRefresh()) {
      updateCredentials();
    }

    return {
      AccessKeyId: credentials.accessKeyId,
      SecretAccessKey: credentials.secretAccessKey,
      SessionToken: credentials.sessionToken
    };
  }
});

Google Cloud

Generate a private key and convert it to a .pem file using openssl:

openssl pkcs12 -in google-cloud-service-key.p12 -nodes -nocerts > google-cloud-service-key.pem

Setup CORS on the bucket:

gsutil cors set docs/gs-cors.json gs://mybucket

Save this file into the /private directory of your meteor app and add this line to your server-side code:

Slingshot.GoogleCloud.directiveDefault.GoogleSecretKey = Assets.getText('google-cloud-service-key.pem');

Declare Google Cloud Storage Directives as follows:

Slingshot.createDirective("google-cloud-example", Slingshot.GoogleCloud, {
  //...
});

Rackspace Cloud Files

You will need aRackspaceAccountId (your acocunt number) and RackspaceMetaDataKey in Meteor.settings.

In order to obtain your RackspaceMetaDataKey (a.k.a. Account-Meta-Temp-Url-Key) you need an auth-token and then follow the instructions here.

Note that API-Key, Auth-Token, Meta-Data-Key are not the same thing:

API-Key is what you need to obtain an Auth-Token, which in turn is what you need to setup CORS and to set your Meta-Data-Key. The auth-token expires after 24 hours.

For your directive you need container and provide its name, region and cdn.

Slingshot.createDirective("rackspace-files-example", Slingshot.RackspaceFiles, {
  container: "myContainer", //Container name.
  region: "lon3", //Region code (The default would be 'iad3').

  //You must set the cdn if you want the files to be publicly accessible:
  cdn: "https://abcdefghije8c9d17810-ef6d926c15e2b87b22e15225c32e2e17.r19.cf5.rackcdn.com",

  pathPrefix: function (file) {
    //Store file into a directory by the user's username.
    var user = Meteor.users.findOne(this.userId);
    return user.username;
  }
});

To setup CORS you also need to your Auth-Token from above and use:

curl -I -X POST -H 'X-Auth-Token: yourAuthToken' \
  -H 'X-Container-Meta-Access-Control-Allow-Origin: *' \
  -H 'X-Container-Meta-Access-Expose-Headers: etag location x-timestamp x-trans-id Access-Control-Allow-Origin' \
  https://storage101.containerRegion.clouddrive.com/v1/MossoCloudFS_yourAccoountNumber/yourContainer

Cloudinary

Cloudinary is supported via a 3rd party package.
jimmiebtlr:cloudinary

Browser Compatibility

Currently the uploader uses XMLHttpRequest 2 to upload the files, which is not supported on Internet Explorer 9 and older versions of Internet Explorer.

This can be circumvented by falling back to iframe uploads in future versions, if required.

Latency compensation is available in Internet Explorer 10.

Security

The secret key never leaves the meteor app server. Nobody will be able to upload anything to your buckets outside of your meteor app.

Instead of using secret access keys, Slingshot uses a policy document that is sent to along with the file AWS S3 or Google Cloud Storage. This policy is signed by the secret key and contains all the restrictions that you define in the directive. By default a signed policy expires after 5 minutes.

Adding Support for other storage Services

Cloud storage services are pluggable in Slingshot. You can add support for a cloud storage service of your choice. All you need is to declare an object with the following parameters:

MyStorageService = {

  /**
   * Define the additional parameters that your your service uses here.
   *
   * Note that some parameters like maxSize are shared by all services. You do
   * not need to define those by yourself.
   */


  directiveMatch: {
    accessKey: String,

    options: Object,

    foo: Match.Optional(Function)
  },

  /**
   * Here you can set default parameters that your service will use.
   */

  directiveDefault: {
    options: {}
  },


  /**
   *
   * @param {Object} method - This is the Meteor Method context.
   * @param {Object} directive - All the parameters from the directive.
   * @param {Object} file - Information about the file as gathered by the
   * browser.
   * @param {Object} [meta] - Meta data that was passed to the uploader.
   *
   * @returns {UploadInstructions}
   */

  upload: function (method, directive, file, meta) {
    var accessKey = directive.accessKey;

    var fooData = directive.foo && directive.foo.call(method, file, meta);

    //Here you need to make sure that all parameters passed in the directive
    //are going to be enforced by the server receiving the file.

    return {
      // Endpoint where the file is to be uploaded:
      upload: "https://example.com",

      // Download URL, once the file uploaded:
      download: directive.cdn || "https://example.com/" + file.name,

      // POST data to be attached to the file-upload:
      postData: [
        {
          name: "accessKey",
          value: accessKey
        },
        {
          name: "signature",
          value: signature
        }
        //...
      ],

      // HTTP headers to send when uploading:
      headers: {
        "x-foo-bar": fooData
      }
    };
  },

  /**
   * Absolute maximum file-size allowable by the storage service.
   */

  maxSize: 5 * 1024 * 1024 * 1024
};

Example Directive:

Slingshot.createDirective("myUploads", MyStorageService, {
  accessKey: "a12345xyz",
  foo: function (file, metaContext) {
    return "bar";
  }
});

Dependencies

Meteor core packages:

  • underscore
  • tracker
  • reactive-var
  • check

Troubleshooting and Help

If you are having any queries about how to use slingshot, or how to get it to work with the different services or any other general questions about it, please post a question on Stack Overflow. You will get a high quality answer there much quicker than by posting an issue here on github.

Bug reports, Feature Requests and Pull Requests are always welcome.

API Reference

Directives

General (All Services)

authorize: Function (required unless set in File Restrictions)

maxSize: Number (required unless set in File Restrictions)

allowedFileTypes RegExp, String or Array (required unless set in File Restrictions)

cdn String (optional) - CDN domain for downloads. i.e. "https://d111111abcdef8.cloudfront.net"

expire Number (optional) - Number of milliseconds in which an upload authorization will expire after the request was made. Default is 5 minutes.

AWS S3 (Slingshot.S3Storage)

region String (optional) - Default is Meteor.settings.AWSRegion or "us-east-1". See AWS Regions

AWSAccessKeyId String (required) - Can also be set in Meteor.settings.

AWSSecretAccessKey String (required) - Can also be set in Meteor.settings.

AWS S3 with Temporary Credentials (Slingshot.S3Storage.TempCredentials)

region String (optional) - Default is Meteor.settings.AWSRegion or "us-east-1". See AWS Regions

temporaryCredentials Function (required) - Function that generates temporary credentials. It takes a signle argument, which is the minumum desired expiration time in milli-seconds and it returns an object that contains AccessKeyId, SecretAccessKey and SessionToken.

Google Cloud Storage (Slingshot.GoogleCloud)

bucket String (required) - Name of bucket to use. The default is Meteor.settings.GoogleCloudBucket.

GoogleAccessId String (required) - Can also be set in Meteor.settings.

GoogleSecretKey String (required) - Can also be set in Meteor.settings.

AWS S3 and Google Cloud Storage

bucket String (required) - Name of bucket to use. The default is Meteor.settings.GoogleCloudBucket. For AWS S3 the default bucket is Meteor.settings.S3Bucket.

bucketUrl String or Function (optional) - Override URL to which files are uploaded. If it is a function, then the first argument is the bucket name. This url also used for downloads unless a cdn is given.

key String or Function (required) - Name of the file on the cloud storage service. If a function is provided, it will be called with userId in the context and its return value is used as the key. First argument is file info and the second is the meta-information that can be passed by the client.

acl String (optional)

cacheControl String (optional) - RFC 2616 Cache-Control directive

contentDisposition String or Function (optional) - RFC 2616 Content-Disposition directive. Default is the uploaded file's name (inline). If it is a function then it takes the same context and arguments as the key function. Use null to disable.

Rackspace Cloud (Slingshot.RackspaceFiles)

RackspaceAccountId String (required) - Can also be set in Meteor.settings.

RackspaceMetaDataKey String (required) - Can also be set in Meteor.settings.

container String (required) - Name of container to use.

region String (optional) - Data Center region. The default is "iad3". See other regions

pathPrefix String or Function (required) - Similar to key for S3, but will always be appended by file.name that is provided by the client.

deleteAt Date (optional) - Absolute time when the uploaded file is to be deleted. This attribute is not enforced at all. It can be easily altered by the client

deleteAfter Number (optional) - Same as deleteAt, but relative.

File restrictions

authorize Function (optional) - Function to determines if upload is allowed.

maxSize Number (optional) - Maximum file-size (in bytes). Use null or 0 for unlimited.

allowedFileTypes RegExp, String or Array (optional) - Allowed MIME types. Use null for any file type.

meteor-slingshot's People

Contributors

1e0ng avatar aladine avatar callmephilip avatar dooart avatar gitter-badger avatar gsuess avatar jgraham-amplify avatar jimmiebtlr avatar jlouzado avatar markdowney avatar ogourment avatar pagebakers avatar xoddong avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

meteor-slingshot's Issues

Rackspace Support

Any plans on bringing in Rackspace cloud files support any time soon?

Version 0.3.0 crashes...?

After upgrading from 0.2.0 to 0.3.0 my meteor application now crashes with the following:

W20150112-11:01:00.593(0)? (STDERR) 
W20150112-11:01:00.593(0)? (STDERR) /Users/siyfion/.meteor/packages/meteor-tool/.1.0.38.15hfw32++os.osx.x86_64+web.browser+web.cordova/meteor-tool-os.osx.x86_64/dev_bundle/server-lib/node_modules/fibers/future.js:173
W20150112-11:01:00.594(0)? (STDERR)                         throw(ex);
W20150112-11:01:00.594(0)? (STDERR)                               ^
W20150112-11:01:00.616(0)? (STDERR) Error: Match error: Unknown key in field domain
W20150112-11:01:00.616(0)? (STDERR)     at packages/check/match.js:299:1
W20150112-11:01:00.617(0)? (STDERR)     at Function._.each._.forEach (packages/underscore/underscore.js:113:1)
W20150112-11:01:00.617(0)? (STDERR)     at checkSubtree (packages/check/match.js:290:1)
W20150112-11:01:00.617(0)? (STDERR)     at check (packages/check/match.js:32:1)
W20150112-11:01:00.617(0)? (STDERR)     at new Slingshot.Directive (packages/edgee:slingshot/lib/directive.js:111:1)
W20150112-11:01:00.617(0)? (STDERR)     at Object.Slingshot.createDirective (packages/edgee:slingshot/lib/directive.js:81:1)
W20150112-11:01:00.617(0)? (STDERR)     at app/server/file_uploads.js:1:46
W20150112-11:01:00.618(0)? (STDERR)     at app/server/file_uploads.js:26:3
W20150112-11:01:00.618(0)? (STDERR)     at /Users/siyfion/Meteor/lll/.meteor/local/build/programs/server/boot.js:175:10
W20150112-11:01:00.618(0)? (STDERR)     at Array.forEach (native)
=> Exited with code: 8
=> Your application is crashing. Waiting for file change.

Content-Disposition header

Hello, thanks for this awesome package.

I need upload files with the header "Content-Disposition": "attachment"; and keep the file name by default.

"Content-Disposition": 'attachment; filename=' + file.name

Is this possible?

Thanks!

Upload performance

Thanks for this great package and thorough Readme with examples.

I am handling some PDF uploads that are 0x.x MB in size and they are taking several minutes to complete. This is much, much slower than my connection speed would imply.

Is there something I need to do on my size or AWS to improve this?

aborting an upload

I've read through the Upload object, couldn't see any such functionality.

Is there currently a way to do that? should there be one?

How do you upload a blob?

var blob = createdblob;

uploader.send(blob, function (error, downloadUrl) {
Meteor.users.update(Meteor.userId(), {$push: {"profile.files": downloadUrl}});
});

Console error: Not a file

S3 returns 403 Forbidden

I think it's not related to this package. I configured CORS exactly same as in README.

Is there anyone who faced this issue? Please help me.

Thank you.

Preload file constrains for directives on the client

It would be good to allow the client to validate the file against the size and file-type before making a round trip to the meteor server, without having to duplicate the parameters in the directive server side and client side.

In a nutshell something along the lines of:

var uploader = new Slingshot.Upload("myDirective");

if (file.size <= uploader.maxSize)
   uploader.send(file);
else
   this.error.set("File is too large");

404 not found when uploading

here is the error message:

GET blob:http%3A//localhost%3A3003/535c7eb4-a6e4-448c-b5d6-6e33246aa7a9/ 404 (Not Found)

idk whats going on, I can use slingshot on the old version, but with the latest version there is error like this.

Thanks

Possible to upload from url?

Hello,
I must say this is really nice concept lightweight on resources I want to use this package it's amazing. But I also have another use of uploading images from URL server side, so I was wondering if it's also possible to upload images from url's and receive back the amazon s3 url?

upload to US Standard region failing with 0.4.0

Hi,

A "meteor update" broke my previously working setup in which I configure slingshot with a --settings CLI argument containing the following (substituting my actual values):

{"AWSAccessKeyId": "my_key",
 "AWSSecretAccessKey": "my_secret_key",
 "S3Bucket": "my_bucket"}

In the browser JS console, the first error I see is:

OPTIONS https://my_bucket.s3-us-east-1.amazonaws.com/ net::ERR_NAME_NOT_RESOLVED

This arises in the line xhr.send(buildFormData()); in upload.js.

And indeed, the DNS name does not resolve. However, my_bucket.s3.amazonaws.com does resolve and, as far as I can tell, this was the name slingshot 0.3.0 would use.

So it seems, at least for my use of slingshot without setting the "region" variable, the code is now broken.

Support for Audio (.mp3, .ogg) File Types

From the readme file: "This directive will not allow any files other than images to be uploaded. The policy is directed by the meteor app server and enforced by AWS S3."

I am primarily concerned with uploading Audio files at the moment, is this even a possibility with this package or should I look into other options?

Persistent uploads

Improve file uploader so that uploads can be resumed after connection has been interrupted.

Use Slingshot with DropzoneJS?

I've been trying to use dropzone with slingshot for couple of days now.. dropzone requires url to post to directly... do you have any idea how I can accomplish this?

Thanks

Forbidden 403 when using this.uploader.url(true)

When I was using this code from example

<template name="myPicture">
  <img src={{url}}/>
</template>
Template.myPicture.helpers({
  url: function () {
    //pass true to download the image into cache (preload) before using it.
    return this.uploader.url(true);
  }
});

I am getting error message:
GET https://piyiku.s3.amazonaws.com/brendan-rodgers-soccer-friendly-manchester-city-vs-liverpool-fc-850x560.jpg/ 403 (Forbidden)

The image actually have been uploaded correctly, but I can't display the image using above helpers example.

Any suggestion about this?

Thanks

using multiple Upload objects on the same page

hey

I have 2 directives, with distinct names and buckets
I happen to use the 2 of them on the same page, where each directive is invoked in a separate [included] template

problem is Upload A actually uses the settings of Upload B, so I end up uploading file of A to bucket B

is this a known issue?

Pass arguments createDirective

Is it possible to pass arguments to the createDirective function, so that one can use such when creating the key/filename?

AWS secret keyname mismatch

From the docs: "You will need aAWSAccessKeyId and AWSSecretAccessToken ins Meteor.settings"

I tried it, but I need to set AWSSecretAccessKey and not AWSSecretAccessToken.

Cordova File URI

Can we pass either DATA_URL or FILE_URI from Cordova's navigator.camera.getPicture to the first parameter of uploader.send?

Right now it seems that we need to pass the file object from an input with type="file"

How to check if the file really exists?

Someone could just call

Meteor.users.update(Meteor.userId(), {$push: {"profile.files": url}});

to save to the DB, without checking the file. There is no feature built-in, isn't it?

Should I use the aws-sdk to check the file?

Error: Match error: Expected plain object

When I get to this part in my example

uploader.send(document.getElementById('input').files[0], function (error, url) {
  Meteor.users.update(Meteor.userId(), {$push: {"profile.files": url}});
});

it always fails with error in view.js:406

Error: Match error: Expected plain object

500 error when trying to upload from Meteor using slingshot package

I have a javascript file in the server side that looks like this

Slingshot.GoogleCloud.directiveDefault.GoogleSecretKey = Assets.getText('google-cloud-service-key.pem');


Slingshot.createDirective("myFileUploads", Slingshot.GoogleCloud, {
  bucket: "enwave",
  GoogleAccessId: "randomID",

 authorize: function () {
   //Deny uploads if user is not logged in.
   if (!this.userId) {
     var message = "Please login before posting files";
     throw new Meteor.Error("Login Required", message);
   }

   return true;
 },

 key: function (file) {

   //Store file into a directory by the user's username.
   var user = Meteor.users.findOne(this.userId);
   return user.username + "/" + file.name;
 }
});

I have this on my client side

'change #fileUpload':function(event, template){
      //evt.preventDefault();
      var file = event.currentTarget.files[0];
      console.log(file);

      var uploader = new Slingshot.Upload("myFileUploads");
      uploader.send(document.getElementById('fileUpload').files[0], function (error, downloadUrl) {
      Meteor.users.update(Meteor.userId(), {$push: {"profile.files": downloadUrl}


      });

      });

    }

I have this in my lib folder

Slingshot.fileRestrictions("myFileUploads", {
  allowedFileTypes: ["image/png", "image/jpeg", "image/gif"],
  maxSize: 10 * 1024 * 1024 // 10 MB (use null for unlimited)
});

and in /private folder I have a google-cloud-service-key.pem file that I converted after downloading from google cloud.

I get this error when choosing a image in the file upload input

 POST https://enwave.storage.googleapis.com/ 500 (OK)
debug.js:41 update failed: Access denied

I must be doing something wrong, google says a 500 error in google cloud is a internal server error, but I must be doing something wrong, I highly doubt it is on googles end. I am also testing off of localhost if that might be it.

Thanks in Advance for any help.

After log the error in the console, this is what I get

http://i.stack.imgur.com/pffI4.png

Add unique error keys?

Can we add unique error keys to "throw new Meteor.Error" errors? So there would be a way to translate/customize the error message. E.g, I am missing a unique key for:

// lib/directive.js
throw new Meteor.Error("Upload denied", "File exceeds allowed size of " +
      formatBytes(maxSize));

You are using the "Upload denied" key for many "Meteor.Error"s, therefore, there is no easy way to translate the corresponding error message. Or do you have a better way to show the customized message to the user?

Thanks!

Server-side uploader

Make the uploader work on the server side with the same API. The only difference: it takes an asset name (string) instead of a File object. Also, of course there will be no reactivity on its methods on the server-side.

400 (bad request)

Hi, I got this error but the weird thing is I run the same code on multiple pc but only one of them got this error.
400 bad request

Add more info to errors

For instance, all I see from this line

return new Meteor.Error(xhr.statusText + " - " + xhr.status,

is

 Error: Failed to upload file to cloud storage [Bad Request - 400]
    at getError (upload.js:163)
    at XMLHttpRequest.<anonymous> (upload.js:176)

and I have no idea what went wrong. But the xhr does have more informative fields:

image

Thanks for this great package!

Getting Insecure response error

I followed the example provided to upload to my s3 bucket, and added the CORS config. I left the policy blank, as slingshot is supposed to generate the policy on uploads.

But I am getting an error saying :
OPTIONS https://dev.mybucket.s3.amazonaws.com/ net::ERR_INSECURE_RESPONSE
update failed: Access denied

Am I missing something? I am currently testing from localhost.

Add local storage

Cloud storage is great for production, but may be hard to set up. Add a local storage adapter in which files are uploaded to the meteor app, using the same file uploader.

With this you can try the package and then easily switch to cloud storage.

Progress bar question

When using the progress bar I'm running into an issue when I use this as a template. I have copied and pasted in the exact code you have on github. Then I'm including it as a template within my main page {{progressBar}}.

I'm getting:

Exception in template helper: TypeError: Cannot read property 'progress' of undefined

It looks to me that it's not realizing the uploader instance. I've tried moving the upload constructor to the Template.myPage.render function (as well as some other things) and am not able to figure it out.

Any help would be appreciate with this. Thank you in advance! -Chris

Currently I have the code within my form submit function:

Template.imagesSubmitTpl.events({
  'submit form': function(e, template) {
    e.preventDefault();

    // Saving to Amazon S3
    var metaContext = {
      projectId: this._id
    }

    var uploader = new Slingshot.Upload("imagesCleaved", metaContext);

    uploader.send(document.getElementById('imageUpload-js').files[0], function (error, downloadUrl) {
      // Client-side error handling
      if (error) {
        console.error(error);
      }

      // Saving to the DocumentsCollection in Mongodb (upon successful save to Amazon S3)
      // Stripping out the full file path and saving only the image name itself
      var imageInput = $(e.target).find('#imageUpload-js').val();
      var imageFileName = imageInput.split('\\').pop().split('/').pop();

      var images = {
        projectId: template.data._id,
        imageFileName: imageFileName,
        imageName: $(e.target).find('[name=imageName-js]').val(),
        imageUrl: downloadUrl,
        imageNote: $(e.target).find('[name=imageNote-js]').val()
      };

      Meteor.call('imagesInsert', images, function(error, result){
        if (error){
          return alert(error.reason);
        }

        //Clear form
        $('#upload-images-entry-js')[0].reset();
      });
    });
  }
});

Progress bar code:
I'm including your code as a template, unmodified at the moment.

What about downloads?

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?

Pre-load images for latency compensation

Currently .url() will switch to the cloud hosted image as soon as the file was uploaded. When used as an image, this will make it go blank until the image is downloaded again.

This can be circumvented by pre-loading the image first.

Files with no type instafail

Since you have a check that, for some reason, seems to validate that every file has a */* matching type, but if the browser cannot detect the MIME type it just passes an empty string.

How to enable users to delete uploaded files?

Awesome looking package.

I'm considering it for a project in the works but first have a perhaps silly question: How would one enable users to download uploaded content with Meteor Slingshot? The readme doesn't seem to mention doing much with the file(s) once uploaded... perhaps it's solely focused on uploading (hence the name Meteor slingshot). Is this beyond the package's scope?

Example folder

It's no doubt my own incompetence at fault, but I'm unclear on how to implement the server-side part of Slingshot.

I wonder if there's an sample Meteor project anywhere that would show how to get set up (in the context of an entire project, as opposed to just the code samples in your README)?

Thanks.

support upload of objects other than File

currently I must pass a File object, which is fine if I have an input type=file. What if I try to manipulate an image before uploading? Or try to have the browser generate derivatives for an image and upload those as well? So what if all I have to upload is the dataUrl of a canvas?

Allow for uploads with no userId

Currently it seems you have to be a signed-in user to create an upload:

var context = {
    userId: Meteor.userId()
};

(line 70, upload.js)

Is there a way we can avoid that restriction? I can think of a few scenarios where it wouldn't be necessary.

Delete files off S3

Feature request:

Are there any plans to allow the user to delete/remove files off amazon S3 storage?

Thanks and will talk with you soon. -Chris

S3 region issue

First off, awesome work on this plugin.

I did find an issue with getting slingshot to work with an S3 bucket that's not initialized to the default region (i.e. 'US Standard').

To make sure it was just a region issue, I tried following along with the simple example in the README an posting to 3 different S3 buckets, which are all under the same account, and have gotten the same CORS configuration.

First I added the directive server-side, added the AWS key and secret to Meteor.settings, and configured the S3 buckets. Then I used the uploader from the client using the console:

var t = document.getElementById('test').files[0]
File {webkitRelativePath: "", lastModified: 1393941506000, lastModifiedDate: Tue Mar 04 2014 14:58:26 GMT+0100 (CET), name: "bicycle_road.jpeg", type: "image/jpeg"…}
var uploader = new Slingshot.Upload("myFileUploads");
Slingshot.Upload {status: function, progress: function, uploaded: function, send: function, request: function…}
uploader.send(t, function(err, downloadUrl) {
if (err) {console.dir(err);} else {console.dir(downloadUrl);}
});

Here are the issues I ran into following along with the example in the README:

  1. S3 bucket region: Frankfurt
    console error log:
POST https://fotoposterdev.s3.amazonaws.com/ 400 (Bad Request)
VM3007:3 Meteor.makeErrorType.errorClassdetails: undefinederror: "Bad Request - 400"errorType: "Meteor.Error"message: "Failed to upload file to cloud storage [Bad Request - 400]"reason: "Failed to upload file to cloud storage"stack: (...)get stack: function () { [native code] }set stack: function () { [native code] }__proto__: _.extend._inherits.Middle 
  1. S3 bucket region: Oregon
    console error log:
 XMLHttpRequest cannot load https://fpawdev.s3.amazonaws.com/. The request was redirected to 'https://fpawdev.s3-us-west-2.amazonaws.com/', which is disallowed for cross-origin requests that require preflight.
VM3265:3 Meteor.makeErrorType.errorClassdetails: undefinederror: " - 0"errorType: "Meteor.Error"message: "Failed to upload file to cloud storage [ - 0]"reason: "Failed to upload file to cloud storage"stack: (...)get stack: function () { [native code] }set stack: function () { [native code] }__proto__: _.extend._inherits.Middle
  1. S3 bucket region: US Standard ==> SUCCESS
    console log:
Slingshot.Upload {status: function, progress: function, uploaded: function, send: function, request: function…}
VM3534:3 https://fptestdev.s3.amazonaws.com/undefined/bicycle_road.jpeg

Null not working with maxSize

From the API reference: "Number (required) - Maximum file-size (in bytes). Use null for unlimited."

I tried it, but null for unlimited is not working. A number is required.

createDirective requires maxSize and allowedFileTypes?

According to example in README, I have both those fields in a fileRestrictions call in lib/env.js, and neither in the createDirective call in server/lib/env.js. I get this error:

W20150123-18:16:49.057(-8)? (STDERR) Error: Match error: Missing key 'maxSize'
W20150123-18:16:49.058(-8)? (STDERR)     at packages/check/match.js:312:1
W20150123-18:16:49.058(-8)? (STDERR)     at Function._.each._.forEach (packages/underscore/underscore.js:113:1)
W20150123-18:16:49.058(-8)? (STDERR)     at checkSubtree (packages/check/match.js:311:1)
W20150123-18:16:49.058(-8)? (STDERR)     at check (packages/check/match.js:32:1)
W20150123-18:16:49.058(-8)? (STDERR)     at new Slingshot.Directive (packages/edgee:slingshot/lib/directive.js:111:1)
W20150123-18:16:49.058(-8)? (STDERR)     at Object.Slingshot.createDirective (packages/edgee:slingshot/lib/directive.js:81:1)
W20150123-18:16:49.058(-8)? (STDERR)     at server/lib/environment.coffee:35:11
W20150123-18:16:49.058(-8)? (STDERR)     at server/lib/environment.coffee:4:1
W20150123-18:16:49.058(-8)? (STDERR)     at /Users/me/Dropbox/Documents/code/parlay/.meteor/local/build/programs/server/boot.js:205:10
W20150123-18:16:49.058(-8)? (STDERR)     at Array.forEach (native)

I don't get the error when I add them to createDirective.

Validate function: TypeError

I'm using Slingshot 0.4.1 and I'm getting the following error:

// lib/uploads.js
validate: function(file) {
  var context = {
    userId: Meteor.userId() // Uncaught TypeError: undefined is not a function
  };
  try {
    var validators = Slingshot.Validators,
        restrictions = Slingshot.getRestrictions(directive);

    validators.checkAll(context, file, metaData, restrictions) && null;
  } catch(error) {
    return error;
  }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.