2021年3月9日星期二

Google Apps Script: Getting Orders from Amazon Selling Partner API (Signing Requests)

I'm trying to create a request to Amazon Selling Partner API following this guide.

The first part: Creating an access has already been taken care of here.

The documentation of the API for Orders can be found here.

I'm trying to invoke the GET /orders/v0/orders operation.

Connecting to the API

The only mandatory parameter for this operation is the MarketplaceIds based on the documentation.

In order to get the orders we need to sign our request. Here is my code so far:

const ACCESS_ID = "MyAccessKey";  const ACCESS_KEY = "MyAccessSecret";    function GetOrders(){    var access_token = AccessToken();      //Time variables    var currentDate = new Date();    var isoDate = currentDate.toISOString();    var yearMonthDay= Utilities.formatDate(currentDate, 'GTM-5', 'yyyyMMdd');      //API variables    var end_point = 'https://sellingpartnerapi-eu.amazon.com';      //Credential variables    var aws_region = "eu-west-1";    var service = "sellingpartnerapi";    var termination_string = "aws4_request";      //CanonicalRequest = httpRequestMethod + '\n' + CanonicalURI + '\n' + CanonicalQueryString + '\n' + CanonicalHeaders + '\n' + SignedHeaders + '\n' + HexEncode(Hash(RequestPayload));    //CanonicalRequest components:    var httpRequestMethod = 'GET';    var canonicalURI = '/orders/v0/orders';    var canonicalQueryString = '?marketplaceId=A1PA6795UKMFR9';    var canonicalheaders = 'host:' + canonicalURI + '\n' + 'x-amz-access-token:' + access_token + '\n' + 'x-amz-date:' + isoDate;    var signedheaders = 'host;user-agent;x-amz-access-token;x-amz-date';      //Building the canonical request    var canonical_request = httpRequestMethod + '\n' + canonicalURI + '\n' + canonicalQueryString + '\n' + canonicalheaders + '\n' + signedheaders;    var canonical_signature = Utilities.computeHmacSha256Signature(canonical_string, ACCESS_KEY);    canonical_request = canonical_request + '\n' + canonical_signature;      //CredentialScope = Date + AWS region + Service + Termination string;    //StringToSign = Algorithm + \n + RequestDateTime + \n + CredentialScope + \n + HashedCanonicalRequest;    var credential_scope = yearMonthDay + '/' + aws_region + '/' + service + '/' + termination_string;    var string_to_sign = "AWS4-HMAC-SHA256" + '\n' + isoDate + '\n' + credential_scope + '\n' + canonical_request (not signed yet);      var kSecret = ACCESS_KEY;    var kDate = Utilities.computeHmacSha256Signature(yearMonthDay, "AWS4" + kSecret);    var kRegion = Utilities.computeHmacSha256Signature(Utilities.newBlob(aws_region).getBytes(), kDate);    var kService = Utilities.computeHmacSha256Signature(Utilities.newBlob(service).getBytes(), kRegion);    var kSigning = Utilities.computeHmacSha256Signature(Utilities.newBlob(termination_string).getBytes(), kService);        var signature = Utilities.computeHmacSha256Signature(kSigning, string_to_sign);    signature = signature.map(function(e) {return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2)}).join("");      var options = {      'method': 'GET',      'payload': {        'end_point': end_point,        'path': canonicalURI,        'query_string': canonicalQueryString        //Path parameter not needed      },      'headers': {        'host': end_point,        'x-amz-access-token': access_token,        'x-amz-date': isoDate,        'user-agent': 'GAS Script 1.0 (Javascript)',        'Authorization': 'AWS4-HMAC-SHA256 Credential=' + ACCESS_ID + '/' + credential_scope + ', SignedHeaders=' + signedheaders + ', Signature=' + signature,      },    }        var getOrders = UrlFetchApp.fetch(end_point, options);    Logger.log(getOrders);  }  

PROBLEMS

Following the Step 4. Create and sign your request, part 1. Create a canonical request, it is mentioned on their guide on item #6.

Use a hash (digest) function like SHA256 to create a hashed value from the payload in the body of the HTTP or HTTPS request. Example Structure of payload

HashedPayload = Lowercase(HexEncode(Hash(requestPayload)))

Question: What exactly is the payload? and how can we encode it as per the guide mentions?

This element is part of the canonical_string variable

var canonical_string = httpRequestMethod + '\n' + canonicalURI + '\n' + canonicalQueryString + '\n'                          + canonicalheaders + '\n' + signedheaders + '\n\ + HashedPayload??;  

It then mentions on item #8

Create a digest (hash) of the canonical request with the same algorithm that you used to hash the payload.

The hashed canonical request must be represented as a string of lowercase hexadecimal characters. The following example shows the result of using SHA-256 to hash the example canonical request.

Question: Creating a hash of the canonical request doesn't require that we use a key?

This is a possible solution but I'm not sure:

  //CanonicalRequest = httpRequestMethod + '\n' + CanonicalURI + '\n' + CanonicalQueryString + '\n' + CanonicalHeaders + '\n' + SignedHeaders + '\n' + HexEncode(Hash(RequestPayload));    //CanonicalRequest components:    var httpRequestMethod = 'GET';    var canonicalURI = '/orders/v0/orders';    var canonicalQueryString = '?marketplaceId=A1PA6795UKMFR9';    var canonicalheaders = 'host:' + canonicalURI + '\n' + 'x-amz-access-token:' + access_token + '\n' + 'x-amz-date:' + isoDate;    var signedheaders = 'host;user-agent;x-amz-access-token;x-amz-date';    //NEW    var requestPayloadHashed = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, "");    //NEW    requestPayloadHashed = requestPayloadHashed.map(function(e) {return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2)}).join("");      //Building the canonical request    //UPDATED    var canonical_string = httpRequestMethod + '\n' + canonicalURI + '\n' + canonicalQueryString + '\n' + canonicalheaders + '\n' + signedheaders + '\n' + requestPayloadHashed;    var canonical_signature = Utilities.computeHmacSha256Signature(canonical_string, ACCESS_KEY);    var canonical_request = canonical_string + '\n' + canonical_signature;    //NEW    canonical_request = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, canonical_request);      //CredentialScope = Date + AWS region + Service + Termination string;    //StringToSign = Algorithm + \n + RequestDateTime + \n + CredentialScope + \n + HashedCanonicalRequest;    var credential_scope = yearMonthDay + '/' + aws_region + '/' + service + '/' + termination_string;    var string_to_sign = "AWS4-HMAC-SHA256" + '\n' + isoDate + '\n' + credential_scope + '\n' + canonical_request;  

It mentions in the guide:

If the payload is empty, use an empty string as the input to the hash function.

But I fail to recognize what is the payload exactly.

Finally, Completing those steps would allow me to have a first complete version of the script that then I will be able to test, however, is it correct to invoke the API like this?

var getOrders = UrlFetchApp.fetch(end_point, options);  

ERRORS

When running the script I get the following error:

Exception: The parameters (number[],String) don't match the method signature for Utilities.computeHmacSha256Signature.

For this part of the code:

var signature = Utilities.computeHmacSha256Signature(kSigning, string_to_sign);  
https://stackoverflow.com/questions/66557069/google-apps-script-getting-orders-from-amazon-selling-partner-api-signing-requ March 10, 2021 at 09:20AM

没有评论:

发表评论