how can I make an outbound SIP call using Twilio? - python

I am using a Galaxy 8S android phone with the Samsung SIP settings. I have successfully registered a (Twilio) SIP account on the phone. I want to make an outbound call to an international PSTN Number NOT to another sip address.
My SIP doman, on Twilio, points to my heroku app.
The code is:
#application.route("/makesip", methods=['GET', 'POST'])
def makesip():
to_number=request.values.get('To', None),
client = Client(ACCOUNT_SID, AUTH_TOKEN)
call = client.calls.create(to=to_number, from_="+1415792xxxx", url="https://myapp.herokuapp.com/sipout", method="POST")
return call.sid
#return "OK"
#application.route("/sipout", methods=['GET', 'POST'])
def sipout():
response = VoiceResponse()
to_number = request.values.get('To', None)
dial = Dial(caller_id='+1415792xxxx')
dial.number(to_number)
response.append(dial)
return str(response)
When I make the call from my cell phone it hangs up almost immediately and says "Server Error try again later". The Twilio error log says:
We don't support dialing out to global twilio domains (domainname.sip.twilio.com). Only regional (domainname.sip.us1.twilio.com) ones are supported.
I think that I am making a very fundamental error here but I simply cannot identify it. Can anybody help please? Should I, for example, set the "from_" parameter as "sip:my_sip_address.domainname.sip.us1.twilio.com"?

I'm not a heroku expert, but your code looks similar enough to the php I have running which works fine for this.
In your phone settings is your SIP server set as user#domainname.sip.twilio.com or as user#domainname.sip.us1.twilio.com? It should be the latter. I seem to remember getting caught out by something like this when I was trying to get things working
EDIT
Just had another play with mine and I figured it out. You have to dial the number from your phone as phonenumber#yourdomain.sip.twilio.com, then twilio will return to as sip:phonenumber#yourdomain.sip.twilio.com
You need to change this line of your code to strip out just the number
to_number=request.values.get('To', None),
My php line is substr(strtok($to, '#'), 4); so whatever your equivalent of that is.

What I think is probably happening is that the "To" that is hitting your Heroku app is in the format "sip:+12312123123#yoursipdomain.sip.twilio.com;user=phone" and you're trying to inject that directly into the "dial" verb.
What you actually want is to strip it down to the bare number in E.194 format (with the leading +).
I'd suggest starting by testing using a quick TwiML Bin as per the Twilio SIP Registration docs, rather than your Heroku app.
TwiML Bins are basically static TwiML but with a tiny bit of intelligence in special tags. It's like the Twilio equivalent of Mail Merge, if you've ever used that in Microsoft Word.
(Twilio recently updated the SIP Registration docs. They're much better now.)
Use a TwiML Bin for initial testing otherwise you risk spending time fixing an otherwise working Heroku app because the problem is your phone/account.
Go to "Twilio Docs > API Reference > Twilio Voice API > SIP Registration".
Scroll down to "Using Enhanced TwiML Bin Templates to Call a mobile/landline on the Public Telephone Network" and follow that.
See if that works.
If it doesn't, my suspicion is your Samsung is actually spitting out something daft due to something dial plan related. (Dial plan is the conversion of +12345645642 into a SIP URI. You might find it's doing something like +012345645642 instead.)
If it does work, great. If you want to get your Heroku app working, compare the working response body to the one your Heroku app is spitting out. Post both, and we'll figure out what's going wrong.
Just to check, you are specifying a region in your Domain and Registration Server settings on the Samsung, yeah? The "yoursipdomain.sip.us1.twilio.com" that miknik talked about?

Related

How to set password reset url to a mobile deeplink using Flask Security?

