Kraken API authentication sample converted from python to Google apps script is not returning the same output - authentication

I am trying to convert python kraken API auth to Google Script to use it in a Google Spreadsheet, but with no luck.
# python sample
def get_kraken_signature(urlpath, data, secret):
postdata = urllib.parse.urlencode(data)
encoded = (str(data['nonce']) + postdata).encode()
message = urlpath.encode() + hashlib.sha256(encoded).digest()
mac = hmac.new(base64.b64decode(secret), message, hashlib.sha512)
sigdigest = base64.b64encode(mac.digest())
return sigdigest.decode()
api_sec = "kQH5HW/8p1uGOVjbgWA7FunAmGO8lsSUXNsu3eow76sz84Q18fWxnyRzBHCd3pd5nE9qa99HAZtuZuj6F1huXg=="
data = {
"nonce": "1616492376594",
"ordertype": "limit",
"pair": "XBTUSD",
"price": 37500,
"type": "buy",
"volume": 1.25
}
signature = get_kraken_signature("/0/private/AddOrder", data, api_sec)
print("API-Sign: {}".format(signature))
# prints API-Sign: 4/dpxb3iT4tp/ZCVEwSnEsLxx0bqyhLpdfOpc6fn7OR8+UClSV5n9E6aSS8MPtnRfp32bAb0nmbRn6H8ndwLUQ==
I ended up with this, but it's not returning the same output.
# google script sample from my sheet
function get_kraken_sinature(url, data, nonce, secret) {
var message = url + Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, Utilities.base64Encode(nonce + data));
var base64Secret = Utilities.base64Decode(secret);
var mac = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_512, message, secret);
return Utilities.base64Encode(mac);
}
signature = get_kraken_signature("/0/private/AddOrder", data, api_sec)
print("API-Sign: {}".format(signature))
# prints API-Sign: Jn6Zk8v41uvMWOY/RTBTrb7zhGxyAOTclFFe7lySodBnEnXErfJgIcQb90opFwccuKDd0Nt1l71HT3V9+P8pUQ==
Both code samples should do the same, and are supposed to output an identical API-Sign key. They are not at this stage, and I am wondering why is that.

I believe your goal is as follows.
You want to convert your python script to Google Apps Script.
In your Google Apps Script, you have already confirmed that the script for requesting works fine. You want to convert get_kraken_signature of your python script to Google Apps Script.
In this case, how about the following modified script?
Modified script:
function get_kraken_sinature(url, data, nonce, secret) {
var str = Object.entries(data).map(([k, v]) => `${k}=${v}`).join("&");
var message = Utilities.newBlob(url).getBytes().concat(Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, nonce + str));
var mac = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_512, message, Utilities.base64Decode(secret));
return Utilities.base64Encode(mac);
}
// Please run this function.
function main() {
const data = {
"nonce": "1616492376594",
"ordertype": "limit",
"pair": "XBTUSD",
"price": 37500,
"type": "buy",
"volume": 1.25
};
var url = "/0/private/AddOrder";
var nonce = "1616492376594";
var secret = "kQH5HW/8p1uGOVjbgWA7FunAmGO8lsSUXNsu3eow76sz84Q18fWxnyRzBHCd3pd5nE9qa99HAZtuZuj6F1huXg==";
var res = get_kraken_sinature(url, data, nonce, secret);
console.log(res)
}
References:
computeDigest(algorithm, value)
computeHmacSignature(algorithm, value, key)

Related

API call from google sheets is too long

