Saturday, April 20, 2013

What's My IP?

Why do you need/want to know your IP?

The links to all the code and tools used in this article are provided at the bottom.
I travel a lot, and even when I don't, I access the internet from various locations. Other than the varying bandwidths and limitations, there are adverse side effects to having a certain IP over another:

  1. Certain countries block access to certain content based on your geolocation - try accessing Hulu abroad, or BBC content in the US.
  2. Some information is blocked based on geographical location - even in the US. Some live streaming channels (like CNN) demand that you identify your local cable provider, in order to watch live TV.
  3. Some web sites completely change the user experience based on the perceived user location. Try going to Google.com from abroad, and by default you'll get a local version of the search site.
As a developer, it's important to me to know what's my IP, and where does a web site thinks I am. The problem is your laptop/device can only show your internal IP - the one allocated to you by your router or switch. To get your external IP, you need to access an external resource and have it tell you what IP does it see.

There are tons upon tons of web sites and extensions that do this for you today (try http://www.whatismyip.org/, or even try typing "what's my ip" into google), but I, being a great wheel re-inventer, wanted to solve my problem myself, and along the way, learn some more JavaScript and new tools.

The design

In order to get your IP, you need a server side component. I decided to use Node.js, as my entire logic can be easily implemented with several lines of JavaScript code. Also, I can host my solution on Heroku for free, and Git deployment means the entire app can be deployed and updated from command line.

For the geolocation info, I used a free service from IPinfoDB. The free tier gives you access to the 'Lite' service, meaning geolocation is not accurate. Sometimes you get a different zip code, city or even state. But it was good enough for my needs and I can always upgrade to the paid service, to get more accurate results.

For the client, at first I thought I'd just use the browser, but then decided it's a good chance to revisit my Chrome extension projects, and just build an extension that consumes the data returned from the server.

The server

Writing a web server in Node.js involves 3-5 lines of code. My entire app, including calls to the IPinfoDB service, results output, and (very minor) error handling, ended up being 40 lines long, in one file. I put all the other parameters in a separate config file, for easier editing. It was then easy to create a new Heroku site, commit my pages to Git and deploy. 

I then added a 'vanity domain name', so you can check out the site at http://myip.TravelingTechGuy.com. You can just go to this link and you'd get the JSON results (again, not really accurate, since it's free), or install the extension below.

The extension

A Chrome extension is basically a web app (HTML, CSS, JavaScript, and images) + a manifest file tying it all together, into a single .zip file. But the directory structure, and the manifest file are a hassle to write, and tasks get quite repetitive. I decided to use a new tool I learned about recently, called Yeoman

Yeoman allows you to bootstrap web development, by using templates (generators) of the desired result, in this case a Chrome extension, and uses Grunt to automate the build process. After installing Yeoman, and the Chrome extension generator, you can kick up the process by issuing a single command line. Few questions later, an you have a skeleton of an extension, that can actually run. All you need then is to fill the JavaScript files with logic, add styles to the CSS file, and add icons/images.
Issuing a grunt command 'builds' the extension - checks the JavaScript correctness (using JSHint), minimizes files, compresses images and zips everything up to an extension ready to be deployed.

All that remains then is to upload the extension to the Chrome web store. Just go to the store, log in, and go to the developer dashboard. You'll be asked for additional information, images, screen captures etc. before you can publish your extension.

To be able to access my server form the extension, I had to add a permission to the manifest file with the exact URL I'd be calling. That allows cross-site AJAX call from the extension's code.

The only challenge I encountered when implementing the extension's logic, was the copy function, that allows copying the IP to the clipboard. Turns out you can only copy text from input elements, so I had to create one. Then, it turns out the input element has to be visible for you to be able to copy from. Since that would have meant sticking an ugly text box in my popup, I just pushed that code to a background page. Finally, you need to add a permission to the manifest for clipboard access - it's called 'clipboardWrite'.

The apps

The code

The tools