Send POST parameters to Voice URL for incoming calls with Twilio - javascript

I'm allowing my site to accept incoming calls with python and javascript. I want to make sure that whoever answers the call has their username logged correctly by Twilio. As posted in their docs you need to create a capability token to accept incoming calls:
capability.allow_client_outgoing(application_sid)
capability.allow_client_incoming("jenny")
There could be up to 20 different users on the site at once that could answer the call so I would want the "jenny" string to be replaced to allow a dynamic username based upon who is logged in.
I'm using Django as my framework and generate the token through a view that request the username from request.user.username
def token(request):
capability = TwilioCapability(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN)
capability.allow_client_outgoing(APP_ID)
capability.allow_client_incoming(request.user.username)
token = capability.generate()
data = json.dumps({'token': token})
return HttpResponse(data, content_type='application/json')
My Twilio Voice URL gets directed to this function. If it does not see a phone_number parameter then it can assume it is a incoming call. I somehow want to send the 'call_rep' parameter through this post which will match up the usernames to allow the incoming call with the correct user information:
#twilio_view
def make_call(request):
resp = Response()
if 'phone_number' in request.POST:
phone_number = request.POST['phone_number']
resp.say("Making the call now")
resp.dial(number=phone_number, callerId=TWILIO_PHONE_NUMBER)
else:
resp.say("Incoming call")
with resp.dial(callerId=TWILIO_PHONE_NUMBER) as r:
r.client(request.POST['call_rep'])
return resp
Is there somewhere in my JavaScript I need to put the call_rep's username in?
Twilio.Device.setup(token);
Twilio.Device.ready(function (device) {
});
Twilio.Device.error(function (error) {
console.log(error);
$("#log").text("Error: " + error.message);
});
Twilio.Device.offline(function(device) {
// Called on network connection lost.
});
Twilio.Device.connect(function (conn) {
console.log("Successfully established call");
});
Twilio.Device.disconnect(function (conn) {
// Called for all disconnections
console.log('DISCONNECT: ' + conn.status);
});
/* Listen for incoming connections */
Twilio.Device.incoming(function (conn) {
connection = conn
connection.accept()
});
For outgoing calls I can pass extra parameters no problems. How do I do this with incoming?
Twilio.Device.connect({
call_rep: '{{ request.user.username }}',
phone_number: phone_number
});

Related

Twilio in nodejs is giving "To: undefined error" and is not able to understand data from front end

