How to confirm subscribe and get SNS Notifications at a HTTP endpoint? - node.js

I'm using Amazon Elastic Beanstalk to run a nodejs web page. I just want to send notifications to this webpage from AWS SNS and catch them in real time. So, when i publish to the HTTP endpoint, nothing happens and i don't know how to get the notification.
As Http endpoint, i set my AWS Elastic-Beanstalk http address.
I'm reading the Amazon docs but nowhere i can find how to catch the sns message once at the http endpoint.
Please, any help will be very appreciated . Thanks.

Try this:
const express = require('express');
const router = express.Router();
const request = require('request');
var bodyParser = require('body-parser')
router.post('/',bodyParser.text(),handleSNSMessage);
module.exports = router;
var handleSubscriptionResponse = function (error, response) {
if (!error && response.statusCode == 200) {
console.log('Yess! We have accepted the confirmation from AWS');
}
else {
throw new Error(`Unable to subscribe to given URL`);
//console.error(error)
}
}
async function handleSNSMessage(req, resp, next) {
try {
let payloadStr = req.body
payload = JSON.parse(payloadStr)
console.log(JSON.stringify(payload))
if (req.header('x-amz-sns-message-type') === 'SubscriptionConfirmation') {
const url = payload.SubscribeURL;
await request(url, handleSubscriptionResponse)
} else if (req.header('x-amz-sns-message-type') === 'Notification') {
console.log(payload)
//process data here
} else {
throw new Error(`Invalid message type ${payload.Type}`);
}
} catch (err) {
console.error(err)
resp.status(500).send('Oops')
}
resp.send('Ok')
}
Note: I didn't use app.use as that will impact all my other endpoints.

The moment you give your HTTP/HTTPS endpoint and create subscription from aws console, what happens is , the Amazon sends a subscription msg to that endpoint. Now this is a rest call, and your app must have a handler for this endpoint, otherwise you miss catching this subscription message. The httpRequest object that your handler is passed, needs to access it's SNSMsgTypeHdr header field. This value will be "SubscriptionConfirmation". You need to catch this particular message first and then get the subscription url. You can handle it in your app itself or maybe print it out, and then manually visit that url to make the subscription. I would ideally suggest to make a subscription to the same topic at the same with your mail id, so that everytime your app gets a messages pushed , your mail id also gets the message(albeit the tokens will be different) but at least you will be sure that the message was pushed to your endpoint. All you need to do is keep working your app to handle the messages at that endpoint as per your requirements then.

There are 3 types of messages with SNS. Subscribe, Unsubscribe, and Notification. You will not get any Notification messages until you have correctly handled the subscribe message. Which involves making an API request to AWS when you receive the Subscribe request.
The call in this case is ConfirmSubscription: http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SNS.html#confirmSubscription-property
Once you do that, then you will start receiving notification messages and you can handle those as your code allows.

After you subscribe your endpoint, Amazon SNS will send a subscription confirmation message to the endpoint.
You should have code at the endpoint that retrieves the SubscribeURL value from the subscription confirmation message and either visit the location specified by SubscribeURL itself or make it available to you so that you can manually visit the SubscribeURL, for example, using a web browser.
Amazon SNS will not send messages to the endpoint until the subscription has been confirmed.
You can use the Amazon SNS console to verify that the subscription is confirmed: The Subscription ID will display the ARN for the subscription instead of the PendingConfirmation value that you saw when you first added the subscription.

Related

Botkit Slackbot responds with 401 error every time

I'm trying to create a very simple Slack bot using botkit and Google App Engine, but for some reason I keep getting 401 errors any time I message the bot. The weird thing is that the Slack Event Subscription URL (the one ending in /api/messages) validates correctly, and I get a 200 response in GAE logs and validation within Slack.
But whenever I actually message the bot it always gets a 401 error with no message explaining the error at all. I've tried various combinations of the code below, and have now stripped it down to the bare minimum as found here. Aside from dependencies and a code to decrypt credentials (which I've verified is working as expected), this is my full code at the moment:
botInit();
async function botInit () {
const credentialsRaw = await getCredentials();
const credentials = JSON.parse(credentialsRaw);
const adapter = new SlackAdapter(credentials);
const controller = new Botkit({
adapter: adapter
});
controller.on('message', async(bot, message) => {
await bot.reply(message, 'I heard a message!');
});
}
I have also tried this for the messaging function:
controller.ready(() => {
controller.hears(['hello', 'hi'], ['message', 'direct_message'],
async (bot, message) => {
await bot.reply(message, 'Meow. :smile_cat:')
})
})
and this for setting up the controller:
const controller = new Botkit({
webhook_uri: '/api/messages',
adapter: adapter
});
And everything gives back the same exact 401 error, despite all of them working with the Event Subscription URL verification on Slack.
I had same issue but figured out the problem.
I had been using Client Secret as clientSigningSecret
But I should use Signing Secret !

How to avoid to exceed rate-limit by using discord.js api?

