How to create a JWT? - javascript

I am working on a script to dynamically create a JWT for a google api call when a customer record is edited/created in NetSuite. I have been able to successfully call the api from a script with a manually created JWT. This script will create a new JWT for every call, this is needed because a JWT is only active for 1 hour after creation, the issue I am running into is correctly encoding an object. The documentation I found on SuiteAnswers only referenced encoding strings, and I am not totally sure how the encoding process works when done manually. (if the entire object is stringified or if it is broken up)
This is the piece of code with the object (payload) needing to be encoded correctly to finish creating the JWT.
var secondsSinceEpoch = Math.round(Date.now() / 1000)
var plusOneHour = secondsSinceEpoch + 3600
var payload = {
"target_audience": "https://sample.com",
"iss": "sample.com",
"sub": "sample.com",
"exp": plusOneHour,
"iat": secondsSinceEpoch,
"aud": "https://www.googleapis.com/oauth2/v4/token"
}
log.debug({
title:'payload',
details: JSON.stringify(payload)});
var base64EncodedString = encode.convert({
string: JSON.stringify(payload),
inputEncoding: encode.Encoding.UTF_8,
outputEncoding: encode.Encoding.BASE_64_URL_SAFE});
return connectToGCP(base64EncodedString)```

If you don't have to use public/private keys for signing your solution would look something like:
/**
*#NApiVersion 2.x
*/
define(['N/encode', 'N/crypto'], function(encode, crypto){
function signIt(payload, ttl){
if(typeof payload.exp == 'undefined'){
var secondsSinceEpoch = Math.round(Date.now() / 1000);
var expAt = secondsSinceEpoch + (ttl || 60);
payload["exp"] = expAt;
payload["iat"] = secondsSinceEpoch;
}
log.debug({
title:'payload',
details: JSON.stringify(payload)});
function toB64(str){
return encode.convert({
string: str,
inputEncoding: encode.Encoding.UTF_8,
outputEncoding: encode.Encoding.BASE_64_URL_SAFE}).replace(/=+$/, '');
}
var header = toB64(JSON.stringify({
type:'JWT',
alg:'HS256'
}));
var body = toB64( JSON.stringify(payload));
var mySecret = 'custsecret_jwt_sample_secret'; //secret id take from secrets management page
var sKey = crypto.createSecretKey({
secret: mySecret,
encoding: encode.Encoding.UTF_8
});
var signer = crypto.createHmac({
algorithm: crypto.HashAlg.SHA256,
key:sKey
});
signer.update({
input:header +'.'+ body,
inputEncoding: encode.Encoding.UTF_8
});
var sig = signer.digest({
outputEncoding:encode.Encoding.BASE_64_URL_SAFE
}).replace(/=+$/, '');
return [header, body, sig].join('.');
}
return {
signIt: signIt
}
});

Related

Kraken API private request authentication {"error":["EAPI:Invalid key"]} - Google Script

I have been trying to communicate with the private API on kraken. The error I get suggests {"error":["EAPI:Invalid key"]} that the encryption/decryption steps are correct. I have tried creating new keys, does not help. I'm wondering if the 'format' of the signature variable is wrong, even though correct in nature.
function balance () {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("API_read_only");
var key = sheet.getRange("B5").getValue()
var secret = sheet.getRange("B6").getValue()
// (API method, nonce, and POST data)
var path = "/0/private/TradeBalance"
var nonce = new Date () * 1000
var postdata = "nonce=" + nonce
//Algorithms
//Calculate the SHA256 of the nonce and the POST data
// using goolge script lib
// using more succint function from https://stackoverflow.com/questions/16216868/get-back-a-string-representation-from-computedigestalgorithm-value-byte
function SHA_256 (str) {
return Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256, str).reduce(function(str,chr){
chr = (chr < 0 ? chr + 256 : chr).toString(16);
return str + (chr.length==1?'0':'') + chr;
},'');
}
var api_sha256 = SHA_256(nonce + postdata)
//Decode the API secret (the private part of the API key) from base64 // need to stringyfy
var base64 = Utilities.base64Decode(secret)
var base64s = Utilities.newBlob(base64).getDataAsString()
//Calculate the HMAC of the URI path and the SHA256, using SHA512 as the HMAC hash and the decoded API secret as the HMAC key
var hamc512_uri = Utilities.computeHmacSha256Signature(path + api_sha256,base64s)
var hamc512_uris = Utilities.newBlob(hamc512_uri).getDataAsString()
//Encode the HMAC into base64
var signature = Utilities.base64Encode(hamc512_uris)
Logger.log(signature)
//An example of the algorithm using the variables shown above is as follows:
//Base64Encode(HMAC-SHA512 of ("/0/private/TradeBalance" + SHA256("1540973848000nonce=1540973848000&asset=xxbt")) using Base64Decode("FRs+gtq09rR7OFtKj9BGhyOGS3u5vtY/EdiIBO9kD8NFtRX7w7LeJDSrX6cq1D8zmQmGkWFjksuhBvKOAWJohQ==") as the HMAC key
//The result is the API-Sign value / signature.
// connect
var url = "https://api.kraken.com" + path;
var options = {
method: 'post',
headers: {
'API-Key': key,
'API-Sign': signature
},
payload: postdata
};
var response = UrlFetchApp.fetch (url, options);
json = response.getContentText ();
Logger.log(json)
}
While I cannot spot what's wrong with your code I faced the same problem as well (thinking I have everything correct but getting a EAPI:Invalid key) with different libraries.
The approach that helped me was:
Take some posted working solution, e.g. https://stackoverflow.com/a/43081507/672008 (in Java)
Check that it really works
Fix the nonce parameter to get a stable HMAC end results
Massage my code until I get then same intermediate & end results
In the end I was successful using this library: https://www.npmjs.com/package/jssha
The code:
import jssha from 'jssha';
const secret = '...';
const nonce = 1642383717038;
const message = '';
const path = '/0/private/Balance';
const data = 'nonce=' + nonce;
const dataHash = new jssha('SHA-256', 'TEXT');
dataHash.update(nonce + data + message);
let utf8Encode = new TextEncoder();
const hmacHash = new jssha('SHA-512', 'UINT8ARRAY', { hmacKey: { value: secret, format: 'B64' } });
hmacHash.update(utf8Encode.encode(path));
hmacHash.update(dataHash.getHash('UINT8ARRAY'));
console.log('hmac', hmacHash.getHash('B64'));

How to sign a JWT with a private key (pem) in CryptoJS?

I am trying to create a signed JWT in postman with the following code
function base64url(source) {
// Encode in classical base64
encodedSource = CryptoJS.enc.Base64.stringify(source);
// Remove padding equal characters
encodedSource = encodedSource.replace(/=+$/, '');
// Replace characters according to base64url specifications
encodedSource = encodedSource.replace(/\+/g, '-');
encodedSource = encodedSource.replace(/\//g, '_');
return encodedSource;
}
function addIAT(request) {
var iat = Math.floor(Date.now() / 1000) + 257;
data.iat = iat;
return data;
}
var header = {
"typ": "JWT",
"alg": "HS256"
};
var data = {
"fname": "name",
"lname": "name",
"email": "email#domain.com",
"password": "abc123$"
};
data = addIAT(data);
var secret = 'myjwtsecret';
// encode header
var stringifiedHeader = CryptoJS.enc.Utf8.parse(JSON.stringify(header));
var encodedHeader = base64url(stringifiedHeader);
// encode data
var stringifiedData = CryptoJS.enc.Utf8.parse(JSON.stringify(data));
var encodedData = base64url(stringifiedData);
// build token
var token = encodedHeader + "." + encodedData;
// sign token
var signature = CryptoJS.HmacSHA256(token, secret);
signature = base64url(signature);
var signedToken = token + "." + signature;
postman.setEnvironmentVariable("payload", signedToken);
Code taken from https://gist.github.com/corbanb/db03150abbe899285d6a86cc480f674d .
I've been trying to input the PEM as the secret but does not work. Also can't find any HmacSHA256 overload that takes a PEM.
How can that be done?
The mention of postman changed this. I have a solution for you, but it's not exactly a clean way by any mean.
You'll need to create a request that you will need to execute whenever you open postman. Go as follows:
The purpose of this request is to side-load jsrsasign-js and storing it in a global Postman variable.
Once this is done, you can then use this content elsewhere. For every request you need a RSA256 JWT signature, the following pre-request script will update a variable (here, token) with the token:
var navigator = {};
var window = {};
eval(pm.globals.get("jsrsasign-js"));
function addIAT(request) {
var iat = Math.floor(Date.now() / 1000) + 257;
data.iat = iat;
return data;
}
var header = {"alg" : "RS256","typ" : "JWT"};
var data = {
"fname": "name",
"lname": "name",
"email": "email#domain.com",
"password": "abc123$"
};
data = addIAT(data);
var privateKey = "-----BEGIN RSA PRIVATE KEY----- \
MIIBOQIBAAJAcrqH0L91/j8sglOeroGyuKr1ABvTkZj0ATLBcvsA91/C7fipAsOn\
RqRPZr4Ja+MCx0Qvdc6JKXa5tSb51bNwxwIDAQABAkBPzI5LE+DuRuKeg6sLlgrJ\
h5+Bw9kUnF6btsH3R78UUANOk0gGlu9yUkYKUkT0SC9c6HDEKpSqILAUsXdx6SOB\
AiEA1FbR++FJ56CEw1BiP7l1drM9Mr1UVvUp8W71IsoZb1MCIQCKUafDLg+vPj1s\
HiEdrPZ3pvzvteXLSuniH15AKHEuPQIhAIsgB519UysMpXBDbtxJ64jGj8Z6/pOr\
NrwV80/EEz45AiBlgTLZ2w2LjuNIWnv26R0eBZ+M0jHGlD06wcZK0uLsCQIgT1kC\
uNcDTERjwEbFKJpXC8zTLSPcaEOlbiriIKMnpNw=\
-----END RSA PRIVATE KEY-----";
var sHeader = JSON.stringify(header);
var sPayload = JSON.stringify(data);
var sJWT = KJUR.jws.JWS.sign(header.alg, sHeader, sPayload, privateKey);
pm.variables.set('token', sJWT);
In order:
I define mock window and navigator objects as jsrsasign-js needs them.
I then eval() the content of what we fetched earlier in order to rehydrate everything
The rest of your code is simple usage of jsrsasign-js. Your token info is there, and I've defined a private key there. You can change this or use an environment variable; it's just there for demo purposes. I then simply use the rehydrated library to sign it, and set the variable to the value of the signed JWT.
A PEM, as you refer to it, is a container format specifying a combination of public and/or private key. You're using it to sign using HMAC-SHA256, which operates on a shared secret. This obviously isn't going to work (unless you take the poor man's approach and use your public key as the shared secret).
Fortunately enough, there are other signature methods defined in the RFCs. For instance, there is a way to sign using RSA, and a very convenient way of defining a public key as a JSON web key (JWK). We're going to be leveraging both.
I've generated a key pair for testing, they're named out and out.pub. Generation tool is genrsa (and as such, they're an RSA keypair).
In order to sign, we're going to have to change a few things:
We're changing algorithms from HS256 to RS256, as explained above
We're going to need a new library to do the signing itself, as crypto-js does not support asymmetric key crypto. We'll fall back to the native crypto module, though there are pure-JS alternatives
The code:
var CryptoJS = require("crypto-js");
var keyFileContent = require("fs").readFileSync("./out");
var pubkey = require("fs").readFileSync("./out.pub");
var base64url = require("base64url");
var nJwt = require("njwt");
function addIAT(request) {
var iat = Math.floor(Date.now() / 1000) + 257;
data.iat = iat;
return data;
}
var header = {
"typ": "JWT",
"alg": "RS256"
};
var data = {
"fname": "name",
"lname": "name",
"email": "email#domain.com",
"password": "abc123$"
};
data = addIAT(data);
// encode header
var stringifiedHeader = JSON.stringify(header);
var encodedHeader = base64url(stringifiedHeader);
// encode data
var stringifiedData = JSON.stringify(data);
var encodedData = base64url(stringifiedData);
// build token
var token = encodedHeader + "." + encodedData;
// sign token
var signatureAlg = require("crypto").createSign("sha256");
signatureAlg.update(token);
var signature = signatureAlg.sign(keyFileContent);
signature = base64url(signature);
var signedToken = token + "." + signature;
console.log(signedToken);
// Verify
var verifier = new nJwt.Verifier();
verifier.setSigningAlgorithm('RS256');
verifier.setSigningKey(pubkey);
verifier.verify(signedToken, function() {
console.log(arguments);
});
And that's it! It's quite literally that simple, although I would not recommend rewriting the sign() function from crypto from scratch. Leave it to a library that has had thorough inspection by the community, and crypto is pretty serious business.

NodeJS equivalent of C# code for hmac-sha256 authorization

Im trying to convert the C# code found here:
AMX Authorization Header in order to connect to an external API. The C# code works when trying to connect to the external API but when I convert it to a nodeJS solution it doesnt work.
I dont have access to the external C# API so can't update that side but was hoping someone could look at this and see something Im missing or doing wrong:
My nodejs solution:
var request = require('request');
var uuid = require('node-uuid');
var CryptoJS = require('crypto-js');
var URL = "https://urltoexternalAPI.com";
var itemAPPId = "testAPPId";
var APIKey = "testAPIKey";
var requestUri = encodeURIComponent(URL.toLowerCase());
var requestHttpMethod = "GET";
var requestTimeStamp = Math.floor(new Date().getTime() / 1000).toString();
var nonce = uuid.v1().replace(/-/g, '');
//I excluded the content hashing part as the API Im hitting is a GET request with no body content
var signatureRawData = itemAPPId + requestHttpMethod + requestUri + requestTimeStamp + nonce;
var secretKeyByteArray = CryptoJS.enc.Base64.parse(APIKey);
var signature = CryptoJS.enc.Utf8.parse(signatureRawData);
var signatureBytes = CryptoJS.HmacSHA256(signature, secretKeyByteArray);
var requestSignatureBase64String = signatureBytes.toString(CryptoJS.enc.Base64);
request({
url: URL,
headers: {
'Authorization': "amx "+itemAPPId+":"+requestSignatureBase64String+":"+nonce+":"+requestTimeStamp
}
}, function (error, response, body) {
if (response.statusCode != 200) {
console.log("Fail");
} else {
console.log("Success");
}
});
I figured it out! If anyone ever comes across this issue they may find the below helpful:
the following C# code works a little different to nodeJS:
System.Web.HttpUtility.UrlEncode(request.RequestUri.AbsoluteUri.ToLower());
Initially I copied this functionality as is and wrote the nodejs equivalent as such:
var requestUri = encodeURIComponent(URL.toLowerCase());
The encoding of the URL in C# keeps everything in lowercase - for e.g: https:// becomes https%3a%2f%2f - whereas nodeJS uppercases its encoding characters - https%3A%2F%2F - this is what as causing the incorrect hashing.
The solution is to just move the lowercase function to after the encoding has been done on the URL. Like so:
var requestUri = encodeURIComponent(URL).toLowerCase();
Seems rather simple but when trying to replicate the C# solution you may not pick up that the two URL encoders work differently.
Final solution: (updated to crypto thanks to Yoryo)
const fetch = require("node-fetch");
const uuid = require("uuid");
const crypto = require('crypto');
var URL = "https://urltoapi.com";
var itemAPPId = config.itemAPPId;
var APIKey = config.itemAPIKey;
var requestUri = encodeURIComponent(URL).toLowerCase();
var requestHttpMethod = "GET"; //should be dynamic
var requestTimeStamp = Math.floor(new Date().getTime() / 1000).toString();
var nonce = uuid.v1().replace(/-/g, '');
var signatureRawData = itemAPPId + requestHttpMethod + requestUri + requestTimeStamp + nonce;
var key = Buffer.from(APIKey, 'base64');
var requestSignatureBase64String = crypto.createHmac('sha256', key).update(signatureRawData, 'utf8').digest('base64');
const hitExternalAPI = async url => {
try {
const res = await fetch(url, { method: 'GET', headers: { "Authorization": "amx "+itemAPPId+":"+requestSignatureBase64String+":"+nonce+":"+requestTimeStamp } })
.then(res => {
console.log(res.ok);
});
} catch (error) {
console.log("Error",error);
}
};
hitExternalAPI(URL);

Using JavaScript to properly sign a string using HmacSHA256

In the Houndify API Docs for Authentication, you have the following block of content:
An Example of Authenticating a Request
Let's assume we have the following information:
UserID: ae06fcd3-6447-4356-afaa-813aa4f2ba41
RequestID: 70aa7c25-c74f-48be-8ca8-cbf73627c05f
Timestamp: 1418068667
ClientID: KFvH6Rpy3tUimL-pCUFpPg==
ClientKey: KgMLuq-k1oCUv5bzTlKAJf_mGo0T07jTogbi6apcqLa114CCPH3rlK4c0RktY30xLEQ49MZ-C2bMyFOVQO4PyA==
Concatenate the UserID string, RequestID string, and TimeStamp string in the following format: {user_id};{request_id}{timestamp}
With the values from the example, the expected output would be in this case: ae06fcd3-6447-4356-afaa-813aa4f2ba41;70aa7c25-c74f-48be-8ca8-cbf73627c05f1418068667
Sign the message with the decoded ClientKey. The result is a 32-byte binary string (which we can’t represent visually). After base-64 encoding, however, the signature is: myWdEfHJ7AV8OP23v8pCH1PILL_gxH4uDOAXMi06akk=
The client then generates two authentication headers Hound-Request-Authentication and Hound-Client-Authentication.
The Hound-Request-Authentication header is composed by concatenating the UserID and RequestID in the following format: {user-id};{request-id}. Continuing the example above, the value for this header would be:
Hound-Request-Authentication: ae06fcd3-6447-4356-afaa-813aa4f2ba41;70aa7c25-c74f-48be-8ca8-cbf73627c05f
The Hound-Client-Authentication header is composed by concatening the ClientID, the TimeStamp string and the signature in the following format: {client-id};{timestamp};{signature}. Continuing the example above, the value for this header would be: Hound-Client-Authentication: KFvH6Rpy3tUimL-pCUFpPg==;1418068667;myWdEfHJ7AV8OP23v8pCH1PILL_gxH4uDOAXMi06akk=
For Number 3, it says "Sign the message with the decoded ClientKey". The "message" and "ClientKey" are two distinct strings.
My question(s): How do you sign one string with another string i.e. what exactly does that mean? And how would you do that in JavaScript?
var message = 'my_message';
var key = 'signing_key';
//??what next??
I'm trying to figure all this out so I can create a pre-request script in Postman to do a proper HmacSHA256 hash.
According to the documentation, if you're using one of their SDKs, it will automatically authenticate your requests:
SDKs already handle authentication for you. You just have to provide
the SDK with the Client ID and Client Key that was generated for your
client when it was created. If you are not using an SDK, use the code
example to the right to generate your own HTTP headers to authenticate
your request.
However, if you want to do it manually, I believe you need to compute the HMAC value of the string they describe in the link in your question and then send it base64 encoded as part of the Hound-Client-Authentication header in your requests. They provide an example for node.js:
var uuid = require('node-uuid');
var crypto = require('crypto');
function generateAuthHeaders (clientId, clientKey, userId, requestId) {
if (!clientId || !clientKey) {
throw new Error('Must provide a Client ID and a Client Key');
}
// Generate a unique UserId and RequestId.
userId = userId || uuid.v1();
// keep track of this requestId, you will need it for the RequestInfo Object
requestId = requestId || uuid.v1();
var requestData = userId + ';' + requestId;
// keep track of this timestamp, you will need it for the RequestInfo Object
var timestamp = Math.floor(Date.now() / 1000),
unescapeBase64Url = function (key) {
return key.replace(/-/g, '+').replace(/_/g, '/');
},
escapeBase64Url = function (key) {
return key.replace(/\+/g, '-').replace(/\//g, '_');
},
signKey = function (clientKey, message) {
var key = new Buffer(unescapeBase64Url(clientKey), 'base64');
var hash = crypto.createHmac('sha256', key).update(message).digest('base64');
return escapeBase64Url(hash);
},
encodedData = signKey(clientKey, requestData + timestamp),
headers = {
'Hound-Request-Authentication': requestData,
'Hound-Client-Authentication': clientId + ';' + timestamp + ';' + encodedData
};
return headers;
};
So basically, signing [in this specific case] simply means to create a hash of the string using a hash algorithm in addition to a key, as opposed to a keyless hash [like MD5]. For example:
var message = 'my_message';
var key = 'signing_key';
var hashed_message = hash_func(message, key);
where hash_func is a hashing algorithm like HmacSHA256 (the hashing algorithm in question).
The reason I was trying to figure this out was to test authentication for the Houndify API using Postman. Fortunately, Postman has a nice feature called pre-request scripts [complete with hashing algorithms] that helps if you need to pre-generate values that need to be sent along with your request.
After much fiddling around, I managed to create a pre-request script that properly authenticates to this API (see code below).
var unescapeBase64Url = function (key) {
return key.replace(/-/g, '+').replace(/_/g, '/');
},
escapeBase64Url = function (key) {
return key.replace(/\+/g, '-').replace(/\//g, '_');
},
guid = function() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
};
var client_id_str = environment["client-id"];
var client_key_str = environment["client-key"];
var user_id_str = environment["user-id"];
var request_id_str = guid();
var timestamp_str = Math.floor(Date.now() / 1000);
var client_key_dec_str = CryptoJS.enc.Base64.parse(unescapeBase64Url(client_key_str));
var message_str = user_id_str+";"+request_id_str+timestamp_str;
var signature_hash_obj = CryptoJS.HmacSHA256(message_str, client_key_dec_str);
var signature_str = signature_hash_obj.toString(CryptoJS.enc.Base64);
var hound_request_str = user_id_str+";"+request_id_str;
var hound_client_str = client_id_str+";"+timestamp_str+";"+escapeBase64Url(signature_str);
postman.setEnvironmentVariable("hound-request-authentication", hound_request_str);
postman.setEnvironmentVariable("hound-client-authentication", hound_client_str);
Note that you are going to have to create environment variables in Postman for client-id, client-key, and user-id, as well as for the header variables hound-request-authentication and hound-client-authentication to hold the final values that will be referenced when defining headers.
Hope it helps.

Convert Node.JS code snippet to Javascript (Google Apps Script)

I would like to convert the following Node.JS code snippet to JavaScript in order to run it in Google Apps Script:
From: Node.JS
function getMessageSignature(path, request, nonce) {
var message = querystring.stringify(request);
var secret = new Buffer(config.secret, 'base64');
var hash = new crypto.createHash('sha256');
var hmac = new crypto.createHmac('sha512', secret);
var hash_digest = hash.update(nonce + message).digest('binary');
var hmac_digest = hmac.update(path + hash_digest, 'binary').digest('base64');
return hmac_digest;
}
This is the code I have tried so far (and many variations of it):
To: JavaScript / Google Apps Script
function getMessageSignature(url, request, nonce) {
// Message signature using HMAC-SHA512 of (URI path + SHA256(nonce + POST data))
//and base64 decoded secret API key
const secretApiKey = 'wdwdKswdKKewe23edeYIvL/GsltsGWbuBXnarcxZfu/9PjFbXl5npg==';
var secretApiKeyBytes = Utilities.base64Decode(secretApiKey);
var blob = Utilities.newBlob(secretApiKeyBytes);
var secretApiKeyString = blob.getDataAsString(); // POTENTIAL ERROR HERE?
var json = Utilities.jsonStringify(request);
var hash_digest = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_256,
nonce + json);
var hmac_digest = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_512,
url + hash_digest, secretApiKeyString); // POTENTIAL ERROR HERE?
var base64 = Utilities.base64Encode(hmac_digest);
return base64;
}
When sending the signature as part of my request to the server, I always get the error message from the server: Invalid Key.
BTW: This is the API which I would like to use in JavaScript: Kraken API
I would appreciate any hint or suggestions very much!!
Solution:
Use jsSHA (https://github.com/Caligatio/jsSHA/) rather than Google App Script's functions. Create a new "jsSHA.gs" code file in Google App Script and copy/past in all the jsSHA optimised .js files from github.
function getKrakenSignature (path, postdata, nonce) {
var sha256obj = new jsSHA ("SHA-256", "BYTES");
sha256obj.update (nonce + postdata);
var hash_digest = sha256obj.getHash ("BYTES");
var sha512obj = new jsSHA ("SHA-512", "BYTES");
sha512obj.setHMACKey (api_key_private, "B64");
sha512obj.update (path);
sha512obj.update (hash_digest);
return sha512obj.getHMAC ("B64");
}
function getKrakenBalance () {
var path = "/0/private/Balance";
var nonce = new Date () * 1000;
var postdata = "nonce=" + nonce;
var signature = getKrakenSignature (path, postdata, nonce);
var url = api_url + path;
var options = {
method: 'post',
headers: {
'API-Key': api_key_public,
'API-Sign': signature
},
payload: postdata
};
var response = UrlFetchApp.fetch (url, options);
// ERROR handling
return response.getContentText ();
}
One problem is that querystring.stringify is not the same as Utilities.jsonStringify (which, FYI, is deprecated in favor of JSON.stringify).
I believe that this will be equivalent:
function queryStringify(obj) {
var params = [];
for(var key in obj) {
if(Object.hasOwnProperty(key)) {
if(typeof key === 'string') {
params.push([key, obj[key]]);
} else {
obj[key].forEach(function(val) {
params.push([key, val]);
});
}
}
}
return params.map(function(param) {
return encodeURIComponent(param[0]) + '=' + encodeURIComponent(param[1]);
}).join('&');
}
Though I am not sure if that is the reason you are seeing your error.
I noticed this nodejs to GS converter: https://www.npmjs.com/package/codegs
Haven't got the chance to use it, but it claims to handle 'require'-statements.

Categories

Resources