Gate io error INVALID_SIGNATURE in app script - javascript

I try to get data from Exchange Gate.io by app script.
This is my code:
function data() {
var key = "***"
var sec = "***"
var timestamp = Math.floor(Date.now() / 1000)
var base = "https://api.gateio.ws";
var prefix = "/api/v4"
var pat = '/wallet/total_balance'
var sign = "timestamp=" + timestamp;
Logger.log(sign)
var signature = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_512, sign, sec);
signature = signature.map(function(e) {
var v = (e < 0 ? e + 256 : e).toString(16);
return v.length == 1 ? "0" + v : v;
}).join("");
var params = {
'method': "get",
'headers': {
'Accept': 'application/json',
'Content-Type': 'application/json',
'KEY': key,
'Timestamp': timestamp,
'SIGN': signature,
},
'muteHttpExceptions': true,
};
var data = UrlFetchApp.fetch(base + prefix + pat, headers=params);
Logger.log(data)
}
I get the error:
{"label":"INVALID_SIGNATURE","message":"Signature mismatch"}
The Keys is valid problem in code.
to learn more check that: https://www.gate.io/docs/apiv4/en/#retrieve-user-s-total-balances

About the official document, when I directly access the URL, an error occurs. But, when I search it on Google and access it, I could open the document. From the document, I found the documentation for the authorization and the document for "Retrieve user's total balances". And also, I found the following sample python script from the official document.
import time
import hashlib
import hmac
import requests
def gen_sign(method, url, query_string=None, payload_string=None):
key = '' # api_key
secret = '' # api_secret
t = time.time()
m = hashlib.sha512()
m.update((payload_string or "").encode('utf-8'))
hashed_payload = m.hexdigest()
s = '%s\n%s\n%s\n%s\n%s' % (method, url, query_string or "", hashed_payload, t)
sign = hmac.new(secret.encode('utf-8'), s.encode('utf-8'), hashlib.sha512).hexdigest()
return {'KEY': key, 'Timestamp': str(t), 'SIGN': sign}
host = "https://api.gateio.ws"
prefix = "/api/v4"
headers = {'Accept': 'application/json', 'Content-Type': 'application/json'}
url = '/wallet/total_balance'
query_param = ''
# for `gen_sign` implementation, refer to section `Authentication` above
sign_headers = gen_sign('GET', prefix + url, query_param)
headers.update(sign_headers)
r = requests.request('GET', host + prefix + url, headers=headers)
print(r.json())
In your situation, when this script is converted to Google Apps Script, I thought that it is your goal. When this python script is converted to Google Apps Script, it becomes as follows.
Sample script:
Before you use this script, please set the variables of key and secret.
function gen_sign_(key, secret, method, url, query_param = "", payload_string = "") {
const t = (Date.now() / 1000).toString();
const c1 = Utilities.computeDigest(Utilities.DigestAlgorithm.SHA_512, payload_string, Utilities.Charset.UTF_8);
const c2 = Utilities.formatString('%s\n%s\n%s\n%s\n%s', method, url, query_param, c1.map(b => ("0" + (b < 0 && b + 256 || b).toString(16)).slice(-2)).join(""), t);
const c3 = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_512, c2, secret, Utilities.Charset.UTF_8);
const sign = c3.map(b => ("0" + (b < 0 && b + 256 || b).toString(16)).slice(-2)).join("");
return { "KEY": key, "Timestamp": t, "SIGN": sign };
}
// Please run this function.
function main() {
const key = "your api key";
const secret = "your secret";
const host = "https://api.gateio.ws";
const prefix = "/api/v4";
const url = "/wallet/total_balance";
const method = "GET";
const signature = gen_sign_(key, secret, method, prefix + url);
const headers = { "Accept": "application/json", "Content-Type": "application/json", "muteHttpExceptions": true, ...signature };
const res = UrlFetchApp.fetch(host + prefix + url, { method, headers });
console.log(res.getContentText());
}
Note:
When I tested the script using the sample variables of const key = "sample", const secret = "sample" and const t = "1234567890.123" for the python script in the official document and Google Apps Script, the same value of signature could be obtained as follows. Both requests are also the same.
603899db07ca29e5240de397b8088271b765925ba29a67267b33ad0b076fc31b0cf98d623878d57bf824b58e5336fd74f1cd101e9377816c34fec2acb9358cb2
So, when you test the above sample Google Apps Script and if an error occurs, please confirm your variables again. And, please show the error message.
References:
computeDigest(algorithm, value, charset)
formatString(template, args)
computeHmacSignature(algorithm, value, key, charset)
map()

