Here's what I have so far:
function sha256(stringToSign, secretKey) {
return CryptoJS.HmacSHA256(stringToSign, secretKey);
}
function getAmazonItemInfo(barcode) {
var parameters =
"Service=AWSECommerceService&"
+ "AWSAccessKeyId=" + appSettings.amazon.accessKey + "&"
+ "Operation=ItemLookup&"
+ "ItemId=" + barcode
+ "&Timestamp=" + Date.now().toString();
var stringToSign =
"GET\n"
+ "webservices.amazon.com\n"
+ "/onca/xml\n"
+ parameters;
var signature = "&Signature=" + encodeURIComponent(sha256(stringToSign, appSettings.amazon.secretKey));
var amazonUrl =
"http://webservices.amazon.com/onca/xml?"
+ parameters
+ signature;
// perform a GET request with amazonUrl and do other stuff
}
When executed as an HTTP GET request, the value of amazonUrl
in the above code results in the following response from Amazon:
<?xml version="1.0"?>
<ItemLookupErrorResponse xmlns="http://ecs.amazonaws.com/doc/2005-10-05/">
<Error>
<Code>SignatureDoesNotMatch</Code>
<Message>
The request signature we calculated does not match the signature you provided.
Check your AWS Secret Access Key and signing method. Consult the service
documentation for details.
</Message>
</Error>
<RequestId>[REMOVED]</RequestId>
</ItemLookupErrorResponse>
Useful links:
Use this Node.js library for AWS. It even includes an example specifically for the Product Advertising API.
I hacked around with your code and I got it working.
The Header of the Javascript I used for some reference.
You will need to modify parts of it because I changed some parameters around and don't reference your "app" object.
For what I did to fix it (from what I can recall).
The parameters have to be alphabetical. I placed them in an array and then sort them. I follow this up by a join with the ampersand.
I modified the sha256 function to return the base64 of the RAW sha256. Before it was returning the hexbits in lowercase, which isn't correct.
I was going to add a base64 before encoding, but the sha256 now handles all of the signing.
The date format was incorrect. It was returning a epoch timestamp instead of a string timestamp. I hacked together a simple timestamp option.
This code requires you to include the Base64 Library for CryptoJS also.
Building on David's great answer, I made some tweaks. The solution below uses moment.js and crytpo-js, and can be used to search for items by keyword. I used the amazon scratch-pad to help build the target call. A couple of things I noticed: