Im trying to integrate 2Checkout on application that the front-end is build on Angular 11 and back end Node js, i managed to integrate IPN(Instant Payment Notification) of 2Checkout but i get a notification that says: ""
Our system detected that you have slow responding web hooks.
after checking documentation multiple times i saw that i need to return <EPAYMENT>20050303123434|7bf97ed39681027d0c45aa45e3ea98f0</EPAYMENT>
but still i get same response on dashboard and 2Checkout cannot verif
my code:
const bodyParse = parse(req.body);
let date = new Date();
let updatedDate =
date.getFullYear().toString() +
pad2(date.getMonth() + 1) +
pad2(date.getDate()) +
pad2(date.getHours()) +
pad2(date.getMinutes()) +
pad2(date.getSeconds());
let hashToReturn = hmac(
`${bodyParse['IPN_PID[]'].length}${bodyParse['IPN_PID[]']}${bodyParse['IPN_PNAME[]'].length}${bodyParse['IPN_PNAME']}${bodyParse['IPN_DATE'].length}${bodyParse['IPN_DATE']}${updatedDate.length}${updatedDate}`
);
console.log('hashToReturn', hashToReturn);
res.send(`Verified OK! <EPAYMENT>${updatedDate}|${hashToReturn}</>`)
function hmac(stringToHash: string) {
const secretKey = process.env.checkoutSecret;
const hmac = crypto.createHmac('MD5', secretKey);
return hmac.update(stringToHash).digest('hex');
}
I cant figure it out what I'm missing or what is wrong i tried to contact 2Checkout support but they just replied with code samples from PHP and parts from documentation.
Related
I have been trying to follow this tutorial to use NodeJs with BigQuery, however, when I run the script I get the error Error: Unable to detect a Project Id in the current environment.
This is the full code following the tutorial:
const { BigQuery } = require('#google-cloud/bigquery');
async function queryStackOverflow() {
const bigqueryClient = new BigQuery();
const sqlQuery = `SELECT
CONCAT(
'https://stackoverflow.com/questions/',
CAST(id as STRING)) as url,
view_count
FROM \`bigquery-public-data.stackoverflow.posts_questions\`
WHERE tags like '%google-bigquery%'
ORDER BY view_count DESC
LIMIT 10`;
const options = {
query: sqlQuery,
location: 'US',
};
const [rows] = await bigqueryClient.query(options);
console.log('Query Results:');
rows.forEach(row => {
const url = row['url'];
const viewCount = row['view_count'];
console.log(`url: ${url}, ${viewCount} views`);
});
}
queryStackOverflow();
EDIT:
I wonder if I should create a project through BigQuery's UI & import the StackOverflow's dataset so the script can recognize the project's ID?
EDIT2:
I created a project & add the public dataset for StackOverflow, the logged through the Google CLI & still get the same error. Investing further...
I have solved my issue with the error by following the documentation on authorization here. I needed to log in to Google CLI. Then, create & download a json containing the credentials & set the env variable GOOGLE_APPLICATION_CREDENTIALS to the json's path.
I am trying to create an SAS Token to communicate with Azure API Management Rest API using JavaScript (Express.js). But using that actually leads me to a 401 Unauthorized. I am using the following lines of code.
// setting one day expiry time
const expiryDate = new Date(Date.now() + 1000 * 60 * 60 * 24)
const expiryString = expiryDate.toISOString()
const identifier = process.env.AZURE_APIM_IDENTIFIER
const key = process.env.AZURE_APIM_SECRET_KEY ?? ""
const stringToSign = `${identifier}\n${expiryString}`
const signature = CryptoJS.HmacSHA256(stringToSign, key)
const encodedSignature = CryptoJS.enc.Base64.stringify(signature)
// SAS Token
const sasToken = `SharedAccessSignature uid=${identifier}&ex=${expiryString}&sn=${encodedSignature}`
The above snippet returns me something like this:
SharedAccessSignature uid=integration&ex=2021-04-21T10:48:04.402Z&sn=**O8KZAh9zVHw6Dmb03t1xlhTnrmP1B6i+5lbhQWe**= (Some characters hidden for security, but number of characters is real)
Note that there is only one trailing dash = in the above mentioned SAS token, whereas SAS Tokens in all examples and manually created SAS Token from API Management Portal have 2 dashes ==
Is there anything I am doing wrong?
Thanks in advance.
According to the document of SAS token for Azure APIM, we can see the sample is c# code:
The difference between the sample and your code is the c# sample uses HMACSHA512 but your code use HMAS256. So I think you also need to use HMACSHA512 in your nodejs. You can do it like:
var hash = crypto.createHmac('sha512', key);
You may also need to do hash.update(text); and hash.digest(), please refer to this document about it.
Thank you Hury Shen! I also figured out that we don't need crypto-js for (as we have to import an external library for that). Node has crypto as its native module and we can use that. The following JavaScript snippet works fine.
import crypto from "crypto"
const identifier = <YOUR_AZURE_APIM_IDENTIFIER>
const secretKey = <YOUR_AZURE_APIM_SECRET_KEY>
// setting token expiry time
const expiryDate = new Date(Date.now() + 1000 * 60 * 60 * 24 * 29)
const expiryString = expiryDate.toISOString().slice(0, -1) + "0000Z"
const dataToSign = `${identifier}\n${expiryString}`
// create signature
const signedData = crypto
.createHmac("sha512", secretKey)
.update(dataToSign)
.digest("base64")
// SAS Token
const accessToken = `SharedAccessSignature uid=${identifier}&ex=${expiryString}&sn=${signedData}`
I am trying to create an HMAC signature in Postman using a pre-request script. Without going too far into the details of implementation,
I have confirmed that my means for generating the signature is messed up. I can see what the expected result should be with a proof of concept example but I’m missing something somewhere and cannot tell if it is in the conversion. I’ve read around from other questions on SO that binary is the default provided by cryptojs internally and that simply calling for the hash is the equivalent of asking for the digest with conversions completed for you. Here is the code I’m trying to run in postman and the working implementation code as shown in nodeJS.
var CryptoJS = require("crypto-js");
const d = new Date();
const timestamp = d.getTime();
const postData = {};
postData.nonce = 100; //timestamp * 1000; //nanosecond
postman.setEnvironmentVariable('nonce', postData.nonce);
const secret = CryptoJS.enc.Base64.parse(pm.environment.get("apiSecret"));
const path = pm.globals.get("balanceMethod");
const message = CryptoJS.SHA256( encodeURI(postData.nonce + postData)) ; // ...
const hmacDigest = CryptoJS.HmacSHA512(path + message, secret);
postman.setEnvironmentVariable('API-Signature', CryptoJS.enc.Base64.stringify(hmacDigest));
console.log(CryptoJS.enc.Base64.stringify(hmacDigest));
Does this apply to my situation in that I’d need to convert my sha256 message into a bytes array in order to work?
Reference code for building implementation that does work with nodeJS:
const getMessageSignature = (path, request, secret, nonce) => {
const message = qs.stringify(request);
const secret_buffer = new Buffer(secret, 'base64');
const hash = new crypto.createHash('sha256');
const hmac = new crypto.createHmac('sha512', secret_buffer);
const hash_digest = hash.update(nonce + message).digest('binary');
const hmac_digest = hmac.update(path + hash_digest, 'binary').digest('base64');
return hmac_digest;
};
Same reference code for building implementation in python3:
req['nonce'] = 100 #int(1000*time.time())
postdata = urllib.parse.urlencode(req)
# Unicode-objects must be encoded before hashing
encoded = (str(req['nonce']) + postdata).encode()
message = urlpath.encode() + hashlib.sha256(encoded).digest()
signature = hmac.new(base64.b64decode(self.secret),
message, hashlib.sha512)
sigdigest = base64.b64encode(signature.digest())
The only post data I'm sending is the Nonce at this time and I've purposely set it to 100 to be able to replicate the result to fix the generated signature. Seems close but not matching result. The python and nodeJS do match expected results and work properly.
Check out the answer in this thread. It helped me with the my problem and may be what is happening in your case also. All it is necessary is break the input of the HMAC into two parts.
I want to add a custom casting feature to my Google Home. What I've done so far was the tutorial using Dialogflow from this page: https://developers.google.com/actions/dialogflow/first-app
Then I found a repo about casting videos to Chromecast, only from PC and not from Google Home: https://github.com/googlecast/CastHelloVideo-chrome/blob/master/helloVideos.js
Then I tried combining the two. I've only tried to connect to my Chromecast so far, but I get this error every time:
API Version 2: Failed to parse JSON response string with 'INVALID_ARGUMENT' error: ": Cannot find field.".
I made the tutorial work, so I didn't change anything on Dialogflow, only the index.js file.
This is my file:
'use strict';
process.env.DEBUG = 'actions-on-google:*';
const App = require('actions-on-google').DialogflowApp;
const functions = require('firebase-functions');
// a. the action name from the make_name Dialogflow intent
const NAME_ACTION = 'game_cast';
// b. the parameters that are parsed from the make_name intent
const COLOR_ARGUMENT = 'color';
const NUMBER_ARGUMENT = 'number';
exports.gameCast = functions.https.onRequest((request, response) => {
const app = new App({request, response});
console.log('Request headers: ' + JSON.stringify(request.headers));
console.log('Request body: ' + JSON.stringify(request.body));
// c. The function that generates the silly name
function gameCast (app) {
let number = app.getArgument(NUMBER_ARGUMENT);
let color = app.getArgument(COLOR_ARGUMENT);
// app.tell('Alright, your silly name is ' +
// color + ' ' + number +
// '! I hope you like it. See you next time.');
launchApp();
}
// d. build an action map, which maps intent names to functions
let actionMap = new Map();
actionMap.set(NAME_ACTION, gameCast);
app.handleRequest(actionMap);
});
The launchApp() function call in the gameCast function would connect to my Chromecast. Additionally I added the whole content of helloVideos.js, so there wouldn't be any missing functions that launchApp() may uses. (I didn't include my original file here, as the file helloVideos.js has 617 lines of code.)
Any suggestions would be greatly appreciated! Thanks!
" Cannot find field" comes when your google action intent name is different from gamecast on the api.ai console.
You can goto google cloud back end https://console.cloud.google.com and check the logging error.
I've been searching for ways to restrict access to an API made for using a AWS Lambda function written on javascript.
I've found documentation on how to use AWS Signature S4, but I still do not understand it.
According to creating a signature, after applying the pseudocode I should get the signature to be placed on the header.
I've found the following code that addresses this point:
// Example of signature generator
var crypto = require("crypto-js");
function getSignatureKey(Crypto, key, dateStamp, regionName, serviceName) {
var kDate = Crypto.HmacSHA256(dateStamp, "AWS4" + key);
var kRegion = Crypto.HmacSHA256(regionName, kDate);
var kService = Crypto.HmacSHA256(serviceName, kRegion);
var kSigning = Crypto.HmacSHA256("aws4_request", kService);
return kSigning;
}
console.log(getSignatureKey(crypto,'secretkey','date','us-east-2','iam'));
Here comes my first question, I do not know what should be the output of getSignatureKey()? This is because on the documentation it is a very long string, while the output I got was {words:[x,x,x,x,x,x,x,x],sigBytes: 32},where the x are random numbers.
Moreover, after getting the signature and filling the header for the request with the "authorization" field and others, how do I filter unproper requests? Do I have to create a policy for the AWS API so it only allows signed requests? Here I guess I should follow Signing Requests.
Thanks!
Here is the simple implementation of Signed URL's. aws-cloudfront-sign package offers simpler implementation.
var cfsign = require('aws-cloudfront-sign');
var signingParams = {
keypairId: process.env.PUBLIC_KEY,
privateKeyString: process.env.PRIVATE_KEY,
// Optional - this can be used as an alternative to privateKeyString
privateKeyPath: '/path/to/private/key',
expireTime: 1426625464599
}
// Generating a signed URL
var signedUrl = cfsign.getSignedUrl(
'http://example.cloudfront.net/path/to/s3/object',
signingParams
);
https://aws.amazon.com/blogs/developer/creating-amazon-cloudfront-signed-urls-in-node-js/
Purpose of SignedURL is to serve Private Contents.
More details at,
http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/PrivateContent.html
Hope it helps.