1

In continuation of building Google SpreadSheet using Google Apps Script I've done with getting my Bittrex and Poloniex balances, but can't get to work with Cryptopia.

Here is a link to my struggles with Bittrex Map JSON objects array to strings

Here is an official API links: https://www.cryptopia.co.nz/Forum/Thread/256

Here are some examples:

  1. https://www.cryptopia.co.nz/Forum/Thread/262
  2. https://github.com/Coac/cryptopia.js/blob/master/index.js
  3. https://github.com/sigwo/node-cryptopia/blob/master/cryptopia.js

Here is my code, which getting "Invalid authorization header" error:

// Get Cryptopia balances
  var key = keys.getRange("B4").getValue();
  var secret = keys.getRange("C4").getValue();
  var baseUrl = 'https://www.cryptopia.co.nz/api/';

  var command = "GetBalance";    
  var url = baseUrl + command;

  var signature = key + "POST" + encodeURIComponent(url).toLowerCase() + nonce;
  var hmacsignature = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_256,signature,secret);

  var header_value = "amx " + key + ":" + hmacsignature + ":" + nonce;
  var headers = { 'Authorization': header_value, 'Content-Type':'application/json; charset=utf-8' };

  var options = {
    method: 'POST',
    headers: headers
  };

  var response = UrlFetchApp.fetch("https://www.cryptopia.co.nz/api/GetBalance", options);
  var json = JSON.parse(response.getContentText());
}
Joe
  • 41,484
  • 20
  • 104
  • 125
Sergey Sypalo
  • 1,223
  • 5
  • 16
  • 35

2 Answers2

0

From your sample links, it seems that hmacsignature is encoded by base64. So how about the following modofication?

From :

var hmacsignature = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_256,signature,secret);

To :

var hmacsignature = Utilities.base64Encode(Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_256,signature,secret));

Note :

  • Is nonce declared? If you have not declared it, you can use a following script.
    • var nonce = Math.floor(new Date().getTime() / 1000);

I cannot test this. So I don't know whether this works fine. If this didn't work, I'm sorry.

Edit :

How about this? var params = {}; might be required, even if there is no request parameters. So I added this and Content-Length. And then, is secret encoded by base64? I thought that it may be encoded from other scripts.

var key = keys.getRange("B4").getValue();
var secret = keys.getRange("C4").getValue();
var nonce = Math.floor(new Date().getTime() / 1000); // Added
var params = {}; // Added
var baseUrl = 'https://www.cryptopia.co.nz/api/';
var command = "GetBalance";
var url = baseUrl + command;
var requestContentBase64String = Utilities.base64Encode(Utilities.computeDigest(Utilities.DigestAlgorithm.MD5, JSON.stringify(params), Utilities.Charset.UTF_8)); // Added
var signature = key + "POST" + encodeURIComponent(url).toLowerCase() + nonce + requestContentBase64String; // Modified
var hmacsignature = Utilities.base64Encode(Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_256, signature, Utilities.base64Decode(secret), Utilities.Charset.UTF_8)); // Modified
var header_value = "amx " + key + ":" + hmacsignature + ":" + nonce;
var headers = {
  "Authorization": header_value,
  "Content-Type": 'application/json; charset=utf-8',
  "Content-Length" : Utilities.newBlob(JSON.stringify(params)).getBytes().length // Added
};
var options = {
  method: 'POST',
  headers: headers
};
var response = UrlFetchApp.fetch(url, options);
var json = JSON.parse(response.getContentText());
Tanaike
  • 181,128
  • 11
  • 97
  • 165
  • Now it's returning 401 Error which means Not Authorized, but I'm providing correct key and secret. – Sergey Sypalo Dec 22 '17 at 22:21
  • @Sergey Sypalo Thank you for your reply. I'm sorry for the inconvenience. Did the error message changed? I cannot test about this. So I would like to think of this situation from sample links. When I proposal a next modification, I will tell you. I'm really sorry for my poor skill. – Tanaike Dec 22 '17 at 23:17
  • Np, thx for the idea. I'll try to do the same in C# and run using debugging enabled. What to compare some working result with not working one varilble value by one to see what's wrong. – Sergey Sypalo Dec 24 '17 at 17:26
  • @Sergey Sypalo I updated my answer. Please confirm it. If this didn't work, I'm sorry. If the error message is changed, please tell me about it. – Tanaike Dec 25 '17 at 02:22
  • Thx again, now it looks better, but still complaining about Content-Length value. So I had to define another one variable cl = Utilities.newBlob(JSON.stringify(params)).getBytes().length and use it in headers. And when run debug script can't send the request because of unexpected value of cl variable, which value is "2.0" – Sergey Sypalo Dec 25 '17 at 22:41
  • @Sergey Sypalo I'm sorry for the inconvenience. For example, how about modifying ``Content-Length`` to ``"Content-Length" : 0``? Because there is no body in your case. ``Utilities.newBlob(JSON.stringify(params)).getBytes().length`` means 2 bytes of ``{}``. – Tanaike Dec 25 '17 at 22:50
0

Utilities.computeHmacSignature(algorithm, value, key) method does not compute the binary input correctly. The type of value and key parameter is String, but Utilities.base64Decode's result is Byte[]. The raw binary value is changed while being converted from Byte[] to String.

Use jsSHA, and cf. https://stackoverflow.com/a/14007167.

The following can be used to calculate the correct value, and fetch the result by proper UrlFetchApp.fetch's options.

.... paste src/sha256.js contents ...

...  
var params = {"Currency" : "BTC"};
...
var sha = new jsSHA("SHA-256", "TEXT");
sha.setHMACKey(secret, "B64");
sha.update(signature);
var hmacsignature = sha.getHMAC("B64");

var header_value = "amx " + key + ":" + hmacsignature + ":" + nonce;
var headers = {
  "Authorization" : header_value,
};

var options = {
  "contentType": 'application/json; charset=utf-8',
  "method": 'post',
  "headers": headers,
  "payload": JSON.stringify(params),
  "contentLength": JSON.stringify(params).length
};

var response = UrlFetchApp.fetch(url, options);
var json = JSON.parse(response.getContentText());

Logger.log(json);
bugiii
  • 29
  • 2