I just started using Twilio services and there have been a few challenges. The phone number I send from the front end, I'm not able to make out if its actually being sent to the backend route. Whenever the GET request is done, it throws an error
": Required parameter "opts['to']" missing. twilio".
The first error is what I am getting now.
My form sends this to the backend:
case 2:
const Phoneno = {
phone:countryCode+PhoneNumber
};
axios.post('http://localhost:4000/app/otp', { data :Phoneno });
console.log(Phoneno)
my route for sending otp:
router.post('/otp', async(req, res)=>{
client.verify.v2.services("VERIFY_SERVICE_SID")
.verifications
.create({to:req.body.phone, channel: 'sms'})
.then((verification) => {
console.log(verification.status);
return callback(null);
}).catch((e) => {
console.log(e);
return callback(e);
});
});
In that console.log, I get this,
"{phone: '+91**********'}
phone: "+91**********"(my actual number)
[[Prototype]]: Object"
Also, when I hardcode the phone number, the route works perfectly fine. And when i send an HTTP request to the route, then also it sends an otp to my phone number. But is not able to recognize the data sent from the frontend.
My http request:
POST http://localhost:4000/app/otp
Content-Type: application/json
{
"Phoneno":"+9199********"
}
Please help me out. Thanks a lot for looking into it.
You are making a GET request to your back-end, but you are trying to get the data from the request body. GET requests do not have a body.
You're also trying to send the data by passing it in an object as the second argument to axios.get, but that argument should be a config object. To send the data in the query for the GET request it should be under the params key for that object:
const Phoneno = {
phone:countryCode+PhoneNumber
};
axios.get('http://localhost:4000/app/otp', { params: Phoneno });
Then on the back-end, read the data from the query, using req.query.phone:
router.get('/otp', async(req, res)=>{
client.verify.v2.services(VERIFY_SERVICE_SID)
.verifications
.create({to:req.query.phone, channel: 'sms'})
.then((verification) => {
console.log(verification.status);
return callback(null);
}).catch((e) => {
console.log(e);
return callback(e);
});
However, this might not be a good idea because an attacker can easily create a URL to your site and add the phone number in the query parameters and use it to perform SMS pumping.
I'd actually recommend you change your back-end to a POST request and send the data from the front end in a POST request with the data in the body of the request:
const Phoneno = {
phone:countryCode+PhoneNumber
};
axios.post('http://localhost:4000/app/otp', { data: Phoneno });
router.post('/otp', async(req, res)=>{
client.verify.v2.services(VERIFY_SERVICE_SID)
.verifications
.create({to:req.body.data.phone, channel: 'sms'})
.then((verification) => {
console.log(verification.status);
return callback(null);
}).catch((e) => {
console.log(e);
return callback(e);
});

Are there any public API (s) that I could use to verify an activation code?

I am trying to create a product verification system, and I have the login part down. My question is how are there any API (s) that can verify something like an activation code and return if it succeeded or not.
Btw, you might have to scroll horizontally to see all of the code
//How would I add a verification system
document.getElementById('redeemButton').addEventListener('click', () => {
var code = document.getElementById('redeemCodeBox').value;
var product = document.getElementById('productCode').value;
const fetchPromise = fetch(`https://www.mywebsite.com/api/redeem?product=${product}&code=${code}`);
fetchPromise.then( response => {
if (!response.ok) {
throw new Error(`HTTP error: ${response.status}`);
}
return response.json();
})
.then( json => {
console.log(json[0].name);
})
.catch( error => {
console.error(`Could not get products: ${error}`);
throw `Please Enter a Valid Activation Code`;
});
});
I don't think you should be dependent on a third party to verify an Activation Code.
You should use a combination of JWT token + activation code that you store in the database.
Generate an activation code.
Generate JWT token.
const token = await this.jwtService.sign(
{
usetId: userId
},
{ expiresIn: "1d" }
);
Save the activation code and the JWT token to the database.
Send an E-mail or SMS with an activation code to the user. + include URL where user can insert the activation code.
URL can look something like this:
https://www.mywebsite.com/api/activation?token=eyJhbGciOiJIfasdfas
(use query parameter for JWT token =>> ?token=JWT_token
Verify JWT token from URL (value from query parameter "token") and validate if Token is not expired.
Control if user input matches an Activation code stored in your database.
Activated

Angular2: PUT request to Node-Server doesn't work - authentication lost

I'm using Angular2 on the client side and a node-express server as my backend. The node-server works as an API-middleware and also as my authentication service. The user-requests must contain a valid JWT token to perform requests on the node-server.
All of my GET functions and other PUT functions are working properly. I wrote a new one, which just should delete an ID on a third-party API, doesn't.
Furthermore, my node-express server sends custom error messages at some points to the client. This comes to my problem, whenever I run my latest PUT-function, my server responds with "No token provided". This happens when the user isn't logged in on the client side.
As I said, all my other functions working. this.createAuthenticationHeaders(); is necessary to perform valid request on the server side. But it's implemented.
In other words, the authentication gets lost between client and server and I get my own error message: "No token provided".
Appointment-Detail.Component.ts
cancelAppointment() {
this.authService.getProfile().subscribe(profile => {
this.username = profile.user.username; // Set username
this.email = profile.user.email; // Set e-mail
if (profile.user.email) {
this.apiService.cancelUserAppointment(this.id).subscribe(data => {
console.log(this.id);
if (!data.success) {
this.messageClass = 'alert alert-danger'; // Set error bootstrap class
this.message = data.message; // Set error message
} else {
this.messageClass = 'alert alert-success'; // Set success bootstrap class
this.message = data.message; // Set success message
// After two seconds, navigate back to blog page
}
});
}
});
}
API Service
cancelUserAppointment(id) {
this.createAuthenticationHeaders();
console.log('API SERVICE ' + id);
return this.http
.put(this.domain + 'api/appointments/' + id + '/cancel', this.options)
.map(res => res.json());
}
An API Service functions that works
getCertificatesByUser(email) {
this.createAuthenticationHeaders();
return this.http
.get(this.domain + 'api/user/' + email + '/certificates', this.options)
.map(res => res.json());
}
Server route to the third party API
router.put('/appointments/:id/cancel', (req, res) => {
console.log('hi');
var id = req.params.id;
const url = process.env.acuityUri + '/appointments/' + id + '/cancel';
console.log(id);
});
Authentication middleware
router.use((req, res, next) => {
const token = req.headers['authorization']; // Create token found in headers
// Check if token was found in headers
if (!token) {
res.json({
success: false,
message: 'No token provided'
}); // Return error
} else {
// Verify the token is valid
jwt.verify(token, config.secret, (err, decoded) => {
// Check if error is expired or invalid
if (err) {
res.json({
success: false,
message: 'Token invalid: ' + err
}); // Return error for token validation
} else {
req.decoded = decoded; // Create global variable to use in any request beyond
next(); // Exit middleware
}
});
}
});
Without doing too much of a deep dive into your auth headers, I see a pretty glaring issue that I think may be the cause of your troubles.
HTTP REST verbs carry different "intents", the intent we specifically care about in this case is wether or not your request should have a body.
GET requests do not carry a body with them.
PUT requests do carry a body.
Because of this, angular's HttpClient request methods (http.get, http.post, etc.) have different method signatures.
To cut to the chase, http.put's method signature accepts 3 parameters: url, body, and options, whereas http.get's method signature only accepts 2: url and options.
If you look at your example, for http.put you are providing this.httpOptions as the second parameter instead of the third, so Angular is packaging up your options object as the PUT request body. This is why you have a working example and a non-working example; the working example is a GET!
The solution? Simply put something else as the request body in the second parameter and shift this.options down to the third parameter slot. If you don't care what it is, just use the empty object: {}.
So your request should look like this:
return this.http
.put(this.domain + 'api/appointments/' + id + '/cancel', {}, this.options)
At the very least, this should send whatever is in this.options to the server correctly. Now wether what's in this.options is correct or not is another story.
Example PUT call from Angular's docs: https://angular.io/guide/http#making-a-put-request

How to Render HTTP Post Request result to pug?

When a user clicks on the form, I send a http post request to database server. Which in turn sends post request back to user server.
My problem is that I can't post this database result recieved from database server to pug. I am not sure how to implement AJAX here.
I have tried sending the server http request itself, doesn't work. I have also tried to render the results to the pug file in the code as well, not luck!
script.js:
// analyze sentiment button
function analyzeSentiment() {
// get and post filter to the backend for sentiment score
let form = $("#searchSentiment-form");
let query = form.serialize();
console.log(query);
$.post('/', query);
}
pug file
form#searchSentiment-form(action='javascript:analyzeSentiment()', method='POST')
input(type="text" id="sentimentFilter" name="sentimentFilter" placeholder="Search a filter" required)
button(type="submit" id="sentiAnalysis" name="sentiAnalysis") ANALYZE
index.js
if(req.body.sentimentFilter) {
// 1) Convert Tweet into JSON
tweetJSON = { sentimentFilter: req.body.sentimentFilter };
console.log("Analyze this:", tweetJSON)
// 2) Send via HTTP post request to the ANALYSIS-SERVER
request({
url: "http://LoadBalancer-1284897978.us-west-2.elb.amazonaws.com",
method: "POST",
json: true, // <--Very important!!!
body: tweetJSON
}, function (error, response, body){
if(error) {
console.log("HTTP POST: Sending tweets to analysis-server Failed", error);
} else {
console.log("Success! Send sentiment request to analysis-server");
}
});
// receiving post result from server with results
} else if (req.body.score) {
let score = req.body.score;
res.render('index', {score:score});
let JSONscore = { userScore: score};
// 2) Send via HTTP post request to the LOAD-BALANCER FOR TWITTER-SERVER
request({
url: "http://52.26.216.28:3000",
method: "GET",
json: true,
body: JSONscore
}, function (error, response, body){
if(error) {
console.log("ERROR: COULD NOT SEND SCORE TO OWN USER-SERVER...", error);
} else {
console.log("SUCCESSFULY SENT SCORE TO OWN USER!..");
}
});
console.log("Received Score is ", req.body.score);
}
Your question states that you send the request to the database server which then sends the request to the node.js server, this is not correct. The user sends the request to the node.js server, which then creates a new request to the database server. When the response is received by the node.js server in the callback, at that time you want to send the final response back to the client.
If you want to do this in the client without reloading the template then you need to:
Only send JSON in the response,
Handle the response with jquery, and then
Update the DOM using jquery
First, only send JSON. None of the two callbacks are sending a response back to the client, that's a really big problem and it will look like your server is hanging.
This is how to return the response from the database to the client in your first callback. Expressjs has a shortcut method on the response (res) object that cleanly and quickly sends a JSON payload back properly:
function (error, response, body){
if(error) {
console.log("HTTP POST: Sending tweets to analysis-server Failed", error);
} else {
console.log("Success! Send sentiment request to analysis-server");
res.json(response);
}
}
Make sure you have that in all callbacks, then let's move on to the second issue in your code, handling the Ajax response.
Here is the relevant part of the sample code from the jquery $.post docs:
// Assign handlers immediately after making the request,
// and remember the jqxhr object for this request
var jqxhr = $.post( "example.php", function() {
alert( "success" );
})
.done(function() {
alert( "second success" );
})
.fail(function() {
alert( "error" );
});
You'll want to add the .done and .fail functions to your ajax code so you have something listening for that response from the server.
Finally, you'll probably want to show the user the result, so add a div to your pug:
form#searchSentiment-form(action='javascript:analyzeSentiment()', method='POST')
input(type="text" id="sentimentFilter" name="sentimentFilter" placeholder="Search a filter" required)
button(type="submit" id="sentiAnalysis" name="sentiAnalysis") ANALYZE
div#response
Then in your .done call you can display the results:
// analyze sentiment button
function analyzeSentiment() {
// get and post filter to the backend for sentiment score
let form = $("#searchSentiment-form");
let query = form.serialize();
console.log(query);
$.post('/', query).done(function(data){
console.log(data);
$('#results').html(data);
});
}

Cloud Functions for Firebase HTTP timeout

I'm so close with this one.
I have written a Cloud Function that takes information sent from an Azure token to custom mint a Firebase token and send this token back to the client.
The token is created correctly, but isn't returned on my HTTP-request.
Unfortunately my Firebase app causes a timeout.
Function execution took 60002 ms, finished with status: 'timeout'
I can't really wrap my head around why that is, hence this post. Is there something wrong with my code, or is it me that's calling the HTTP-request wrong?
Here is the log I get from the Firebase Functions console.
Here's my code
// Create a Firebase token from any UID
exports.createFirebaseToken = functions.https.onRequest((req, res) => {
// The UID and other things we'll assign to the user.
const uid = req.body.uid;
const additionalClaims = {
name: req.body.name,
email: req.body.email
};
// Create or update the user account.
const userCreationTask = admin.auth().updateUser(uid, additionalClaims).catch(error => {
// If user does not exists we create it.
if (error.code === 'auth/user-not-found') {
console.log(`Created user with UID:${uid}, Name: ${additionalClaims.name} and e-mail: ${additionalClaims.email}`);
return admin.auth().createUser({
uid: uid,
displayName: displayName,
email: email,
});
}
throw error;
console.log('Error!');
});
// Wait for all async tasks to complete, then generate and return a custom auth token.
return Promise.all([userCreationTask]).then(() => {
console.log('Function create token triggered');
// Create a Firebase custom auth token.
return admin.auth().createCustomToken(uid, additionalClaims).then((token) => {
console.log('Created Custom token for UID "', uid, '" Token:', token);
return token;
});
});
});
When I'm making this HTTP-request, all i'm sending in is a JSON that looks like this:
parameters = [
"uid" : id,
"email" : mail,
"name" : name
]
Cloud Functions triggered by HTTP requests need to be terminated by ending them with a send(), redirect(), or end(), otherwise they will continue running and reach the timeout.
From the terminate HTTP functions section of the documentation on HTTP triggers:
Always end an HTTP function with send(), redirect(), or end(). Otherwise, your function might to continue to run and be forcibly terminated by the system. See also Sync, Async and Promises.
After retrieving and formatting the server time using the Node.js moment module, the date() function concludes by sending the result in the HTTP response:
const formattedDate = moment().format(format);
console.log('Sending Formatted date:', formattedDate);
res.status(200).send(formattedDate);
So, within your code, you could send the token back in the response with send(), for example:
// ...
// Create a Firebase custom auth token.
return admin.auth().createCustomToken(uid, additionalClaims).then((token) => {
console.log('Created Custom token for UID "', uid, '" Token:', token);
res.status(200).send(token);
return token;
});
// ...

Categories

Resources