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:
https://www.cryptopia.co.nz/Forum/Thread/262
https://github.com/Coac/cryptopia.js/blob/master/index.js
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());
}
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());
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);
Related
I try a lot of think to create listenKey in app script but nothing work.
the binance URL: https://binance-docs.github.io/apidocs/spot/en/#user-data-streams
this is my code:
function generated_key() {
var aPIKEY = '*****'; // key.
var secretKey = '****'; // Secret key.
var api = "/api/v3/userDataStream";
var timestamp = Number(new Date().getTime()).toFixed(0);
var string = "timestamp="+timestamp;
var baseUrl = "https://api1.binance.com";
var signature = Utilities.computeHmacSha256Signature(string, secretKey);
signature = signature.map(function(e) {
var v = (e < 0 ? e + 256 : e).toString(16);
return v.length == 1 ? "0" + v : v;
}).join("");
var query = "?" + string + "&signature=" + signature;
var params = {
'method': 'POST',
'headers': {'X-MBX-APIKEY': aPIKEY},
'muteHttpExceptions': true
};
var data = UrlFetchApp.fetch(baseUrl + api + query, params);
var obj = JSON.parse(data); // To JSON
Logger.log(obj)
}
I get the result error: {code=-1101.0, msg=Too many parameters; expected '0' and received '2'.}
any suggestion to do it.
I've successfully connected to most other crypto exchanges but keep getting "success":false,"error":"Not logged in" when using FTX.
This is my code:
var host = 'https://ftx.com/api';
var endpoint ='/wallet/all_balances';
var url = host + endpoint;
var timestamp = ''+ new Date().getTime();
var payload = timestamp + 'GET' + endpoint+'';
var shaObj = new jsSHA("SHA-256", "BYTES");
shaObj.setHMACKey(secret, "BYTES");
shaObj.update(payload);
var signature = shaObj.getHMAC("HEX");
var options = {
method: 'get',
headers: {
'FTX-KEY': key,
'FTX-TS': timestamp,
'FTX-SIGN': signature
},
muteHTTPExceptions: 'true'
}
var jsondata = UrlFetchApp.fetch(url, options);
var data = JSON.parse(jsondata.getContentText());
Any help much appreciated!
Found the answer:
var host = 'https://ftx.com';
var endpoint ='/api/wallet/all_balances';
Using Google sheets, I have stored my api_key and api_secret in the Property service section of user info as respectively "api_key" and api_secret".
I want to get wallet info from my account. The code I have written is as follows:
function wallet() {
var api_key = PropertiesService.getScriptProperties().getProperty('api_key');
var api_secret = PropertiesService.getScriptProperties().getProperty('api_secret');
var response = UrlFetchApp.fetch("https://api.bitfinex.com/v2/auth/r/wallets", api_key, api_secret);
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("sheet");
var result = JSON.parse(response.getContentText());
var wallet_btc = result.BALANCE
}
When I run in debug mode the error message is:
Cannot find method fetch(string,null,null). (line 13, file "Code")
Is this approach wrong, the code wrong, or both?
Many thanks.
How about the following modifications?
Modification points :
The parameters for UrlFetchApp.fetch() are UrlFetchApp.fetch(url, params). And params is an object.
This is the reason of error Cannot find method fetch(string,null,null). (line 13, file "Code").
When I saw the sample scripts for Bitfinex API, the request body has to be created using api_key, api_secret, nonce, body and signature. And signature is encrypted by HMAC_SHA_384 and converted to the string of the unsigned hexadecimal.
The sample for the endpoint of https://api.bitfinex.com/v2/auth/r/wallets is as follows. This is from API reference.
Sample for the endpoint of https://api.bitfinex.com/v2/auth/r/wallets
request.post(
`${url}/auth/r/wallets`,
headers: { /* auth headers */ },
body: {},
json: true,
(error, response, body) => console.log(body)
)
When above points are reflected to your script, the modified script is as follows.
Modified script :
function wallet() {
var api_key = PropertiesService.getScriptProperties().getProperty('api_key');
var api_secret = PropertiesService.getScriptProperties().getProperty('api_secret');
var apiPath = "v2/auth/r/wallets";
var nonce = Date.now().toString();
var body = {};
var rawBody = JSON.stringify(body);
var signature = "/api/" + apiPath + nonce + rawBody;
signature = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_384, signature, api_secret)
.map(function(e) {
var v = (e < 0 ? e + 256 : e).toString(16);
return v.length == 1 ? "0" + v : v;
}).join("");
var url = "https://api.bitfinex.com/" + apiPath;
var options = {
method: 'POST',
contentType: "application/json",
headers: {
'bfx-nonce': nonce,
'bfx-apikey': api_key,
'bfx-signature': signature
},
payload: rawBody
};
var response = UrlFetchApp.fetch(url, options);
var result = JSON.parse(response.getContentText());
Logger.log(result)
// var wallet_btc = result.BALANCE // I couldn't confirm whether this key exists.
}
References :
Sample scripts for Bitfinex API
API reference
UrlFetchApp.fetch()
I cannot confirm whether this works. If this didn't work, can you tell me the situation? I would like to modify.
Edit :
When you want 0.0957596 from the result of [["exchange", "USD", 14.81076629, 0, null], ["exchange", "BTC", 0.0957596, 0, null], ["funding", "BTC", 4.13E-6, 0, null], ["funding", "ETH", 3.50186961, 0, null], ["exchange", "OMG", 5.9E-7, 0, null]];, you can use the following script.
Script :
function wallet() {
var api_key = PropertiesService.getScriptProperties().getProperty('api_key');
var api_secret = PropertiesService.getScriptProperties().getProperty('api_secret');
var apiPath = "v2/auth/r/wallets";
var nonce = Date.now().toString();
var body = {};
var rawBody = JSON.stringify(body);
var signature = "/api/" + apiPath + nonce + rawBody;
signature = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_384, signature, api_secret)
.map(function(e) {
var v = (e < 0 ? e + 256 : e).toString(16);
return v.length == 1 ? "0" + v : v;
}).join("");
var url = "https://api.bitfinex.com/" + apiPath;
var options = {
method: 'POST',
contentType: "application/json",
headers: {
'bfx-nonce': nonce,
'bfx-apikey': api_key,
'bfx-signature': signature
},
payload: rawBody
};
var response = UrlFetchApp.fetch(url, options);
var result = JSON.parse(response.getContentText());
// Logger.log(result)
// var wallet_btc = result.BALANCE // I couldn't confirm whether this key exists.
var balance = 0;
for (var i in result) {
if (result[i][0] == "exchange" && result[i][1] == "BTC") {
balance = result[i][2];
break;
}
}
Logger.log(balance)
}
Note :
From the document, it seems that the indexes of WALLET_TYPE, CURRENCY and BALANCE are always 0, 1 and 2 of each element in the response, respectively.
I've tried all the combinations I can think of to make this work. What do I need to send to the New Basecamp API as a POST field to have it accept my POST data?
My code is:
function getFilterBy() {
var url = "https://basecamp.com/****/api/v1/projects/*****.json";
var payload = {"name" : "myapp", "description" : "no desc mls"};
var opt = {
"contentType" : "application/json",
"method" : "POST",
"headers":{ "User-Agent": "myapp (user#somewhere.com)",
"Authorization" :"Basic " + Utilities.base64Encode("user" + ":" + "pass")},
"validateHttpsCertificates" :false,
"muteHttpExceptions" : true,
"payload" : payload
};
var response = UrlFetchApp.fetch(url, opt);
var text = response.getContentText();
Logger.log(text);
}
My Error is:
lexical error: invalid char in json text.
description=no+desc+mls&name=Ho
(right here) ------^
I have tried to Utilities.jsonStringify, but no luck. I know its a noob error, but I just can't figure it out. If there is a place you are aware of where I can get this info too that would be phenomenal.
Thanks!
UPDATE 1
function getFilterBy() {
var url = "https://basecamp.com/****/api/v1/projects/****.json";
var payload = {name : 'myApp Change'};
var opt = {
"contentType" : "application/json",
"method" : "POST",
"headers":{ "User-Agent": "myApp (user#ex.com)",
"Authorization" :"Basic " + Utilities.base64Encode("user" + ":" + "pass")},
"validateHttpsCertificates" :false,
"muteHttpExceptions" : true,
"payload" : Utilities.jsonStringify(payload)
};
var response = UrlFetchApp.fetch(url, opt);
var text = response.getContentText();
Logger.log(text);
}
Yields Err:
<body>
<div class="dialog">
<div class="innercol">
<h1>Hmm, that isn’t right</h1>
<h2>You may have typed the URL incorrectly.</h2>
<p>Check to make sure you’ve got the spelling, capitalization, etc. exactly right.</p>
</div>
</div>
<p id="back" class="back">
← Back to previous page
</p>
<script type="text/javascript">
if (window.history.length <= 1) document.getElementById("back").style.display = "none";
</script>
</body>
Are you sure you tried with JSON.stringify correctly? This example here correctly creates a project for me in Basecamp with the specifified project name/description in the POST payload.
Note, I wrote this quickly to not include the UserAgent - you'll want to put that back in.
function createProject() {
var user = 'USERNAME';
var password = 'PASSWORD'
var accoundId = 'ACCOUNTID#';
var url = 'https://basecamp.com/'+accoundId+'/api/v1/projects.json';
var payload = {name : 'new project', description : 'my project description'};
var opt = {
contentType : 'application/json',
method : 'post',
headers:{Authorization :"Basic " + Utilities.base64Encode(user + ':' + password)},
validateHttpsCertificates :false,
muteHttpExceptions : true,
payload : JSON.stringify(payload)
};
var response = UrlFetchApp.fetch(url, opt);
var text = response.getContentText();
Logger.log(text);
}
In order to update a project, you have to use the put verb instead of post as documented here
Here is a working sample -
function updateProject() {
var projectId = '2413370';
var url = 'https://basecamp.com/'+accoundId+'/api/v1/projects/'+projectId+'.json';
var payload = {name : 'new project', description : 'my new new project description'};
var opt = {
contentType : 'application/json',
method : 'put',
headers:{Authorization :"Basic " + Utilities.base64Encode(user + ':' + password)},
validateHttpsCertificates :false,
muteHttpExceptions : true,
payload : JSON.stringify(payload)
};
var response = UrlFetchApp.fetch(url, opt);
var text = response.getContentText();
Logger.log(text);
}
I'm attempting to upload a file from PhoneGap to a server using the FileTransfer method. I need HTTP basic auth to be enabled for this upload.
Here's the relevant code:
var options = new FileUploadOptions({
fileKey: "file",
params: {
id: my_id,
headers: { 'Authorization': _make_authstr() }
}
});
var ft = new FileTransfer();
ft.upload(image, 'http://locahost:8000/api/upload', success, error, options);
Looking over the PhoneGap source code it appears that I can specify the authorization header by including "headers" in the "params" list as I've done above:
JSONObject headers = params.getJSONObject("headers");
for (Iterator iter = headers.keys(); iter.hasNext();)
{
String headerKey = iter.next().toString();
conn.setRequestProperty(headerKey, headers.getString(headerKey));
}
However, this doesn't seem to actually add the header.
So: is there a way to do HTTP basic auth with PhoneGap's FileTransfer, for both iPhone and Android?
You can add custom headers by adding them to the options rather than the params like so:
authHeaderValue = function(username, password) {
var tok = username + ':' + password;
var hash = btoa(tok);
return "Basic " + hash;
};
options.headers = {'Authorization': authHeaderValue('Bob', '1234') };
The correct location for the headers array is as an immediate child of options. options->headers. Not options->params->headers. Here is an example:
//**************************************************************
//Variables used below:
//1 - image_name: contains the actual name of the image file.
//2 - token: contains authorization token. In my case, JWT.
//3 - UPLOAD_URL: URL to which the file will be uploaded.
//4 - image_full_path - Full path for the picture to be uploaded.
//***************************************************************
var options = {
fileKey: "file",
fileName: 'picture',
chunkedMode: false,
mimeType: "multipart/form-data",
params : {'fileName': image_name}
};
var headers = {'Authorization':token};
//Here is the magic!
options.headers = headers;
//NOTE: I creaed a separate object for headers to better exemplify what
// is going on here. Obviously you can simply add the header entry
// directly to options object above.
$cordovaFileTransfer.upload(UPLOAD_URL, image_full_path, options).then(
function(result) {
//do whatever with the result here.
});
Here is the official documentation: https://github.com/apache/cordova-plugin-file-transfer
You can create a authorization header yourself. But you can also enter the credentials in the url like this:
var username = "test", password = "pass";
var uri = encodeURI("http://"+username + ':' + password +"#localhost:8000/api/upload");
See FileTransfer.js for the implementation (line 45):
function getBasicAuthHeader(urlString) {
var header = null;
// This is changed due to MS Windows doesn't support credentials in http uris
// so we detect them by regexp and strip off from result url
// Proof: http://social.msdn.microsoft.com/Forums/windowsapps/en-US/a327cf3c-f033-4a54-8b7f-03c56ba3203f/windows-foundation-uri-security-problem
if (window.btoa) {
var credentials = getUrlCredentials(urlString);
if (credentials) {
var authHeader = "Authorization";
var authHeaderValue = "Basic " + window.btoa(credentials);
header = {
name : authHeader,
value : authHeaderValue
};
}
}
return header;
}