I am trying to understand how the discord API works. Especially the rate limit policy. By reading the docs . I need to implement a logic that track the rate of invalid request that it sent as a response header when I do my requests. However, when I do it (the request) using postman, the response headers don't include the rate-limit info as showed in this part of the docs . Hence, I don't know how to handle this issue.
So I have two questions :
How to get rate-limit headers in the response ?
How to implement the logic in my code to prevent my backend to send a request if the limit has been reached and set a timeout before the next try in order to avoid my IP to be banned by discord ?
A sample of my expressjs code :
const addnew = async (req, res) => {
try {
const { memberId, guildId, type, value, embed } = req.body;
res
.status(400)
.send({ error: "error" });
return;
await client.addnew(memberId, guildId, type, value, embed);
res.status(200).send(req.body);
} catch (err) {
console.log(err);
res.status(500).send(err);
}
};
Discord.js has logic that takes care of the rate limit issue for you. If you monitor the Client#rateLimit event, you can see that if you make too many API requests within your code, the event will trigger. This means that your requests have been enqueued and Discord.js will send them once your rate limit duration has been exceeded.

Indicating a WhatsApp message is received, via the Twilio API, in NodeJS?

We are creating a service that will receive WhatsApp messages via the Twilio service. This works, but our issue is that we can't work out how to tell the sender that our server has 'read' the message. The messages always appear as being 'delivered' and never 'read', even after responding to the message. We have looked in the documentation, but can't seem to see how to do this.
Our server is written in NodeJS and is using Express for HTTP side.
Below is an equivalent of the code we are using (not a running example):
import { twiml } from 'twilio';
const { MessagingResponse } = twiml;
async receiveMessage(req: Request, res: Response, next: NextFunction) {
const message = req.body;
// Send back an empty response, we will process asynchronously
const immediateResponse = new MessagingResponse();
res.setHeader('content-type', 'text/xml');
res.send(immediateResponse.toString());
// TODO indicate message as read
// Do what ever logic is needed for given message
const replyMessage = await processMessage(message);
const messageToTwilio = {
body: replyMessage,
from: message.To,
to: message.From
};
const twilioResponse = await this.client.messages.create(messageToTwilio);
// Record value of twilioResponse in DB
}
Can anyone suggest what in the API I should be using for this?
I contacted Twilio on this issue and it turns out this is not currently possible. While they consider this a useful functionality, it is not currently a priority for implementation.
Note, It is possible to get the delivery status of outgoing messages, via the status webhook, but it is not possible to indicate to the remote party that the incoming message was 'read'.

AWS Alexa Skill Freeze/Thaw

I have an Alexa Skill that should make a PATCH Request to my Database to change a field for the current user. When I trigger the intent in the alexa developer console, alexa sometimes replies "There was a problem with the requested skill's response" and the PATCH request goes through successfully. Other times Alexa responds "Ok, we will upgrade your number.", however in this case the http PATCH request doesn't go through. I think this has something to do with the "Freeze/Thaw" Cycle (https://aws.amazon.com/blogs/compute/container-reuse-in-lambda/) but I am not sure. When I check the device logs in the developer console it just says:
An error occurred while issuing a SpeechletRequest for (requestId [amzn1.echo-api.request......]
All other http requests work completely fine.
'upgrade': async function () {
const token = this.event.context.System.user.accessToken;
var uniqueId = String(token);
let upgradeNumber = buildPostData(10);
this.emit(':tell','Ok, we will upgrade your number.');
try {
await postData(uniqueId,upgradeNumber);
}
catch (err) {
console.log(err);
return err;
}
},

Attach messagingServiceSid to a twiml response in nodejs library

I have a webhook setup, and I am able to receive messages and reply to them. I would like to have the responses sent by my webhook to have messagingServiceSid attached to them.
I didn't find on documentation a way to configure that for responses from my webhook, only for new SMS using
client.sendMessage({
messagingServiceSid: 'MG9752274e9e519418a7406176694466fa',
to: '+16518675309',
body: 'Phantom Menace was clearly the best of the prequel trilogy.'
}, function(err, message) {
console.log(message);
});
Is there something similar for this code? Is it doable through the UI?
app.post('/foo/bar/sms', twilio.webhook({
host:'gassy-ocelot-129.herokuapp.com',
protocol:'https'
}), function(request, response) {
var twiml = new twilio.TwimlResponse();
twiml.message('This HTTP request came from Twilio!');
response.send(twiml);
});
Images:
No messagingService on reply messages sent using twiml response
Message Detail view from logs
Twilio developer evangelist here.
As far as I'm aware, there's no way to reply to message from a message service with TwiML.
However, rather than using TwiML, you could just send the SMS back to your user from the REST API and return an empty <Response> to the incoming webhook. Something a bit like this:
app.post('/foo/bar/sms', twilio.webhook({
host:'gassy-ocelot-129.herokuapp.com',
protocol:'https'
}), function(request, response) {
// send the message from the message service
client.sendMessage({
messagingServiceSid: 'MG9752274e9e519418a7406176694466fa',
to: request.body.From,
body: 'Your message'
}, function(err, message) {
console.log(message);
});
// send empty TwiML response
var twiml = new twilio.TwimlResponse();
response.send(twiml);
})
Let me know if that helps at all.
If you receive an incoming SMS on a phone number currently set up to that Messaging Service (via the web ui or phone number REST), then the incoming requests will have MessagingServiceSid in the query string.

Resources