Gist of the problem is, I'm not developing an SPA, I'm developing a mobile app, with a backend in Flask. FlaskSecurityToo has provided me with some great features, and I'm now trying to use their password reset functionality. Here's my gripe.
I want to have the email send a deeplink, which users on the mobile app will click and get sent to the password reset form on the app. There's no UI view for this. But FlaskSecurityToo has logic that requires the server is first hit to validate the token, then redirects them to whatever has REDIRECT_HOST set. Which works great when I set the REDIRECT_BEHAVIOR as spa
Is there a way to tell Flask "Hey, don't worry about the need to validate the token from the initially provided password reset email, let the UI/Mobile app make the call to determine that whenever they want" from the provided configuration? Thus, relaxing the constraint on the host name / details of the url for a password reset, as long as a token exists? Or is this abusing some of the principles of FlaskSecurity that I don't grasp yet?
My current plan is to let it open a mobile browser, and hopefully the redirect forces the app open? I have little experience with deeplinks, so I'm testing and probing things as I learn.
You are correct about current FS behavior - here is a suggestion (not clean but it would be interesting if it was all you need) - the POST /reset/ endpoint is stand-alone - you don't have to call GET first - the POST will ALSO verify the token is valid. So the issue becomes how to generate the link for the email that has what you want. FS currently doesn't allow to configure this (that could be an enhancement) - but in 4.0.0 you can easily replace the MailUtil class and have your implementation of send_mail look for template='reset_instructions'. Now - at this point the email has already been rendered - so you would have to parse the body and rewrite the url (keeping the token intact). Ugly but doable - is this sufficient? If so I can see a few simple improvements in FS to allow more flexibility around emails.

Poor Call Quality using Twilio Programmable Voice SDK

I am upgrading my Twilio-enabled app from the old SDK to the new Twilio Programmable Voice (beta 5) but have run into several problems. Chief among them is poor audio quality of outgoing calls, in what can only be described as what lost packets must sound like. The problem exists even when I run the Quickstart demo app, leading me to the conclusion the problem rests in my Twiml. I've followed the instructions to a "T" with respect to setting the appropriate capabilities, entitlements, provisioning profile and uploading the voip push credential, but with little documentation on the new SDK or for Python versions of the server, I'm left scratching my head.
The only modifications to the demo app I've made are to include the "to" and "from" parameters in my call request like so:
NSDictionary *params = #{#"To" : self.phoneTextField.text, #"From": #"+16462332222",};
[[VoiceClient sharedInstance] configureAudioSession];
self.outgoingCall = [[VoiceClient sharedInstance] call:[self fetchAccessToken] params:params delegate:self];
The call goes out to my Twiml server (a python deployment on Heroku) at the appropriate endpoint as seen here:
import os
from flask import Flask, request
from twilio.jwt.access_token import AccessToken, VoiceGrant
from twilio.rest import Client
import twilio.twiml
ACCOUNT_SID = 'ACblahblahblahblahblahblah'
API_KEY = 'SKblahblahblahblahblahblah'
API_KEY_SECRET = 'blahblahblahblahblahblah'
PUSH_CREDENTIAL_SID = 'CRblahblahblahblahblahblah'
APP_SID = 'APblahblahblahblahblahblah'
IDENTITY = 'My_App'
CALLER_ID = '+15551111' # my actual number
app = Flask(__name__)
#app.route('/makeTheDamnCall', methods=['GET', 'POST'])
def makeTheDamnCall():
account_sid = os.environ.get("ACCOUNT_SID", ACCOUNT_SID)
api_key = os.environ.get("API_KEY", API_KEY)
api_key_secret = os.environ.get("API_KEY_SECRET", API_KEY_SECRET)
CALLER_ID = request.values.get('From')
IDENTITY = request.values.get('To')
client = Client(api_key, api_key_secret, account_sid)
call = client.calls.create(url=request.url_root, to='client:' + IDENTITY, from_='client:' + CALLER_ID)
return str(call.sid)
The console outputs outgoingCall:didFailWithError: Twilio Services Error and the call logs show a completed client call. An inspection of the debugger shows TwilioRestException: HTTP 400 error: Unable to create record. As you can see, the url I include in the request might be problematic as it just goes to the root but there is no way to leave the url blank (that I have found). I will eventually change this to a url=request.url_root + 'handleRecording' for call recording purposes but am taking things one step at a time for now.
My solution so far has been to ditch the call = client.calls.create in favor of the dial verb like so:
resp = twilio.twiml.Response()
resp.dial(number = IDENTITY, callerId = CALLER_ID)
return str(resp)
This makes calls, but the quality is so poor as to render it useless. (10+ seconds of silence followed by intermittent spurts of hearing the other party). Using the dial verb in this way is also unacceptable because of its inefficiency as I'm now billed for two calls each time.
The other major problem, which I'm not sure is connected or not, is the fact that I haven't yet been able to receive any incoming calls, though I suspect I may need to ask that question separately.
How can I get this line to work? I'm looking at you, #philnash. Help me make my app great again. :)
call = client.calls.create(url=request.url_root, to='client:' + IDENTITY, from_='client:' + CALLER_ID)
sorry it's taken me a while to get back to your question.
Firstly, the correct way to make the ongoing connection from your Programmable Voice SDK call is using TwiML <Dial>. You were creating a call using the REST API, however you will have already have created the first leg of the call in the SDK and the TwiML forwards onto the second leg of the call, the person you dialled. Notably, you are billed for each leg of the call, not for two calls (legs can be of different length, for example, you could put the original caller through a menu system before dialling onto the recipient).
Secondly, regarding poor call quality, that's not something I can help with on Stack Overflow. The best thing to do in this situation is to get in touch with Twilio support and provide some Call SIDs for affected calls. If you can record an example call that would help too.
Finally, I haven't seen if you've asked another question about incoming calls yet, but please do and I'll do my best to help there. That probably is a code question that we can cover on SO.

