Skip to content

Instantly share code, notes, and snippets.

@mdsohelmia
Created October 1, 2023 10:51
Show Gist options
  • Save mdsohelmia/a4d8c5b011391f0a4f4c97246650a60b to your computer and use it in GitHub Desktop.
Save mdsohelmia/a4d8c5b011391f0a4f4c97246650a60b to your computer and use it in GitHub Desktop.
const ec = new TextEncoder();
const algorithm = { name: "HMAC", hash: "SHA-256" };
// generates a signature for the given data using the given key
async function generateHmacKey(secret) {
const { subtle } = globalThis.crypto;
return subtle.importKey(
"raw",
typeof secret === "string" ? ec.encode(secret) : secret,
algorithm,
false,
["sign"]
);
}
async function hash(key, data) {
const { subtle } = globalThis.crypto;
return subtle.sign(algorithm, await generateHmacKey(key), ec.encode(data));
}
function arrayBufferToHexString(arrayBuffer) {
const byteArray = new Uint8Array(arrayBuffer);
let hexString = "";
for (let i = 0; i < byteArray.length; i++) {
hexString += byteArray[i].toString(16).padStart(2, "0");
}
return hexString;
}
const nonce = generateNonce();
const date = new Date();
const apiSecret = "DEYt52UW00siPrqeaTIaSKL8o7cMhUil";
const requestData = {
method: "GET",
uri: "/example",
xDate: ISO8601DateFormat(date),
nonce: generateNonce(),
requestBody: '{"data": "test"}',
};
async function createAuthorizeToken(secret, data) {
const signature = await hash(secret, data);
const hexSignature = arrayBufferToHexString(signature);
return hexSignature;
}
// Construct the signing string
const signingString = `${requestData.method}\n${requestData.uri}\n${requestData.timestamp}\n${requestData.nonce}\n${requestData.requestBody}`;
async function performAPICall() {
const signature = await createAuthorizeToken(apiSecret, signingString);
const headers = {
Authorization: `${apiSecret}:${signature}`,
"Content-Type": "application/json",
"X-Date": requestData.xDate,
"X-Nonce": requestData.nonce,
}
// xhr request
const xhr = new XMLHttpRequest();
xhr.open(requestData.method, `https://api.sandbox.gemini.com${requestData.uri}`, true);
xhr.setRequestHeader("Authorization", headers.Authorization);
xhr.setRequestHeader("Content-Type", headers["Content-Type"]);
xhr.setRequestHeader("X-Date", headers["X-Date"]);
xhr.setRequestHeader("X-Nonce", headers["X-Nonce"]);
xhr.send(requestData.requestBody);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
console.log(xhr.status);
console.log(xhr.responseText);
}
}
}
performAPICall();
// Authorization Header Format
// Authorization:${apiSecret}:${signature}
//Content-Type: application/json
// X-Date: ${date}
// X-Nonce: ${nonce}
function generateNonce() {
const timestamp = Date.now(); // in milliseconds
const randomDigits = Math.floor(Math.random() * 1000);
const nonce = `${timestamp}${randomDigits}`;
return nonce;
}
function ISO8601DateFormat(date) {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, "0"); // Months are 0-based, so add 1 and pad with 0 if necessary
const day = String(date.getDate()).padStart(2, "0");
const hours = String(date.getHours()).padStart(2, "0");
const minutes = String(date.getMinutes()).padStart(2, "0");
const seconds = String(date.getSeconds()).padStart(2, "0");
return `${year}${month}${day}T${hours}${minutes}${seconds}Z`;
}
console.log(ISO8601DateFormat(date));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment