AWS Lambda HTTPS post to Paypal IPN error - post

I have been trying to implement Paypal's IPN using AWS Api Gateway to get an IPN handler url. the api is integrated with a Lambda function as the "receiver".
I have tested the api gateway url using Paypal's IPN simulator.It works for the first step and I get this message "IPN was sent and the handshake was verified".
My problem is now with the next step,where I have to send the recived message back to Paypal using HTTPS post. I have tried a number of times and keep getting this error:
{
"code": "ECONNREFUSED",
"errno": "ECONNREFUSED",
"syscall": "connect",
"address": "127.0.0.1",
"port": 443
}
I really would appreciate some help in getting this to work.
I'm using node.js 8.10.Here's my Lambda function:
exports.handler = (event, context, callback) => {
console.log('Received event:', JSON.stringify(event, null, 2));
// Return 200 to caller
console.log('sending 200 back to paypal');
callback(null, {
statusCode: '200'
});
// Read the IPN message sent from PayPal and prepend 'cmd=_notify-validate'
console.log('modifying return body...');
var body = 'cmd=_notify-validate&' + event.body;
callHttps(body, context);};
function callHttps(body, context) {
console.log('in callHttp()....');
var https = require('https');
var options = {
url: 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr',
method: 'POST',
headers: {
"user-agent": "Nodejs-IPN-VerificationScript"
},
body: body
};
const req = https.request(options, (res) => {
res.on('data', (chunk) => {
// code to execute
console.log("on data - can execute code here....");
});
res.on('end', () => {
// code to execute
console.log("on end - can execute code here....");
});
});
req.on('error', (e) => {
console.log("Error has occured: ", JSON.stringify(e, null, 2));
});
req.end();}

managed to sort it out.i was using url instead of breaking it down to host and path.here's the full code that worked for me:
exports.handler = (event, context, callback) => {
console.log('Received event:', JSON.stringify(event, null, 2));
// Return 200 to caller
console.log('sending 200 back to paypal');
callback(null, {
statusCode: '200'
});
callHttps(event.body, context);};
function callHttps(body, context) {
console.log('in callHttp()....');
// Read the IPN message sent from PayPal and prepend 'cmd=_notify-validate'
console.log('modifying return body...');
var bodyModified = 'cmd=_notify-validate&' + body;
var https = require('https');
var options = {
host: "ipnpb.sandbox.paypal.com",
path: "/cgi-bin/webscr",
method: 'POST',
headers: {
'user-agent': 'Nodejs-IPN-VerificationScript',
'Content-Length': bodyModified.length,
}
};
const req = https.request(options, (res) => {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
var result = '';
res.on('data', (d) => {
// get the result here
result += d;
});
res.on('end', (end) => {
// check the result
if (result === 'VERIFIED') {
// process the message
// split the message
var res = body.split("&");
// create an object
var paypalMessageObject = new Object();
// loop through split array
res.forEach(element => {
// split element
var temp = (element.toString()).split("=");
// add to the object
paypalMessageObject[temp[0]] = temp[1];
});
console.log('paypalMessageObject: ' + JSON.stringify(paypalMessageObject, null, 2));
var checkItems = {
payment_status: paypalMessageObject.payment_status,
mc_gross: paypalMessageObject.mc_gross,
mc_currency: paypalMessageObject.mc_currency,
txn_id: paypalMessageObject.txn_id,
receiver_email: paypalMessageObject.receiver_email,
item_number: paypalMessageObject.item_number,
item_name: paypalMessageObject.item_name
};
console.log('checkItems: ', JSON.stringify(checkItems, null, 2));
}
else { console.log('not verified, now what?'); }
});
});
req.on('error', (e) => {
console.log("Error has occured: ", JSON.stringify(e, null, 2));
});
req.write(bodyModified);
req.end();}

Related

How to send parallel POST requests in puppeteer?

I want to send parallel POST requests in puppeteer. I have to change the payload with every request (URL remains the same).
I tried using puppeteer cluster, but how do I change payload with every request when I queue the same request?
Using normal puppeteer
(async() => {
const browser = await puppeteer.launch({
args: [
"--no-sandbox",
"--disable-setuid-sandbox",
"--disable-web-security",
],
executablePath: 'C:/Program Files/..',
headless: false,
});
for(const id of Ids) {
const page = await browser.newPage();
await page.setDefaultNavigationTimeout(60000);
await page.evaluateOnNewDocument(() => {
// Some code
})
await page.setRequestInterception(true);
// Request intercept handler... will be triggered with
// each page.goto() statement
page.on('request', interceptedRequest => {
// Here, is where you change the request method and
// add your post data
var data = {
'method': 'POST',
'postData': JSON.stringify({
....
"similarMaterialId": `${id}`,
}),
'headers': {
.....
},
};
// Request modified... finish sending!
interceptedRequest.continue(data);
});
const response = await page.goto('https://.../getProductInfo');
const responseBody = await response.json();
try {
let title = responseBody.description;
let price = responseBody.price;
fs.appendFile('temp.tsv', `${title}\t${price}\n`, function (err) {
if (err) throw err;
})
}
catch {
console.log(id)
}
await page.close();
}
console.log("Code ended!!")
await browser.close();
})();
I want to create many pages in parallel on a single browser.

How to get link to composition by using status callbacks twilio

Here is what I tried but it's not working.
This guy is responsible for creating a composition after the meeting is ended.
app.post('/api/endMeeting', (req, res) => {
const roomSid = req.body.roomSid;
userEmail = req.body.userEmail;
const client = require('twilio')(config.twilio.apiKey, config.twilio.apiSecret, {accountSid: config.twilio.accountSid});
client.video.rooms(roomSid).update({ status: 'completed' });
client.video.compositions.create({
roomSid: roomSid,
audioSources: '*',
videoLayout: {
grid : {
video_sources: ['*']
}
},
statusCallback: `${process.env.REACT_APP_BASE_URL}/api/getMeeting`,
statusCallbackMethod: 'POST',
format: 'mp4'
}).then(() => {
// sendRecordingEmail(composition.sid, userEmail);
res.status(200).send({
message: 'success'
});
}).catch(err => {
res.status(500).send({
message: err.message
});
});
});
And this guy will send the download link of the composition to the participant when it's available.
app.post('/api/getMeeting', (req, res) => {
if (req.query.StatusCallbackEvent === 'composition-available') {
const client = require('twilio')(config.twilio.apiKey, config.twilio.apiSecret, {accountSid: config.twilio.accountSid});
const compositionSid = req.query.CompositionSid;
const uri = "https://video.twilio.com/v1/Compositions/" + compositionSid + "/Media?Ttl=3600";
client.request({
method: "GET",
uri: uri,
}).then((response) => {
const requestUrl = request(response.data.redirect_to);
sendRecordingEmail(requestUrl, userEmail);
res.status(200).send("success");
}).catch((error) => {
res.status(500).send("Error fetching /Media resource " + error);
});
}
});
I can confirm that the composition is created exactly in the Twilio console.
But it seems the status callback guy is not working and I can see the below issue.
It seems I made mistakes in using the status callback.
Please let me know what is the problem and how I can solve this.
Thank you.
Thank you very much for #philnash's help in solving this problem.👍
I solved the above issue and I can get the download link of the composition for now.
The problem was in the status callback function and I should use req.body instead of req.query because of the status callback method. (It's POST on my code.)
Here is the code that is fixed.
app.post('/api/getMeeting', (req, res) => {
if (req.body.StatusCallbackEvent === 'composition-available') {
const client = require('twilio')(config.twilio.apiKey, config.twilio.apiSecret, {accountSid: config.twilio.accountSid});
const compositionSid = req.body.CompositionSid;
const uri = "https://video.twilio.com/v1/Compositions/" + compositionSid + "/Media?Ttl=3600";
client.request({
method: "GET",
uri: uri,
}).then((response) => {
const requestUrl = response.body.redirect_to; // Getting the redirect link that user can download composition
sendRecordingEmail(requestUrl, userEmail); // Send URL via email to the user
res.status(200).send("success");
}).catch((error) => {
res.status(500).send("Error fetching /Media resource " + error);
});
} else {
res.status(204).send('compositioin is not available');
}
});

Twilio Function Calling Studio Rest API - Accountsid in correct error

I am calling a Twilio Studio Flow Rest API from a Twilio function.
Following is the function code:
exports.handler = function(context, event, callback) {
const request = require('request');
to = event.to;
to = to.replace(/[()-.]/g, '');
to = to.replace(/ /g, '');
var postoptions = {
headers: {'AC' : 'b1xx'},
url: 'https://studio.twilio.com/v1/Flows/FWxxx8/Executions',
method: 'POST',
data: { 'from': '+1814xxx',
'to': to
}
};
request(postoptions, function(error, response, body){
callback(null, response);
});
};
The function keeps saying the Account SID adn auth token are incorrect. However sid and token are correct.
What I am missing?
You'll need to "base64" encode the Account SID and auth token when you pass them in headers.
Try something like this:
exports.handler = function (context, event, callback) {
const request = require('request');
to = event.to;
to = to.replace(/[()-.]/g, '');
to = to.replace(/ /g, '');
var username = "AC";
var password = "b1xx";
var auth = "Basic " + new Buffer(username + ":" + password).toString("base64");
var postoptions = {
headers: { 'Authorization': auth },
url: 'https://studio.twilio.com/v1/Flows/FWxxx8/Executions',
method: 'POST',
data: {
'from': '+1814xxx',
'to': to
}
};
request(postoptions, function (error, response, body) {
callback(null, response);
});
};

Microsoft Graph sendMail doesn't work and returns NULL

I'm trying to send e-mails with MS Graph 1.0 and I have not any get any result or response. E-Mails haven't been sent and sendMail method don't return any error o message... it only says "null".
My code is based on this example https://github.com/microsoftgraph/msgraph-sdk-javascript#post-and-patch and looks like this:
// Initialize Graph client
const client = graph.Client.init({
authProvider: (done) => {
done(null, accessToken);
}
});
try {
// construct the email object
var mail = {
subject: "Microsoft Graph JavaScript Sample",
toRecipients: [{
emailAddress: {
address: "mail#domain.com"
}
}],
body: {
content: "<h1>MicrosoftGraph JavaScript Sample</h1>Check out https://github.com/microsoftgraph/msgraph-sdk-javascript",
contentType: "html"
}
};
client
.api('/me/sendMail')
.post({message: mail}, (err, res) => {
console.log("---> " + res);
});
console.log("Try ends");
} catch (err) {
parms.message = 'Error retrieving messages';
parms.error = { status: `${err.code}: ${err.message}` };
parms.debug = JSON.stringify(err.body, null, 2);
res.render('error', parms);
}
I guess mail var needs a header, but anyway, API should return me something, right? And, obviously, which is the problem with the email sending?
I finally added rawResponse to .post call and look at err log...
client
.api('/me/sendMail')
.header("Content-type", "application/json")
.post({message: mail}, (err, res, rawResponse) => {
console.log(rawResponse);
console.log(err);
});
... and I could see that I had problem with my authentication token. So, I was using the api correctly and code from the question is ok.

MS Graph Sample Application Integration Test not Working

I want to do what the MS Graph sample node app is doing in its integrationTests.js, but that test doesn't work. Here's what I've tried:
Followed the quick start for creating a node.js app.
Ran the app. Ensured it worked by sending an e-mail.
Modified the test Checking that the sample can send an email to use my account parameters.
Tried to run the test. It fails with 403: insufficient scope. The call to get the token returned scopes, but lacked Mail.Send.
In the post data for the call to login.microsoftonline.com, I added "scope: 'Mail.Send'"
I still receive a valid token, and the return scope includes Mail.Send, but when I try to post with that token, I get 400: cannot POST /beta/me/sendMail
I tried adding scope (Mail.Send) in the query string and as a header (thought I saw that somewhere), but it made no difference.
I added the Mail.Send permission (under "Application Permissions") for the app in the application registration portal.
I compared the token (using https://jwt.ms) from my test call to the call from the app when it works. I see no real difference. They both contain the Mail.Send scope.
Here is the code (which is only slightly different from what's in the sample):
// in graphHelper.js
function postSendMail(accessToken, message, callback) {
request
.post('https://graph.microsoft.com/beta/me/sendMail')
//.post('https://graph.microsoft.com/beta/me/sendMail?scope=Mail.Send') // nope
.send(message)
.set('Authorization', 'Bearer ' + accessToken)
.set('Content-Type', 'application/json')
.set('Content-Length', message.length)
.set('scope', 'Mail.Send') // nope
.end((err, res) => {
callback(err, res);
});
}
describe('Integration', function () { // mocha
var accessToken;
var scope;
const config = getConfig();
// My account variables in testConfig.json file
function getConfig() {
var configFilePath = path.join(__dirname, 'testConfig.json');
return JSON.parse(fs.readFileSync(configFilePath, { encoding: 'utf8' }));
}
function getAccessToken(done) {
var postData = querystring.stringify(
{
grant_type: 'password',
//grant_type: 'client_id', // not supported
//grant_type: 'authorization_code', // This assumes you've requested an auth code.
resource: 'https://graph.microsoft.com/',
scope: 'Mail.Send',
client_id: config.test_client_id_v2,
client_secret: config.test_client_secret_v2,
username: config.test_username,
password: config.test_password
}
);
var postOptions = {
host: 'login.microsoftonline.com',
port: 443,
path: '/common/oauth2/token',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(postData)
}
};
var postRequest = https.request(postOptions, function (res) {
var data = '';
res.setEncoding('utf8');
res.on('data', function (chunk) {
data += chunk;
});
res.on('end', function () {
const response = JSON.parse(data);
accessToken = response.access_token;
scope = response.scope;
done();
});
});
postRequest.on('error', function (e) {
console.log('Error: ' + e.message);
done(e);
});
postRequest.write(postData);
postRequest.end();
}
before( // eslint-disable-line no-undef
function (done) {
getAccessToken(done);
}
);
it('Checking that the sample can send an email',
function (done) {
var postBody = emailer.generateMailBody(config.test_name, config.test_username);
graphHelper.postSendMail(
accessToken, scope,
JSON.stringify(postBody),
function (error) {
assert(error === null, `The sample failed to send an email: ${error}`);
done();
});
}
);
});

Resources