Uber Rides/Python - How to configure Oauth w. Apache

I'm new to this so I apologize in advance. I am actually an AppleScript developer and would merely like to use Uber Rides.py into a script, and I have virtually no knowledge in Python. (Just looking for an 'easy' way to initiate a Uber ride within a more complex script using Homebridge and Siri).
I've built the py app but I don't know to get the Oauth code after using the authorization_code_grant.py script.
I will be the only user of this app (it's just for testing at home) so I'm not that worried about Auth but I understand it's a mandatory uber process. There's no frontend to the app (it's just the script running and responding to Siri requests via Homebridge) and no web page for the user to authenticate. The user will be myself so I just need a way to "get" the Oauth code that I then will use as part of the CLI/Python command within the Applescript.
I have two main issues:
Can someone give me a step by step on how to grab the code sent by Uber once the user has logged in and clicked on the authorized button? I seem to understand I should configure my Apache server to "receive" the code but I don't know how to? (If it helps I have set up an Horuku account but I'm not sure I need this considering Apache runs on my Mac, I just don't know how to configure it…)
When I try to use the authorization_code py (with the URI set to http://localhost:7000 but, to my knowledge, nothing runs on port 7000 at the moment, hence question 1) it generates the error below
Error:
>mediacenter$ python example/authorization_code_grant.py
Login and grant access by going to:
login.uber.com/oauth/authorize?scope=profile+request+history&state=MgnYJ18l7DxqbSYxkSfjrbGCL8BQAMg0&redirect_uri=https%3A%2F%2Foauthswift.herokuapp.com%2Fcallback%2Fsiriuber&response_type=code&client_id=3Wk7zJbSLVCFCQ69UZvQJCZ_aBfHJBDu
>Copy the URL you are redirected to and paste here:
oauth-callback/siriuber?state=MgnYJ18l7DxqbSYxkSfjrbGCL8BQAMg0&code=dK1ETADCaHcZCAbXnYKOSapetgexgj
Failed to request access token: UNAUTHORIZED.
[ErrorDetails: 401 UNAUTHORIZED invalid_client]
Traceback (most recent call last):
File "example/authorization_code_grant.py", line 150, in
hello_user(api_client)
File "example/authorization_code_grant.py", line 122, in hello_user
response = api_client.get_user_profile()
AttributeError: 'NoneType' object has no attribute 'get_user_profile'
I hope it kind of makes sense. I know I should spend some time getting to learn a "real" language but AS is (most of the time) perfect to bring different things together quickly and doing what I want!
Thanks in advance,
JC
Same person from GitHub. After digging around, I came up with this.
Basically there is probably a configuration issue in either your example/config.yaml or in your app dashboard. Make sure you configured both of those correctly. the example/config.yaml setup should be exactly like this with the three values replaced. Make sure your redirect URL is the same as the one in your dashboard under "Authorizations" redirect URLs.
Did you install from source? As in did you clone it from the GitHub repo? Or did you install it using pip?
Hope this helps.

How to allow access to App Engine from only specified IPs?

I am building a simple POST handler on GAE in Python that will accept a POST and write it to a Cloud SQL database.
I would like to limit access to this app to a limited number of IPs - non-GAE webservers where the POST originates. Essentially, how to allow POSTS from my IPs and disallow all other traffic?
Seems like a simple and common operation, but I haven't found a solution online that seems to fit. Most GAE authentication and routing packages are built around user auth.
Where should I look for a solution here? What Google keywords should I be using? Is this going to be written into the app itself or should I be focused on another component of GCP for IP access and routing?
Thanks!
All credit to Paul Collingwood for alerting me to the existence of request.remote_addr.
Here is my solution as of now:
ALLOWED_IP = ['173.47.xx.xx1', '173.47.xx.xx2']
class PostHandler(webapp2.RequestHandler):
def post(self):
# Read the IP of the incoming request
ip = self.request.remote_addr
# If the IP is allowed, execute our code
if ip in ALLOWED_IP:
# Execute some awesome code
# Otherwise, slam the door!
else:
self.error(403)
I'm not entirely sure that my self.error() usage is appropriate here, but this is working! POST requests made from the allowed IPs are accepted and executed. All others are given a 403.
I'm always eager to hear improvement suggestions.

How to accept a JSON POST?

First time here, it says to be specific... So here goes.
I'm doing a small project to connect Salesforce to my Raspberry Pi. The goal is to make a light (Think a beacon, siren-like light) flash when a high priority case comes in from a client in Salesforce. At the moment, clients usually send an email to a certain address, and this creates a case. It goes to the 'Unassigned Queue' and emails the team that this case is there waiting to be assigned.
Salesforce uses REST, so I need to be able to get the Pi to accept JSON so it can easily understand what Salesforce wants it to do.
Currently, I guess I have won half of the battle. I have a web server (Lighttpd) running on the Pi, which hosts an index page and a Python script. I am also using a Python wrapper, which allows me to easily run a command from a Telldus program I have installed. This program controls a USB RF Transmitter that I have connected, it is paired to a RF Socket, which is connected to the mains power supply with a light connected to it.
So the Python script is called power.py, and can be controlled with URL variables, so if I go to power.py?device=1&power=on&time=10&password=hunter2 that turns on device 1 for 10 seconds. I also created a POST form on the index page, which just POSTS to the python script, and runs it in the same way as using the URL variables. That all works great.
So all I need to do, is connect it to Salesforce. I would like to use REST and JSON, so that if I ever move away from Salesforce to another CRM program, it will easily be able to adapt and receive instructions from new places.
I have posted the Python script I am using here:
https://github.com/7ewis/RemotePiControl/blob/master/power.py
The Pi isn't currently allowed out of the local network, so I will need to somehow develop a way to send JSON commands, and the recieve and convert them to work using the correct variables etc. I'm not a programmer, I've just exposure to languages from hacking things and exploring. Hence why I need some guidance with this.
I have never used REST or JSON before, so what would I need to do to achieve this?
Seems like adding Flask http://flask.pocoo.org to your Raspberry Pi Webserver would be a good move. It allows server-side python to be run in response to JQuery ajax (and regular) requests. Check out a couple of examples here:
http://flask.pocoo.org/docs/patterns/jquery/
and this stack overflow question: how can I use data posted from ajax in flask?
Flask is pretty straightforward to get up and running, and is happy working with a number of servers, including Lighttpd. Writing RESTful flask is also a perfectly reasonable proposition, see: http://blog.miguelgrinberg.com/post/designing-a-restful-api-with-python-and-flask
Additionally, lots of people have used flask on the raspberry pi already-- so that could help get you up and running smoothly: http://mattrichardson.com/Raspberry-Pi-Flask/
Good luck!
Firstly don't use a Python script that prints out result directly to CGI. You will be forever debugging it.
Use a light weight framework like Flask. You can do something as simple as
from flask import Flask
application = Flask(__name__)
#application.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
# use Flask's build in json decoder
the_data = request.get_json()
# then do something with the data
return "This was a POST request, how interesting..."
else:
# request was GET rather than POST, so do something with else
return "Hello World!"
See how to configure Flask to run with Lighttpd here http://flask.pocoo.org/docs/deploying/fastcgi/
If you want to test this you can either write another Python script to send JSON data to your server (I recommend looking at the Python Requests library for this http://www.python-requests.org/en/latest/), or you can do this manually using a HTTP request builder, such as HTTPRequester for Firefox (https://addons.mozilla.org/en-US/firefox/addon/httprequester/)

Categories

Resources