Mandrill webhook authentication-signature not matched - node.js

Mandrill webhook authentication-verify signature
For node js
example verify signature
please check the code below
But its working only for event types like send, reject. Not working for event types like open, click & others
function generateSignature(webhook_key, url, params) {
var signed_data = url;
const param_keys = Object.keys(params);
param_keys.sort();
param_keys.forEach(function (key) {
signed_data += key + params[key];
});
hmac = crypto.createHmac('sha1', webhook_key);
hmac.update(signed_data);
return hmac.digest('base64');
}
let url = "https://your-app-domain.com/default/MandrillXP-new";
let key = "abcd1234"; //your mandrill webhook api key
let bodyPayload;
if(event.isBase64Encoded){
bodyPayload = Buffer.from(event.body, 'base64').toString()
}else{
bodyPayload = event.body
}
let splitData = req.body.split("=")
let decodeData = decodeURIComponent(splitData[1]);
var generatedSignature = generateSignature(key, url, { "mandrill_events": decodeData })
if (req.headers["x-mandrill-signature"]!== generatedSignature) {
console.log("signature mismatch")
}else{
console.log("signature matched")
}

replace '+' with ' '(space) in string before encode
var decodeData = decodeData .replace(/[+]/g, ' ');

Related

first two case working in switch statement why last case is not worked?

I am making dictionary website, for the proper word search within the API, I used there one switch statement (3rd case) which is not working , remaining cases running properly but 3rd case only given loader not output please give me proper solution.
// get element
const input = document.querySelector('#input');
const searchBtn = document.getElementById('button-addon2');
const loader = document.getElementById('loader');
const iword = document.querySelector('.iword');
const word = document.querySelector('.word');
const mean = document.querySelector('.meaning');
const audio = document.querySelector('audio');
// Event listner for search button
searchBtn.addEventListener('click', getData);
function getData(e) {
e.preventDefault();
iword.textContent = '';
word.textContent = '';
mean.textContent = '';
// get input data
let inputWord = input.value;
// call api get data
if (inputWord === '') {
alert ('Word is Required')
return;
}
getApiData(inputWord);
}
// get data from api
async function getApiData(inputWord) {
loader.style.display = 'block';
const apiKey = `https://www.dictionaryapi.com/api/v3/references/learners/json/${inputWord}?key=a6d01f54-9cfd-4941-957b-55935e9f4c5d`;
try {
let response = await fetch(apiKey);
let data = await response.json();
switch (true) {
case (!data.length) :
loader.style.display = 'none';
iword.textContent = inputWord;
word.textContent = 'No Result Found';
break;
case (typeof data[0] === 'string') :
loader.style.display = 'none';
iword.textContent = inputWord;
let sHeading = document.createElement('h3');
sHeading.textContent = 'Did You Mean ?'
mean.appendChild(sHeading);
data.forEach(element => {
let suggetion = document.createElement('span');
suggetion.classList.add('suggested');
suggetion.textContent = element;
mean.appendChild(suggetion);
});
break ;
case data[0].shortdef[0] :
loader.style.display = 'none';
iword.textContent = inputWord;
word.textContent = meaning;
console.log('hey');
break ;
}}
catch (error) {
// catch error here
}
}

Unable to deploy NFT in terminal

