How to Mask Your Phone Number With Tropo and Ruby On Rails
In this post, we’ll show you how to create a Ruby On Rails web application that dynamically generates masks for phone numbers. The source code for this project can be found here. When some one calls the mask, the call will get transferred to the actual number. This way, users can keep their actual phone numbers anonymous, for example, when conducting business online.
We will focus on the Tropo back-end side of things.
Steps:
- Create a Ruby on Rails App and expose it to the internet via ngrok for local testing
- Create a Tropo Account if you have not already done so
- Create a Tropo Application specifically for this feature, and provide your ngrok url
- Provision a Tropo mask (phone number) with the same area code as the number you are masking
- Use the Tropo Ruby Web API to transfer calls made to the mask to the actual number
Create a Rails App and expose it via ngrok:
Ngrok is an application that allows you to expose a local server behind a NAT or firewall to the internet. Using ngrok, you can run your Rails app on your local machine (via the command “rails server”) and have the application be exposed to the internet.
One you have ngrok running, your local server will be exposed on a public URL such as: http://2b767f53.ngrok.io
This is the url we will provide to Tropo when creating a new Tropo app.
Here is the ngrok website: https://ngrok.com/
Every time some one masks a number through our app, we generate and store the mask (and number, if it’s not already stored) in the database. We’ll model this with two tables, a ‘mask’ table storing the generated masks and a ‘number’ table storing the number to which our masks will redirect. Here are the rails commands we used to create our models:
rails g model number number:string rails g model mask mask:string number:references
Basically, each number and mask is a phone number, and each mask is associated to a number.
Create a Tropo Account and Application:
If you haven’t done so already, sign up for a new Tropo account and create a new application.
Here are the Tropo Docs that explain this process in detail: https://www.tropo.com/docs/
When asked to provide a script URL, select the Web API option. Feel free to provide a fake URL if your application is not yet set up. You can always change this later. Once you have it set up, make sure to provide the publicly accessible URL to your app (more on this in the Ruby Web API section). There’s no need to add a number at this stage but feel free to do so.
Provision a mask
Below is an example of how to dynamically provision masks from your Rails application.
Here are the docs: https://www.tropo.com/docs/rest/tutorials/adding-number-based-prefix
# assumes number is prefixed with "+1" def self.generate_mask_for_number(number) uri = URI.parse("https://api.tropo.com/v1/applications/#{@@mask_app_id}/addresses") http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = (uri.scheme == "https") request = Net::HTTP::Post.new(uri.request_uri) request.basic_auth(@@user, @@pass) request.set_form_data({'type' => 'number', 'prefix' => number[1...5]}) response = http.request(request) if response.code === '200' response_uri = JSON.parse(response.body)['href']; return extract_number_from_uri(response_uri) else puts 'generating mask with prefix ' + number[1...5] + ' failed with http ' + response.code + ' and message: ' + response.body return generate_random_mask_for_number(number) end end # assumes number is prefixed with "+1" def self.extract_number_from_uri(uri) index_of_plus = uri.index('+') return uri[index_of_plus..-1] end
I’ve used the Net:HTTP library built into Ruby, but you’re welcome to use other libraries, such as HTTParty.
This method takes in a person’s phone number and makes a POST request to https://api.tropo.com/v1/applications/#{@@mask_app_id}/addresses, where mask_app_id is the id of your Tropo application (not to be confused with app token). This id can be found in the url when visiting your Tropo application.
Your Tropo username and password are used for basic authentication. The form data specifies the type as ‘number’, which is required. The prefix is optional, and specifies the prefix of the provisioned number, with ‘+’ omitted. In the example, we are provisioning a mask with the same areacode as the number passed in to the method. The generate_random_mask_for_number method does the same thing, but sets the prefix to “1”, which causes Tropo to generate a random U.S. number.
Note that the number being passed in is assumed to be in international format. To help with phone number format issues, we recommend using a library such as Phonelib: https://github.com/daddyz/phonelib
If you’re provisioning masks dynamically, it’s important to keep track of the numbers and their masks, so that you can properly transfer calls. One way to do this is to to maintain a table of masks, and a table of numbers, where each mask belongs to a number.
Once a number is provisioned, you will see it listed in your Tropo application webpage.
Tropo Ruby Web API
When some one calls the mask (i.e., the Tropo provisioned number), Tropo will make a POST request to the voice URL you provided, and it expects a JSON response. Below is an example of using the Ruby Web API library to return a JSON string. This string tells Tropo to forward the call to the number associated with the mask. Make sure the URL you provided in your Tropo App leads to this method (e.g., http://2b767f53.ngrok.io/transfer is the url you provided and that gets routed to the transfer method in your config/routes.rb like so: post ‘/transfer’, to: ‘transfers#transfer’ ).
def transfer from = params[:session][:from][:id] to = params[:session][:to][:id] mask = Mask.find_by mask: Phonelib.parse(to).e164 number = mask.number.number t = Tropo::Generator.new t.transfer(:to => number, :from => from) render :json => (t.response) end
The from is the number of the person calling. The to is the mask. The number is the number associated with the mask, which we get from the database. Here are the Tropo docs for transferring a call:
https://www.tropo.com/docs/scripting/quickstarts/controlling-calls/transferring-call
And we’re done! From now on, any calls to the mask will be forwarded to the actual number.
Check out our next blog post on adding a callback feature, coming soon.