I am trying to write a script in google sheets to update my 3commas bots. The API requires a number of mandatory fields are passed even when there's only 1 item that needs to be updated.
The code I have is below and it uses the values already read from the platform updating only the base_order_volume value. This works perfectly except for when the pairs value is long (more the 2k chars) and then I get an error from the UrlFetchApp call because the URL is too long.
var sheet = SpreadsheetApp.getActiveSheet();
var key = sheet.getRange('F4').getValue();
var secret = sheet.getRange('F5').getValue();
var baseUrl = "https://3commas.io";
var editBots = "/ver1/bots/"+bots[botCounter].id+"/update";
var patchEndPoint = "/public/api"+editBots+"?";
.
.
[loop around values in sheet]
.
.
var BaseOrder=Number(sheet.getRange(rowCounter,12).getValue().toFixed(2));
var botParams = {
"name": bots[botCounter].name,
"pairs": bots[botCounter].pairs,
"max_active_deals": bots[botCounter].max_active_deals,
"base_order_volume": BaseOrder,
"take_profit": Number(bots[botCounter].take_profit),
"safety_order_volume": bots[botCounter].safety_order_volume,
"martingale_volume_coefficient": bots[botCounter].martingale_volume_coefficient,
"martingale_step_coefficient": Number(bots[botCounter].martingale_step_coefficient),
"max_safety_orders": bots[botCounter].max_safety_orders,
"active_safety_orders_count": Number(bots[botCounter].active_safety_orders_count),
"safety_order_step_percentage": Number(bots[botCounter].safety_order_step_percentage),
"take_profit_type": bots[botCounter].take_profit_type,
"strategy_list": bots[botCounter].strategy_list,
"bot_id": bots[botCounter].id
};
var keys = Object.keys(botParams);
var totalParams = keys.reduce(function(q, e, i) {
q += e + "=" + encodeURIComponent(JSON.stringify(botParams[e])) + (i != keys.length - 1 ? "&" : "");
return q;
},endPoint);
var signature = Utilities.computeHmacSha256Signature(totalParams, secret);
signature = signature.map(function(e) {return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2)}).join("");
var headers = {
'APIKEY': key,
'Signature': signature,
};
try {
var params = {
'method': 'PATCH',
'headers': headers,
'muteHttpExceptions': true
};
var response = JSON.parse(UrlFetchApp.fetch(baseUrl + totalParams, params).getContentText());
I have tried to set the botParams as a payload in the params but when I do the signature is incorrect.
I anyone knows how to use sheets to make a call using extensive length of parameters I'd appreciate any help at all
Some sample data for the bots array would be
{
"name": "TestBot",
"base_order_volume": 0.001,
"take_profit": 1.5,
"safety_order_volume": 0.001,
"martingale_volume_coefficient": 2,
"martingale_step_coefficient": 1,
"max_safety_orders": 1,
"active_safety_orders_count": 1,
"safety_order_step_percentage": 2.5,
"take_profit_type": "total",
"stop_loss_percentage": 0,
"cooldown": 0,
"pairs": ["BTC_ADA","BTC_TRX"],
"trailing_enabled":"true",
"trailing_deviation":0.5,
"strategy_list": [{"strategy":"cqs_telegram"}]
}
Thanks in advance
I'd consider using a Cloud Function to either do the heavy lifting, or, if you're worried about costs, use it as a proxy. You can then call the cloud function from Google Sheets. Cloud Functions can be written in whatever language you're most comfortable with, including Node.
Check the GCP pricing calculator to see what the cost would be. For many cases it would be completely free.
This should give you a sense of how to use cloud functions for CSV creation:
https://codelabs.developers.google.com/codelabs/cloud-function2sheet#0
Here is a SO question with an answer that explains how to query cloud functions with authentication.

How to get a Minecraft session ID?

I'm trying to make a Minecraft client and I cant figure out how to get a session ID to start the game. I've done some googling and cant find anyway to get it bar from this answer to Launch Minecraft from command line - username and password as prefix that doesn't work.
Minecraft mc = Minecraft.getMinecraft();
mc.getSession().getToken();
You can manually crash your game by holding down F3 + C. In the crash log will be your session id.
I made a little script that returns the session id.
def GetSessionID(Username, Password):
# Url = f'https://login.minecraft.net?user={Username}&password={Password}&version=13'
Url = "https://authserver.mojang.com/authenticate"
# LoginInfo = requests.post(Url)
# LoginInfoList = LoginInfo.split(':')
# SessionID = LoginInfoList[3]
token = str(uuid.uuid4())
requestData = GetAuthenticationBody(Username, Password, token)
response = requests.post(url=Url, json=requestData)
responseData = response.json()
SessionID = responseData['accessToken']
return SessionID
def GetAuthenticationBody(username, password, token):
body = {
"agent": {
"name": "Minecraft",
"version": 1
},
"username": username,
"password": password,
"clientToken": token,
"requestUser": True
}
return body

Consume tensor-flow serving inception model using C# client (PREDICT API)

I have been trying to implement a C# client application to interact with Tensorflow serving server for few weeks now with no success. I have a Python client which works successfully but I can not replicate its functionality with C#. The Python client
import requests
#import json
from keras.preprocessing.image import img_to_array, array_to_img, load_img
from keras.preprocessing import image
flowers = 'c:/flower_photos/cars/car1.jpg'
image1 = img_to_array(image.load_img(flowers, target_size=(128,128))) / 255
payload = {
"instances": [{"image":image1.tolist()},
]
}
print("sending request...")
r = requests.post('http://localhost:8501/v1/models/flowers/versions/1:predict', json=payload)
print(r.content)
The server responds correctly. I am using Tensorflow version 1.12.0 with corresponding latest serving image. They are all working fine.
According to REST API documentation, the API structure is given but its not clear to me at all. I need to send the image to server. How could I add the image payload to JSON request in C# ? After going through many sites, I found that image should be in base64string.
So I did the image conversion into base64
private string GetBase64ImageBytes(string ImagePath)
{
using (Image image = Image.FromFile(ImagePath))
{
using (MemoryStream m = new MemoryStream())
{
image.Save(m, image.RawFormat);
byte[] imageBytes = m.ToArray();
// Convert byte[] to Base64 String
string base64String = Convert.ToBase64String(imageBytes);
return base64String;
}
}
}
The request portion is as follows : (server responds with metadata correctly for the GET request)
public string PostImageToServerAndClassify(string imageArray)
{
//https://stackoverflow.com/questions/9145667/how-to-post-json-to-a-server-using-c
string result = null;
string ModelName = cmbProjectNames.Text.Replace(" ", "");
string status_url = String.Format("http://localhost:{0}/v1/models/{1}/versions/{2}:predict", txtPort.Text, ModelName, txtVersion.Text);
var httpWebRequest = (HttpWebRequest)WebRequest.Create(status_url);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
try
{
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
// string json = "{"+ #"""instances""" + ": [{" + #"""image""" + #":" + imageArray + "}]}";
// imageArray = #""" + imageArray + #""";
string json = "{ " + #"""instances""" + ": [{" + #"""image""" + #": { " + #"""b64"": """ + imageArray + #"""}}]}";
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
result = streamReader.ReadToEnd();
}
}
catch (Exception ex)
{
result = ex.Message;
}
return result;
}
With the POST request, I get the error message "The remote server returned an error: (400) Bad Request.". Also server terminates its service. In Postman I get
the detailed error info as :
{ "error": "Failed to process element: 0 key: image of \'instances\' list. Error: Invalid argument: JSON Value: {\n \"b64\": \"/9j/4AAQSkZJRgABAQEAAAAAAAD/4QBSRXhpZgAATU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAAZKGAAcAAAAcAAAALAAAAABVTklDT0RFAABBAHAAcABsAGUATQBhAHIAaw ... .....(image string data)
So this feels like that I am sending the incorrect data format.
Could someone please tell me what is wrong here ? Any example of image conversion and POST request is highly appreciated. I can not find anywhere that base64string format is the right format for the image in TF site. Python client data format is different hence really need to know what is the right format with any reference documents.
The nearest reference I found here with JAVA client but did not work with mine may be due to TF version difference.

Crunchbase Data API v3.1 to Google Sheets

I'm trying to pull data from the Crunchbase Open Data Map to a Google Spreadsheet. I'm following Ben Collins's script but it no longer works since the upgrade from v3 to v3.1. Anyone had any luck modifying the script for success?
var USER_KEY = 'insert your API key in here';
// function to retrive organizations data
function getCrunchbaseOrgs() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getSheetByName('Organizations');
var query = sheet.getRange(3,2).getValue();
// URL and params for the Crunchbase API
var url = 'https://api.crunchbase.com/v/3/odm-organizations?query=' + encodeURI(query) + '&user_key=' + USER_KEY;
var json = getCrunchbaseData(url,query);
if (json[0] === "Error:") {
// deal with error with fetch operation
sheet.getRange(5,1,sheet.getLastRow(),2).clearContent();
sheet.getRange(6,1,1,2).setValues([json]);
}
else {
if (json[0] !== 200) {
// deal with error from api
sheet.getRange(5,1,sheet.getLastRow(),2).clearContent();
sheet.getRange(6,1,1,2).setValues([["Error, server returned code:",json[0]]]);
}
else {
// correct data comes back, filter down to match the name of the entity
var data = json[1].data.items.filter(function(item) {
return item.properties.name == query;
})[0].properties;
// parse into array for Google Sheet
var outputData = [
["Name",data.name],
["Homepage",data.homepage_url],
["Type",data.primary_role],
["Short description",data.short_description],
["Country",data.country_code],
["Region",data.region_name],
["City name",data.city_name],
["Blog url",data.blog_url],
["Facebook",data.facebook_url],
["Linkedin",data.linkedin_url],
["Twitter",data.twitter_url],
["Crunchbase URL","https://www.crunchbase.com/" + data.web_path]
];
// clear any old data
sheet.getRange(5,1,sheet.getLastRow(),2).clearContent();
// insert new data
sheet.getRange(6,1,12,2).setValues(outputData);
// add image with formula and format that row
sheet.getRange(5,2).setFormula('=image("' + data.profile_image_url + '",4,50,50)').setHorizontalAlignment("center");
sheet.setRowHeight(5,60);
}
}
}
This code no longer pulls data as expected.
I couldn't confirm about the error messages when you ran the script. So I would like to show about the clear difference point. It seems that the endpoint was changed from https://api.crunchbase.com/v/3/ to https://api.crunchbase.com/v3.1/. So how about this modification?
From :
var url = 'https://api.crunchbase.com/v/3/odm-organizations?query=' + encodeURI(query) + '&user_key=' + USER_KEY;
To :
var url = 'https://api.crunchbase.com/v3.1/odm-organizations?query=' + encodeURI(query) + '&user_key=' + USER_KEY;
Note :
From your script, I couldn't also find query. So if the script doesn't work even when you modified the endpoint, please confirm about it. You can see the detail of API v3 Compared to API v3.1 is here.
References :
API v3 Compared to API v3.1
Using the API
If this was not useful for you, I'm sorry.

