Pat-rice
Pat-rice

Reputation: 432

Upload S3 knox node js (signature doesnt match)

I've been trying for many days now to upload a file (message.txt) to aws s3 using knox and node js.

I keep having a signature doesnt match error.

my code in node js (upload was not working so i'm just trying to do a get) :

var client = knox.createClient({
    key: 'myAWSkey'
  , secret: 'mySecretKey'
  , bucket: 'mybucket'
  , endpoint: 'mybucket.s3-eu-west-1.amazonaws.com'
});
client.get('/').on('response', function(res){
  console.log(res.statusCode);
  console.log(res.headers);
  res.setEncoding('utf8');
  res.on('data', function(chunk){
    console.log(chunk);
  });
}).end();

I also tried the amazon to compare the test signature with many different methods like this one : html and python version

Nothing worked for me, I'm probably a bit lost in the process... If someone could give me some big lines to guide me and/or a script to generate correctly a signature in javascript/node js I would be very grateful.

Upvotes: 1

Views: 1652

Answers (3)

Sandeep Kumar
Sandeep Kumar

Reputation: 692

For NodeJS, there is an API which helps to generate Signature. It is available at NPM repo with name aws4.

Can refer from link: https://www.npmjs.com/package/aws4

To download and install, use below command:

npm i aws4

Can add in package.json file

{
  "dependencies": {
    "aws4": "^1.11.0",
    "https": "^1.0.0",
    "crypto": "^1.0.1"
  }
}

Following parameters are used for generating signature:

  • host: host of service, mandatory
  • path: Path of the file being uploaded, mandatory
  • service: Service name e.g. s3
  • region: Region name e.g. us-east-1
  • method: HTTP method e.g. GET, PUT
  • accessKeyId: Access Key ID for the service, mandatory
  • secretAccessKey: Secret for access key id, mandatory
  • sessionToken: Temporary session token, optional

Use below code to upload a file:

var https = require('https')
var aws4  = require('aws4')
var crypto = require('crypto');
var fs = require('fs');

var fileBuffer = fs.readFileSync('1.jpg'); //File name from local which need to upload
var hashSum = crypto.createHash('sha256'); 
hashSum.update(fileBuffer);
var hex = hashSum.digest('hex'); //Generate SHA256 from the file


var opts = aws4.sign({
  host: '<host name for the s3 service>',
  path: '<bucket and file path in s3>',
  service: 's3',
  region: 'us-east-1',
  method: 'PUT',
  
  headers: {
    'X-Amz-Content-Sha256': hex
  },
  body: undefined
}, { 
  accessKeyId: '<access key>', 
  secretAccessKey: '<secret key>'
  sessionToken: '<session token>'
}
)

opts.path = '<complete path: https://host+bucket+filepath>';
opts.headers['Content-Type'] = 'image/jpeg'; //Content type of the file
opts.headers['User-Agent'] = 'Custom Agent - v0.0.1'; //Agent name, optional
opts.headers['Agent-Token'] = '47a8e1a0-87df-40a1-a021-f9010e3f6690'; // Agent unique token, optional
opts.headers['Content-Length'] = fileBuffer.length; //Content length of the file being uploaded

console.log(opts) //It will print generated Signature

var req = https.request(opts, function(res) {
    
  console.log('STATUS: ' + res.statusCode);
  console.log('HEADERS: ' + JSON.stringify(res.headers));
  res.setEncoding('utf8');

  res.on('data', function (chunk) {
    console.log('BODY: ' + chunk);
  });
  
});

req.on('error', function(e) {
  console.log('problem with request: ' + e.message);
});

req.write(fileBuffer);
req.end();

Note: The SHA256 is generated manually and passed into the argument before generating signature and body set as undefined in aws4.sign() method. This important when uploading a file as binary data therefore, SHA256 is generated and set before aws4.sign() method call.

This same API can be used for all different calls e.g. GET call for file download.

The sessionToken is optional as it is only required for the cases where temporary session token is generated for accessing S3 service.

Upvotes: 0

chilts
chilts

Reputation: 451

You might want to try the AwsSum library. It's actively maintained and also comes with a load of examples and another repo with more fully featured scripts.

And for your needs, there is an example upload script in the scripts repo (separate GitHub project):

Let me know if you need any help or if you get on ok. Disclaimer: I'm the author of AwsSum. :)

Upvotes: 2

ZECTBynmo
ZECTBynmo

Reputation: 3367

I just struggled with this issue for a few days. Assuming you're on Windows, it seems like it's an issue on Knox's end. Apparently the problem has been solved, but the solution has not not pulled into the main project yet.

See this thread: https://github.com/LearnBoost/knox/issues/56

My workaround was to just remove the knox library and clone this repository into my node_modules folder: https://github.com/domenic/knox.git

Hope that helps!

Upvotes: 0

Related Questions