5

I am trying to upload a file to Google Cloud Storage through an AngularJS App.

I want to use a Signed URL (so GCS Authentication details are not stored within the client side AngularJS App).

NodeJS Server Side

The follow code does return a Signed URL from GCS to the client.

var gcloud = require('google-cloud');
var storage = gcloud.storage;
var gcs = storage({
  projectId: 'Google Cloud Project ID',
  keyFilename: __dirname + '/Google Cloud Project Keys.json'
});
var bucket = gcs.bucket('Google Cloud Bucket Name');

router.get('/uploadurl', function(req, res) {
  var file = bucket.file('test.jpg');

  var config = {
    action: 'write',
    expires: '03-17-2025',
    cname: 'Google Cloud Bucket CName'
  };

  file.getSignedUrl(config, function(err, url) {
    if (err) {
      deferred.resolve(err);
    } else {
      deferred.resolve(url);
    }
  });

})

AngularJS Client Side

Client Side, using the Signed URL (uploadURL) I try to upload to GCS.

angular.module('admin').controller('appendProjectCtrl', function($scope, $http, Upload){

      $scope.$watch('projectImages', function () {
        $scope.upload($scope.projectImages, "projectImages");
      });

      $scope.$watch('file', function () {
        if ($scope.file != null) {
          $scope.files = [$scope.file];
        }
      });

      $scope.upload = function (files, uploadType) {
        console.log("files: ", files);
        if (files && files.length) {
          for (var i = 0; i < files.length; i++) {
            var file = files[i];
            if (!file.$error) {
              $http.get('/api/storage/uploadurl')
                .success(function(result) {
                  var uploadURL = result;

                  Upload.upload({
                    url: uploadURL,
                    file: file
                  }).then(function (resp) {
                    console.log("image upload: ", resp);
                  }, null, function (evt) {
                    console.log("evt: ", evt);

                    var progressPercentage = parseInt(100.0 *
                      evt.loaded / evt.total);
                    console.log(progressPercentage);

                    $scope.log = 'progress: ' + progressPercentage +
                      '% ' + evt.config.file.name + '\n' +
                      $scope.log;
                  });

                })
            }
          }
        }
      };
});

However the following error is returned:

<?xml version='1.0' encoding='UTF-8'?>
<Error>
    <Code>InvalidAuthentication</Code>
    <Message>The provided authentication header is invalid.</Message
    <Details>Cannot use Query String params with form POST.</Details>
</Error>

I understand from utilising Signed URLs in S3 (and others) that I should not need any further Authentication for the client other than pushing the file to the URL within the allocated timeframe.

I have checked CORS on Google Cloud Storage, and there does not appear to be an issue there either.

[{
   "maxAgeSeconds": 3600, 
   "method": ["GET", "HEAD", "POST", "DELETE", "PUT"], 
   "origin": ["https://regulardomain.com", "http://localhost:8199"],
   "responseHeader": ["*"]
}]

Any thoughts??

user2483
  • 51
  • 3

0 Answers0