Issue with BTC-e API in App Script, method parameter

I am trying to incorporate the BTC-e.com API in to a google docs spreadsheet.
The API documentation is here: https://btc-e.com/api/documentation
The method name is sent via POST parameter method.
As the URLFetchApp requires me to set the type of request as POST by a parameter method and I then have another parameter called method to be set as getInfo.
How can I go about setting the fetch method as POST and have the API parameter method as getInfo.
Below is the function this relates too. Also I am sure there a more issues in my work I am yet to find.
function inventory() {
var nonce=Number(SpreadsheetApp.getActiveSheet().getRange('K2').getValue());
var token=SpreadsheetApp.getActiveSheet().getRange('K1').getValue();
var tokenEndpoint = "https://btc-e.com/tapi";
var sign= 'TEMP'
var head = {
'Content-Type': 'application/x-www-form-urlencoded',
'Key': token,
'Sign': sign
}
var params = {
method : "POST",
method : "getInfo",
headers: head,
contentType: 'application/x-www-form-urlencoded',
method : "getInfo",
nonce: nonce
}
var request = UrlFetchApp.getRequest(tokenEndpoint, params);
var response = UrlFetchApp.fetch(tokenEndpoint, params);
var response2=String(response);
SpreadsheetApp.getActiveSheet().getRange('K2').setValue(nonce+1);
SpreadsheetApp.getActiveSheet().getRange('I16').setValue(response2);
SpreadsheetApp.getActiveSheet().getRange('I17').setValue(nonce);
}
This just yields the error
Attribute provided with invalid value: method
Thanks,
Steve
PS: First time posting, I tried to get the format correct.
I made the following Google JavaScript function to do POST access to BTC-e. You can find this function in action in the example spreadsheet I made to demonstrate the BTC-e API functions.
function btceHttpPost(keyPair, method, params, nonce) {
if (keyPair === undefined) {
return "{'error':'missing key pair'}"
}
if (params === undefined) {
params = '';
}
// Cleanup keypair, remove all \s (any whitespace)
var keyPair = keyPair.replace(/[\s]/g, '');
// Keypair example: "AFE730YV-S9A4FXBJ-NQ12HXS9-CA3S3MPM-CKQLU0PG,96a00f086824ddfddd9085a5c32b8a7b225657ae2fe9c4483b4c109fab6bf1a7"
keyPair = keyPair.split(',');
var pubKey = keyPair[0];
var privKey = keyPair[1];
// As specified on the BTC-e api (https://btc-e.com/api/documentation) the
// nonce POST parameter must be an incrementing integer (>0). The easiest
// implementation is the use of a timestamp (TS), so there is no need
// for persistant storage. Preferable, the resolution of the TS should be
// small enough the handle the desired call-frequency (a sleep of the TS
// resolution can fix this but I don't like such a waste). Another
// consideration is the sizeof the nonce supported by BTC-e. Experiments
// revealed this is a 32 bit unsigned number. The native JavaScript TS,
// stored in a float, can be 53 bits and has a resolution of 1 ms.
if (nonce === undefined)
// This time stamp counts amount of 200ms ticks starting from Jan 1st, 2014 UTC
// On 22 Mar 2041 01:17:39 UTC, it will overflow the 32 bits and will fail
// the nonce key for BTC-e
var nonce = Math.floor((Date.now() - Date.UTC(2014,0)) / 200);
// Construct payload message
var msg = 'nonce=' + nonce + '&method=' + method + params;
var msgSign = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_512, msg, privKey);
// Convert encoded message from byte[] to hex string
for (var msgSignHex = [], i = 0; i < msgSign.length; i++) {
// Doing it nibble by nibble makes sure we keep leading zero's
msgSignHex.push(((msgSign[i] >>> 4) & 0xF).toString(16));
msgSignHex.push((msgSign[i] & 0xF).toString(16));
}
msgSignHex = msgSignHex.join('');
var httpHeaders = {'Key': pubKey, 'Sign': msgSignHex};
var fetchOptions = {'method': 'post', 'headers': httpHeaders, 'payload': msg};
var reponse = UrlFetchApp.fetch('https://btc-e.com/tapi', fetchOptions);
return reponse.getContentText();
};
The problem looks to be with your params object . You have method set thrice in the same object, which is a source of confusion.
Next, take a look at the documentation for UrlFetchApp.fetch() ( https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app#fetch(String,Object) ) . The method can take a value of post, get, delete, put.
The getInfo should probably be appended to your URL to make it
var tokenEndpoint = "https://btc-e.com/tapi/getInfo"
Per the docs, you also have to put in more parameters to the request, nonce, api key etc. Use this as a starting point, revisit the documentation and get back to SO if you still have trouble