I already deployed my smart contract to my wallet and connected it to my Alchemy account.
Here are my codings (Note that my contract address, PUBLIC_KEY, PRIVATE_KEY, API_URL and alchemy address are edited for security purposes).
mint-nft.js
require('dotenv').config();
const API_URL = process.env.API_URL;
const PUBLIC_KEY = process.env.PUBLIC_KEY;
const PRIVATE_KEY = process.env.PRIVATE_KEY;
const { createAlchemyWeb3 } = require("#alch/alchemy-web3");
const web3 = createAlchemyWeb3(API_URL);
const contract = require("../artifacts/contracts/MyNFT.sol/MyNFT.json");
const contractAddress = "My_Contract_Adress";
const nftContract = new web3.eth.Contract(contract.abi, contractAddress);
async function mintNFT(tokenURI) {
const nonce = await web3.eth.getTransactionCount(PUBLIC_KEY, 'latest'); //get latest nonce
//the transaction
const tx = {
'from': PUBLIC_KEY,
'to': contractAddress,
'nonce': nonce,
'gas': 500000,
'data': nftContract.methods.mintNFT(PUBLIC_KEY, tokenURI).encodeABI()
};
const signPromise = web3.eth.accounts.signTransaction(tx, PRIVATE_KEY);
signPromise.then((signedTx) => {
web3.eth.sendSignedTransaction(signedTx.rawTransaction, function(err, hash) {
if (!err) {
console.log("The hash of your transaction is: ", hash, "\nCheck Alchemy's Mempool to view the status of your transaction!");
} else {
console.log("Something went wrong when submitting your transaction:", err)
}
});
}).catch((err) => {
console.log(" Promise failed:", err);
});
}
mintNFT("https://gateway.pinata.cloud/ipfs/My_NFT_Picture_Hash");
alchemyContext.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.makeAlchemyContext = void 0;
var tslib_1 = require("tslib");
var sturdy_websocket_1 = tslib_1.__importDefault(require("sturdy-websocket"));
var websocket_1 = require("websocket");
var jsonRpc_1 = require("../util/jsonRpc");
var version_1 = require("../version");
var alchemySendHttp_1 = require("./alchemySendHttp");
var alchemySendWebSocket_1 = require("./alchemySendWebSocket");
var httpProvider_1 = require("./httpProvider");
var sendPayload_1 = require("./sendPayload");
var webSocketProvider_1 = require("./webSocketProvider");
var NODE_MAX_WS_FRAME_SIZE = 100 * 1024 * 1024; // 100 MB
function makeAlchemyContext(url, config) {
var makePayload = jsonRpc_1.makePayloadFactory();
if (/^https?:\/\//.test(url)) {
var alchemySend = alchemySendHttp_1.makeHttpSender(url);
var _a = sendPayload_1.makePayloadSender(alchemySend, config), sendPayload = _a.sendPayload, setWriteProvider = _a.setWriteProvider;
var senders = jsonRpc_1.makeSenders(sendPayload, makePayload);
var provider = httpProvider_1.makeAlchemyHttpProvider(sendPayload);
return { provider: provider, senders: senders, setWriteProvider: setWriteProvider };
}
else if (/^wss?:\/\//.test(url)) {
var protocol = isAlchemyUrl(url) ? "alchemy-web3-" + version_1.VERSION : undefined;
var ws = new sturdy_websocket_1.default(url, protocol, {
wsConstructor: getWebSocketConstructor(),
});
var alchemySend = alchemySendWebSocket_1.makeWebSocketSender(ws);
var _b = sendPayload_1.makePayloadSender(alchemySend, config), sendPayload = _b.sendPayload, setWriteProvider = _b.setWriteProvider;
var senders = jsonRpc_1.makeSenders(sendPayload, makePayload);
var provider = new webSocketProvider_1.AlchemyWebSocketProvider(ws, sendPayload, senders);
return { provider: provider, senders: senders, setWriteProvider: setWriteProvider };
}
else {
throw new Error("Alchemy URL protocol must be one of http, https, ws, or wss. Recieved: " + url);
}
}
exports.makeAlchemyContext = makeAlchemyContext;
function getWebSocketConstructor() {
return isNodeEnvironment()
? function (url, protocols) {
return new websocket_1.w3cwebsocket(url, protocols, undefined, undefined, undefined, {
maxReceivedMessageSize: NODE_MAX_WS_FRAME_SIZE,
maxReceivedFrameSize: NODE_MAX_WS_FRAME_SIZE,
});
}
: WebSocket;
}
function isNodeEnvironment() {
return (typeof process !== "undefined" &&
process != null &&
process.versions != null &&
process.versions.node != null);
}
function isAlchemyUrl(url) {
return url.indexOf("alchemyapi.io") >= 0;
}
.env
API_URL = "https://eth-rinkeby.alchemyapi.io/v2/KEY"
PRIVATE_KEY = "MY_PRIVATE_KEY"
PUBLIC_KEY = "MY_PUBLIC_KEY"
But then I was trying to deploy my NFT with metadata and nft-mint.js, I got these error.
Can anyone please tell me what was the error about?
Your issue may be with dotenv not reading in the values in your .env.
If you add console.log(API_URL), is it correct or is it undefined?
If it is undefined, I was able to resolve the issue by adding the path to my .env like so:
require('dotenv').config({path:"../.env"});
(In my case my mint-nft.js was in scripts/mint-nft.js
and .env is in the root directory.)

Bitstamp Authenticated API hmac