Related

AWS API Call from GAS Signature Mismatch

I have been trying to get an api call to Amazon SES to work for sending bulk emails. After figuring out issues with dates I'm now getting an error about the signatures mismatching. My code is below
function sendEmails() {
var template = HtmlService.createHtmlOutputFromFile('EmailTemplate.html');
var output = template.getContent();
var subject = 'Message from Mr. Bunz';
var data = JSON.stringify(
{
"Content": {
"Simple": {
"Body": {
"Html": {
"Data": output
},
},
"Subject": {
"Data": subject
}
},
},
"Destination": {
"ToAddresses": [ "example#gmail.com" ]
},
"FromEmailAddress": "no-reply#mail.example.com",
"ReplyToAddresses": [ "josh#example.com" ]
}
);
var url = 'https://email.us-west-1.amazonaws.com/v2/email/outbound-emails';
var aws_key_id = 'AKIAWLG4NO6GFEXAMPLE';
var aws_key = 'wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY';
var today = new Date();
var amz_date_iso = Utilities.formatDate(today,"UTC","YYYYMMd'T'HHmmss'Z'");
var amz_date = Utilities.formatDate(today,"UTC",'YYYYMMd');
console.log(amz_date)
var signature = awsSignature(aws_key,amz_date_iso);
var headers = {
"contentType": "application/json",
'X-Amz-Date': amz_date_iso,
"Authorization": "AWS4-HMAC-SHA256 Credential="+aws_key_id+"/"+amz_date+"/us-west-1/ses/aws4_request, SignedHeaders=content-type;host;x-amz-date;, Signature="+signature
};
console.log(headers);
var options = {
"method": "POST",
"headers": headers,
"payload": data,
"muteHttpExceptions" : true,
};
apiresponse = UrlFetchApp.fetch(url,options);
console.log(apiresponse.getContentText());
}
function awsSignature(key,dateStamp) {
var regionName = 'us-west-1';
var serviceName = 'iam';
var kDate = Utilities.computeHmacSha256Signature(dateStamp, "AWS4" + key);
var kRegion = Utilities.computeHmacSha256Signature(
Utilities.newBlob(regionName).getBytes(),
kDate
);
var kService = Utilities.computeHmacSha256Signature(
Utilities.newBlob(serviceName).getBytes(),
kRegion
);
var kSigning = Utilities.computeHmacSha256Signature(
Utilities.newBlob("aws4_request").getBytes(),
kService
);
kSigning = kSigning
.map(function(e) {
return ("0" + (e < 0 ? e + 256 : e).toString(16)).slice(-2);
})
.join("");
Logger.log(kSigning);
return kSigning;
}
The exact error message is below
{"message":"The request signature we calculated does not match the
signature you provided. Check your AWS Secret Access Key and signing
method. Consult the service documentation for details."}
I've tried generating a new key/id pair with no luck. The two answers on this issue on stackoverflow I have found are here and here.
I was getting a byte array back and couldn't figure out how to convert it into the needed signature so my implementation of creating the signature is based on this post.
Would greatly appreciate any and all help.
Update
After checking my signature code with the example values provided here I noticed that at the bottom where it gives the example output it says that while those are hex representations the actual signature should be binary. Now I'm having trouble converting hex to binary in GAS

Authorization Failed while making GET Request to Azure Blob Storage [REST API][Azure Blob Storage]

I am trying to make a GET request to get Account details of my Azure Blob Storage account, but it shows Auth failed each and every time.
Can anyone tell whether the Header or Signature String formed is correct or is there any other issue?
Here's the code:
const account = process.env.ACCOUNT_NAME || "";
const key = process.env.ACCOUNT_KEY || "";
var strTime = new Date().toUTCString();
var strToSign =
"GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:" +
strTime +
`\nx-ms-version:2018-03-28\n/${account}/\ncomp:properties\nrestype:account`;
var secret = CryptoJS.enc.Base64.parse(key);
var hash = CryptoJS.HmacSHA256(strToSign, secret);
var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
var auth = `SharedKey ${account}:${hashInBase64}`;
const options = {
url: `https://${account}.blob.core.windows.net/?comp=properties&restype=account`,
headers: {
Authorization: auth,
"x-ms-date": strTime,
"x-ms-version": "2018-03-28",
},
};
function callback(error, response, body) {
var json = parser.toJson(body);
console.log(error);
console.log(response);
if (!error && response.statusCode == 200) {
var json = parser.toJson(body);
console.log(json);
}
}
request(options, callback);
After this, the response.statusCode which I am getting is Status 403.
statusCode: 403,
statusMessage: 'Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.',
The details about the azure-blob and headers and Auth could be found here:
https://learn.microsoft.com/en-us/rest/api/storageservices/authorize-with-shared-key
https://learn.microsoft.com/en-us/rest/api/storageservices/get-account-information
EDIT:
The string param = has been corrected to :
It will be much easier using Azure Storage JS SDK to make requests to Azure Blob Storage. If you want to get your storage account information, just try code below:
const { BlobServiceClient, StorageSharedKeyCredential } = require("#azure/storage-blob");
const account = '<storage account name>'
const accountKey = '<storage account key>'
const sharedKeyCredential = new StorageSharedKeyCredential(account, accountKey);
const blobServiceClient = new BlobServiceClient(
`https://${account}.blob.core.windows.net`,
sharedKeyCredential
);
blobServiceClient.getAccountInfo().then((result)=>{
console.log("accountKind:"+result.accountKind + " skuName:" + result.skuName + " version:" + result.version );
})
Result:
Update:
If you want to try it in a more generic fashion, try the code below:
var CryptoJS = require("crypto-js");
var request = require("request");
var parser = require('body-parser')
const account = ''
const key = ''
var strTime = new Date().toUTCString();
var strToSign =
"GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:" +
strTime +
`\nx-ms-version:2018-03-28\n/${account}/\ncomp:properties\nrestype:account`;
//console.log(strToSign);
var secret = CryptoJS.enc.Base64.parse(key);
var hash = CryptoJS.HmacSHA256(strToSign, secret);
var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
var auth = `SharedKey ${account}:${hashInBase64}`;
const options = {
url: `https://${account}.blob.core.windows.net/?comp=properties&restype=account`,
headers: {
Authorization: auth,
"x-ms-date": strTime,
"x-ms-version": "2018-03-28",
},
};
function callback(error, response, body) {
console.log(body);
if (!error && response.statusCode == 200) {
console.log(response.headers["x-ms-sku-name"]);
}
}
request(options, callback);
Result:
Seems you should use : instead of = in last param of your strToSign .

How to login through api from Google Script?

I'm now working on the api of Gatecoin and want to get my open order on Google Sheet. I'm trying this:
function GetOrder() {
var method = "GET"
var URL = "https://api.gatecoin.com/Trade/Orders"
var contentType = "application/json"
var d = new Date()
var now = d.getTime()
var msg = method + URL + contentType + now
var publicKey = :Public_key
var privateKey = :Private_key
var hash = Utilities.computeHmacSha256Signature(msg, privateKey, Utilities.Charset.US_ASCII);
var hashInBase64 = Utilities.base64Encode(hash);
var options ={
'contentType': 'application/json',
'method': method,
'API_PUBLIC_KEY': publicKey,
'API_REQUEST_SIGNATURE': hashInBase64,
'API_REQUEST_DATE': now
};
var rdata = UrlFetchApp.fetch("https://api.gatecoin.com/Trade/Orders", options)
}
But the response mentions I was not logged in. What am I doing wrong?
I believe your options should have headers defined in an object as such:
var options ={
“contentType”: “application/json”,
“method”: method,
“headers”: {
“API_PUBLIC_KEY”: publicKey,
“API_REQUEST_SIGNATURE”: hashInBase64,
“API_REQUEST_DATE”: now
}
};

Undefined Error when parsing JSON in google apps script

I'm trying to parse JSON I recieved from an API call, but I keep running into the error "TypeError: Cannot read property "id" from undefined. (line 42, file "")" I'm relatively new to Apps Script. Any ideas on what's going on? I can get the payload back in JSON, but can't seem to parse it.
function getInfo() {
var url = "https://subdomain.chargify.com/subscriptions.json";
var username = "xxx"
var password = "x"
var headers = {
"Authorization": "Basic " + Utilities.base64Encode(username + ':' + password)
};
var options = {
"method": "GET",
"contentType": "application/json",
"headers": headers
};
var response = UrlFetchApp.fetch(url, options);
var data = JSON.parse(response.getContentText());
Logger.log(data);
var id = data.subscription; // kicks back an error
// var id = data; works and returns the whole JSON payload
var ss = SpreadsheetApp.getActiveSheet()
var targetCell = ss.setActiveSelection("A1");
targetCell.setValue(id);
}
According to the documentation here
https://docs.chargify.com/api-subscriptions#api-usage-json-subscriptions-list
it returns an array of subscriptions when you call the /subscriptions.json endpoint. So probably your data object should be handled like:
for (var i=0;i<data.length;i++) {
var item = data[i]; //subscription object, where item.subscription probably works
Logger.log(JSON.stringify(item));
}
function getInfo() {
var url = "https://subdomain.chargify.com/subscriptions.json";
var username = "xxx"
var password = "x"
var headers = {
"Authorization": "Basic " + Utilities.base64Encode(username + ':' + password)
};
var options = {
"method": "GET",
"contentType": "application/json",
"headers": headers
};
var response = UrlFetchApp.fetch(url, options);
var data = JSON.parse(response.getContentText());
for (var i = 0; i < data.length; i++) {
var item = data[i]; //subscription object, where item.subscription probably works
Logger.log(JSON.stringify(item));
var subscriptionid = item.subscription.id;
}
var ss = SpreadsheetApp.getActiveSheet()
var targetCell = ss.setActiveSelection("A2");
targetCell.setValue(subscriptionid);
}

restructure string in javascript

I have this string in which i need to re-structure using JavaScript.
Label=11121212&TopicArn=test&AWSAccountId.member.1=YYYYYYY&ActionName.member.1=createTopic&Action=AddPermission&Version=2010-03-31&AWSAccessKeyId=XXXXXXXXX&SignatureVersion=2&SignatureMethod=HmacSHA1&Timestamp=2012-05-02T16%3A06%3A09.000Z&Signature=C3uIh%2Bz%2Fik
For this example, AWSAccessKeyId should be the first part of the string and label should be 2nd last. There are others as well, similar to this.
Expected output --AWSAccessKeyId=XXXXXXXXX&AWSAccountId.member.1=YYYYYYYYY&Action=AddPermission&ActionName.member.1=Publish&Label=ios-sns-permission-label&Signature=dEaNL0ibP5c7xyl4qXDPFPADW0meoUX9caKyUIx1wkk%3D&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2012-05-02T00%3A51%3A23.965Z&TopicArn=arn%3Aaws%3Asns%3Aus-east-1%3A335750469596%3AiOSGoesWooooo-1335919882&Version=2010-03-31
Code that creates this incorrect string
exports.generatePayload = function(params, accessKeyId, secretKey, endpoint) {
var host = endpoint.replace(/.*:\/\//, "");
var payload = null;
var signer = new AWSV2Signer(accessKeyId, secretKey);
params = signer.sign(params, new Date(), {
"verb" : "POST",
"host" : host,
"uriPath" : "/"
});
var encodedParams = [];
for(var key in params) {
if(params[key] !== null) {
encodedParams.push(encodeURIComponent(key) + "=" + encodeURIComponent(params[key]));
} else {
encodedParams.push(encodeURIComponent(key));
}
}
payload = encodedParams.join("&");
return payload;
}
I tried putting this in an array and restructure it but it didn't work for me.
Please advice how this can be done easily using JavaScript
exports.generatePayload = function(params, accessKeyId, secretKey, endpoint) {
var host = endpoint.replace(/.*:\/\//, "");
var payload = null;
var signer = new AWSV2Signer(accessKeyId, secretKey);
params = signer.sign(params, new Date(), {
"verb" : "POST",
"host" : host,
"uriPath" : "/"
});
var encodedParams = [];
if(params["AWSAccessKeyId"] != null)
{
encodedParams.push(encodeURIComponent("AWSAccessKeyId") + "=" + encodeURIComponent(params["AWSAccessKeyId"]));
}
if(params["AWSAccountId.member.1"] != null)
{
encodedParams.push(encodeURIComponent("AWSAccountId.member.1") + "=" + encodeURIComponent(params["AWSAccountId.member.1"]));
}
//other_ifs_for_param_keys_here
payload = encodedParams.join("&");
return payload;

Categories

Resources