I hope you have more luck on this than I have.
As the title suggests I am trying to hit a private API endpoint on bitstamp.net. https://www.bitstamp.net/api/#api-authentication try as I might I cannot get the signature to make sense. I have followed the docs as close as I know how, I have spent hours trying to learn as much python as possible and decyphering the docs, as there is no JavaScript example.
The signature is supposed to be a sha256 hmac of the API secret and the message variable which is a backslash seperated string that I cannot find anything wrong with anymore.
I use the below link to query the server, the apikey and secret will be encoded and decoded in production when this all works.
http://localhost:3001/sha256/jorw1007/QGcJKrhenfqOML5cOpTsLOe9IbEPsJnN/bKXiqtYHawJ7DAUZIHviAPoRrp0zhfIv
const crypto = require('crypto');
app.get("/sha256/:id/:key/:secret", cors(), (request, response, next) => {
const APIkey = "BITSTAMP" + " " + request.params.key;
const APIsecret = request.params.secret;
const urlHost = "192.168.0.120:3001"; // where is querying the API from bitstamp? in this case its the server localhost:3001
const urlPath = "/api/v2/balance/";
const urlQuery = "";
const UTC = Date.now().toString();
const nonce = randomBytes(18).toString("hex").toLowerCase();
const nonce2 = "f93c979d-b00d-43a9-9b9c-fd4cd9547fa6"
const contentType = "application/x-www-form-urlencoded";
const version = "v2";
const payload = urlencoded({"offset": "1"})
let message = `${APIkey}\\POST\\${urlHost}\\${urlPath}\\${urlQuery}\\${nonce}\\${UTC}\\${version}\\`
// const encodedMsg = encodeURI(message) ///why are we encoding?
// const signature = createHmac("sha256", APIsecret ).update(JSON.stringify(encodedMsg) );
// const sigDigested = signature.digest('hex')
var signature = crypto.createHmac('sha256', APIsecret).update(encodeURI(message));
// to lowercase hexits
const digestedHash = signature.digest('hex');
console.log(message)
const headers = {
"X-Auth": APIkey,
"X-Auth-Signature": digestedHash,
"X-Auth-Nonce": nonce,
"X-Auth-Timestamp": UTC,
"X-Auth-Version": version,
};
fetch("https://www.bitstamp.net/api/v2/balance/", {
headers,
method: "POST",
data : payload
})
.then((res) => res.json())
.then((json) => response.send(json))
.catch((err) => console.error(err));
});
I keep getting error 'API0005' which means the signature is invalid.
Please could someone point me in the right direction?
thank you
After countless effort I finally managed to get it work. The code I will be posting is in C# but it very much resembles that of JavaScript.
protected async Task<string> SendRequest(string #base, string endpoint, EndpointHttpMethod method, Dictionary<string, object> parameters = null, bool signed = true)
{
var resiliencyStrategy = ExchangeTools.DefineAndRetrieveResiliencyStrategy("Bitstamp");
parameters ??= new Dictionary<string, object>();
var payloadString = string.Empty;
var queryParameters = string.Empty;
var contentType = string.Empty;
if (method == EndpointHttpMethod.GET)
{
queryParameters = ExchangeTools.BuildQuery(parameters);
endpoint += !string.IsNullOrWhiteSpace(queryParameters) ? $"?{queryParameters}" : string.Empty;
}
else
{
payloadString = ExchangeTools.BuildQuery(parameters, true);
contentType = !string.IsNullOrWhiteSpace(payloadString) ? "application/x-www-form-urlencoded" : string.Empty;
}
using var client = new HttpClient();
using var httpRequestMessage = new HttpRequestMessage(new HttpMethod(method.ToString()), endpoint);
client.BaseAddress = new Uri(Endpoints.BasePrefix + #base);
if (signed)
{
var apiKey = $"BITSTAMP {publicKey}";
var version = "v2";
var nonce = Guid.NewGuid();
var timestamp = ExchangeTools.GetUnixTimestamp(1000);
var msg = $"{apiKey}{method}{#base}{endpoint}{queryParameters}{contentType}{nonce}{timestamp}{version}{payloadString}";
var signature = ExchangeTools.Sign(msg, privateKey, HashingAlgorithm.HMACSHA256, ByteEncoding.ASCII, SignatureEncoding.HexString);
httpRequestMessage.Headers.Add("X-Auth", apiKey);
httpRequestMessage.Headers.Add("X-Auth-Signature", signature);
httpRequestMessage.Headers.Add("X-Auth-Nonce", nonce.ToString()); ;
httpRequestMessage.Headers.Add("X-Auth-Timestamp", timestamp.ToString()); ;
httpRequestMessage.Headers.Add("X-Auth-Version", version);
if(parameters.Count > 0)
{
httpRequestMessage.Content = new FormUrlEncodedContent(parameters.ToDictionary(kv => kv.Key, kv => kv.Value.ToString()));
}
}
var response = await resiliencyStrategy.ExecuteAsync(() => client.SendAsync(httpRequestMessage));
var result = await response.Content.ReadAsStringAsync();
return result;
}
Let me know if you need further clarification. My best guess as to why yours is not working comes down to conditionally setting the payload and queryParam depending on what parameters you have and whether the request is a GET or POST.

NodeJs + Request-promise - error catching

I'm having trouble with error handling with my function in my bot for Discord. What I've got right now is a command that scraps information from a website, I want to make it so if there is an error (404), the user will get some feedback. How would I go about doing this? Right now I currently have something, but I'm not sure what I'm doing wrong. Here is a snippet of code:
//modules used
const rp = require('request-promise-native');
const errors = require('request-promise/errors');
const cheerio = require('cheerio');
if (message.content.startsWith(prefix + 'latest')) {
//website url variables
const website_domain = "https://hypebeast.com/";
let website_path = args[0];
let website_url = website_domain + website_path;
//extra arguments variable
let extra_arg = args.slice(1).join(" ");
if (extra_arg.length > 0) {
message.reply('too many arguments! Please refer to `h.help` for correct usage.');
} else {
//opening url and scrapping elements
function scrapData(website_url) {
return rp(website_url)
.then(body => {
let items = [],
$ = cheerio.load(body).catch(errors.StatusCodeError, function (reason) {
console.log(reason);
});
//web scrapping here
$('.post-box').each(function() {
let title = $(this).find($('.title h2 span')).first().text(),
caption = $(this).find($('.post-box-excerpt p')).first().text(),
article_url = $(this).find($('.col-hb-post-image a')).first().attr('href'),
thumbnail_long = $(this).find($('.thumbnail img')).first().attr('src');
//adding title, caption, etc to list
items.push({title, caption, article_url, thumbnail_long});
//check items in console
console.log(items);
})
return items;
})
}
I have just modified your code little try this below code.
//modules used
const rp = require('request-promise-native');
const errors = require('request-promise/errors');
const cheerio = require('cheerio');
if (message.content.startsWith(prefix + 'latest')) {
//website url variables
const website_domain = "https://hypebeast.com/";
let website_path = args[0];
let website_url = website_domain + website_path;
//extra arguments variable
let extra_arg = args.slice(1).join(" ");
if (extra_arg.length > 0) {
message.reply('too many arguments! Please refer to `h.help` for correct usage.');
} else {
var options = {
uri: website_url,
transform: function (body) {
return cheerio.load(body);
}
};
rp(options)
.then(function ($) {
// Process html like you would with jQuery...
$('.post-box').each(function() {
let title = $(this).find($('.title h2 span')).first().text(),
caption = $(this).find($('.post-box-excerpt p')).first().text(),
article_url = $(this).find($('.col-hb-post-image a')).first().attr('href'),
thumbnail_long = $(this).find($('.thumbnail img')).first().attr('src');
//adding title, caption, etc to list
items.push({title, caption, article_url, thumbnail_long});
//check items in console
console.log(items);
});
})
.catch(function (err) {
console.log(err);
});
}

Payment gateway for using with nodejs that accepts INR

I'm looking for a payment gateway that supports INR, that I can use with a nodejs app. Can't find anything that works. Any suggestions and pointers would be helpful.
I think citruspay is a good choice. The following links show integrations with node js.
Merchant Hosted Checkout (Citrus.js)
var crypto = require('crypto');
function generateSignature(merchantTxnId, request) {
//Need to change with your Secret Key
var secret_key = "***SEcRETKey***";
//Need to change with your Access Key
var accesskey = "***Access Key***";
//Should be unique for every transaction
var txn_id = merchantTxnId;
//Need to change with your Order Amount
var amount = "1.00";
var data = 'merchantAccessKey=' + accesskey + '&transactionId=' + txn_id + '&amount=' + amount;
// generate hmac
var hmac = crypto.createHmac('sha1', secret_key);
hmac.update(data);
return hmac.digest('hex');
}
Now include this signature in PaymentObject
Then listen for post on the Return URL
You have to generate signature and compare with the signature sent in the post data from citrus to make sure data is not tampered in the way.
var http = require("http");
var qs = require('querystring');
var crypto = require('crypto');
var secret_key = "MERCHANT_SECRET_KEY";
http.createServer(function(request, response) {
var body = "";
if (request.method = "POST") {
request.on("data", function(data) { body += data; });
request.on("end", function() {
var post = qs.parse(body);
var data_string = post['TxId'] + post['TxStatus'] + post['amount']
+ post['pgTxnNo'] + post['issuerRefNo'] + post['authIdCode']
+ post['firstName'] + post['lastName'] + post['pgRespCode']
+ post['addressZip'];
var signature = crypto.createHmac('sha1',
secret_key).update(data_string).digest('hex');
if (signature == post['signature']) {
response.writeHead(200, {"Content-Type": "application/json"});
console.log(post);
response.write(JSON.stringify(post));
}
else {
response.writeHead(403, {"Content-Type": "application/json"});
var error = {error : 'Transaction Failed', message: 'Signature Verification Failed'};
response.write(JSON.stringify(error));
}
response.end();
});
}
}).listen(3000);

Resources