Tuesday, July 29, 2014

JavaScript Event Manager

I am making some graphical plotting widgets for website with D3.js. Overall, it's a very user-friendly tool and I highly recommend it. However, there is one thing that really bothers me - events handling. The reason I want to use this is that I have the need to synchronize data across several plot widgets. As each widget is self-contained and defined within their own namespace, I need to use events to achieve this goal. After some research I found D3.js does come with an event handling functionality - dispatch. Here is how to use it:

// create dispatch and pass in the event name
var dispatch = d3.dispatch("my_event");

// send the event
dispatch.my_event(object);

// listens to the event
dispatch.on("my_event", function(object){
    // my work
});

The code is pretty self-explanatory, and frankly speaking, quite easy to use, but there is one catch that I decide to do it myself.

If an event listener was already registered for the same type, the existing listener is removed before the new listener is added. To register multiple listeners for the same event type, the type may be followed by an optional namespace, such as "click.foo" and "click.bar".

Although it claimed differently, it is effectively saying that you just can't add multiple listeners to one event. So I quickly decided the requirements for my own events handler class:

  • Send event
  • Register/remove event listener
  • Allow multiple listeners for one event

And this is what I came up with:

// constructor
function EventDispatch () {
 // initialize parameters
 this.event_name_list = [];  // list of event names
 this.event_handle_list = {}; // container of event handles
}

// register event
EventDispatch.prototype.registerEvent = function (event_name) {
 if (event_name != null && event_name != undefined) {
  // add to event_list and event_handle_list
  // if event is not in the list
  if (!this.eventNameExist(event_name)) {
   this.event_name_list.push(event_name);
   this.event_handle_list[event_name] = [];
  }
 }
};

// send message
EventDispatch.prototype.send = function (event_name, event) {
 if (this.eventNameExist(event_name)) {
  var callbacks = this.event_handle_list[event_name];
  for (var k=0; k<callbacks.length; k++) {
   callbacks[k](event);
  }
 }
};

// register event listener
EventDispatch.prototype.registerListener = function (event_name, callback) {
 if (this.eventNameExist(event_name)) {
  this.event_handle_list[event_name].push(callback);
 }
 else {
  this.registerEvent(event_name);
  this.event_handle_list[event_name].push(callback);
 }
};

// remove event listener
EventDispatch.prototype.removeListener = function (event_name, callback) {
 if (this.eventNameExist(event_name)) {
  for (var k=0; k<this.event_handle_list[event_name].length; k++) {
   if (this.event_handle_list[event_name][k] == callback) {
    this.event_handle_list[event_name].splice(k, 1);
   }
  }
 }
};

// utility function: check even_name in event_list
EventDispatch.prototype.eventNameExist = function (event_name) {
 var is_found = false;
 for (var k=0; k<this.event_name_list.length; k++) {
  if (this.event_name_list[k] == event_name) {
   is_found = true;
  }
 }
 return is_found;
};

As a result, it works pretty well~




Thursday, July 24, 2014

My First Try with D3.js

I have to say D3.js is such an amazing library. Although I just started a few days ago, I have already get a pretty good idea how it works. Anyway, I started with simple bar plot and here is what I got - DEMO.

It is a simple bar plot with color intensity to indicate their values. Once the update button is clicked, it will generate a batch of new data and assign them to the plot. A transition is used during the update.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>D3 First Demo</title>
        <script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
        <style>
         rect:hover { fill: orange; }
        </style>
    </head>
    <body>
     <svg class="my">test</svg>
     <br />
     <button class="control">Update</button>
        <script type="text/javascript">
            // data
            var dataset = [ 5, 10, 13, 19, 21, 25, 22, 18, 15, 13,11, 12, 15, 20, 18, 17, 16, 18, 23, 25 ];
            // plot parameters
            var w = 480;
            var h = 200;
            // x, y scale
            var xScale = d3.scale.ordinal()
                .domain(d3.range(dataset.length))
                .rangeRoundBands([0, w], 0.2);
            var yScale = d3.scale.linear()
                .domain([0, d3.max(dataset)])
                .range([0, h]);
            // get svg
            var svg = d3.select(".my")
               .attr("width", w)
               .attr("height", h);
            svg.selectAll(".bar")
             .data(dataset)
             .enter()
             .append("rect")
             .attr("x", function(d,i) { return xScale(i); })
             .attr("y", function(d) { return yScale(d3.max(dataset)-d); })
             .attr("width", xScale.rangeBand())
             .attr("height", function(d) { return yScale(d); })
             .attr("fill", function(d) { return "rgba("+Math.floor(yScale(d))+",30,30,0.7)"; });
            // control
            d3.select(".control").on("click", function(){
             update();
             // debug
             console.debug("Click detected");
            });
            function dataGenerate () {
             dataset = [];
          for (var k=0; k<20; k++) {
           dataset.push(Math.floor(((Math.random()+0.5)*20)));
          }
         }
         function update () {
          dataGenerate();
             svg.selectAll("rect")
              .data(dataset)
              .attr("fill", function(d) { return "rgba("+Math.floor(yScale(d))+",30,30,0.7)"; })
              .transition()
              .duration(1000)
              .attr("y", function(d) { return yScale(d3.max(dataset)-d); })
              .attr("height", function(d) { return yScale(d); });
         }
        </script>
    </body>
</html>

Monday, July 7, 2014

Make HTTPS Get Request in Android

Making an HTTP get request is pretty simple in Android. However, the problem becomes a little bit tricky when the request is made in HTTPS. If you try to get the response from an HTTPS site by yourself, you may end up with either one of these two scenarios:
a) target site is verified by one of the certificate authorities (CA): you get the correct response you want
b) target site is self-signed: you get an exception - javax.net.ssl.SSLPeerUnverifiedException: No peer certificate

The first scenario actually is no trouble at all, as all you need to do is change "http" to "https", and everything works fine. In fact, for most of the APIs provided by companies such as Facebook and Google, you won't worry about this at all. The real problem is when you want to make an HTTPS request to a self-signed site. As you may want to develop your own site and protect it with HTTPS, you probably won't go through the trouble to verify your certificate with CA. Then you need to make your Android app to make HTTPS request to a self-signed site.

After a bit of searching, this are generally two ways to do this:
a) request with DefaultHttpClient (Apache)
b) request with HttpURLConnection
As Android documentation suggests, DefaultHttpClient has fewer bugs for Android 2.2 and previous versions and HttpURLConnection is the best choice after Android 2.3. So let's just take a look at how to do this with HttpURLConnection.

The very first step is to get a copy of the certificate the target site is using and store it as some_certificate.crt. I understand that getting a certificate can not be automated, which seems tedious, but as HTTPS is meant to secure HTTP, you better to go through this. After you have the certificate file, store it locally on your project, the path I am using is /res/raw/some_certificate.crt.

The second step is to load the certificate in the program. This step actually can be done inline with the HTTPS request, which mean you can load the certificate every time you make the request (but is might slow done your application).

Certificate cert = null; // certificate variable

// you can put this either in a separate function or inline with HTTPS request
try {
 CertificateFactory certFact = CertificateFactory.getInstance("X.509");
 cert = certFact.generateCertificate(context.getResources().openRawResource(R.raw.cert_id));
} catch (Exception e) {
 e.printStackTrace();
 cert = null;
}

The third step is to use the certificate (KeyStore -> TrustManagerFactory -> SSLContext). Notice in this step I revoke the hostname verification.

// load certificate to KeyStore
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(null, null);
keystore.setCertificateEntry("cert_alias", cert);

// initialize a TrustManagerFactory with the KeyStore
TrustManagerFactory tmfact = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmfact.init(keystore);

// initialize SSLContext with TrustManagerFactory
SSLContext sslctx = SSLContext.getInstance("TLS");
sslctx.init(null, tmfact.getTrustManagers(), null);

// this step is just to revoke hostname verification
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier(){
 @Override
 public boolean verify(String hostname, SSLSession session) {
  return true;
 }
});

// make the  request
URL url = new URL("your url to request with https://");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
r_conn.setSSLSocketFactory(sslctx.getSocketFactory());

Now the connection should be working, and you can read out the input stream of the connection for the real string based response.

// read response
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String r_response = "";
String r_line = null;
while ((r_line = r_reader.readLine()) != null) {
 r_response += r_line;
}

Reference:
1. Android Documentation - HttpURLConnection
2. Android Documentation - HttpsURLConnection
3. StackOverFlow - Android SSL HTTP Request using self signed cert and CA
4. StackOverFlow - java.io.IOException - Hostname was not verified




Tuesday, July 1, 2014

Match Private/Internal IP by RFC1918

This is about how to use regular expression (Regex) to parse IP addresses that are private/internal according to RFC 1918 documentation.

In the documentation, the following IP address ranges are treated as private/internal:

10.0.0.0 - 10.255.255.255              8 bits prefix

172.16.0.0 - 172.31.255.255        12 bits prefix

192.168.0.0 - 192.168.255.255    16 bits prefix

The strategy is to match each range with a regex and use "|" to match either one of them. The individual regex are:

10(?>\.\d{1,3}){2}

172\.(?>1[6-9]|2\d|3[0-1])(?>\.\d{1,3}){2}

192\.168(?>\.\d{1,3}){2}
Note: one thing to mention about this is that these three expressions don't match "exactly" the IP address format, mainly because they don't check the range (0 to 255) in the atomic expression (?>\.\d{1,3}). However, as long as your IP address comes from a trusted source (e.g., http header), you won't face this problem.

After getting each individual regex, I just package them with match string start (\A) and end (\z), and separate them with "|". Here is the results:

\A(10(?>\.\d{1,3}){3})|(192\.168(?>\.\d{1,3}){2})|(172\.(?>1[6-9]|2\d|3[0-1])(?>\.\d{1,3}){2})\z

You can go to regular expression 101 to test it.

Secure RESTful API Access

I recently implemented a RESTful API interface. The interface works well, but what worries me is that is anyone can have access to the APIs. So I started to look for a way to secure my API access. After googling "secure API access", I found some very useful posts, but the one I liked the most is "Designing Secure REST (web) API without OAuth", which partially based on the RFC2104 HMAC document. The reason that I love it the most is that this approach doesn't require a two-stage authentication, where in the first stage, the client need to authenticate the server to get an access token, and in the second stage, the client transmit messages with the access token.

In order to secure the transmission, a common private key is always needed for both client and server, because anything transmitted over the Internet can not be treated as safe. So on the client side, it will looks like this:

Client:
    - Private
        - a private key (never transmitted)
    - Public
        - client identity (IP address and/or MAC address)
        - timestamp (generated when make the request in UTC)
        - actual array of parameters you want to transmit over the Internet
        - a hash (mentioned in the next paragraph)

To secure the transmission, according to HMAC, I have to generate a hash based on both private and public parameters on the client side with a black box function. The black box function is simply a way of secretly mixing these parameters together, during which you can do whatever crazy things you can imagine. After mixing, the result is passed to a hash function such as SHA1 (MD5 is considered to be broken), and transmit the hash with the public parameters.

So on the the server side, it will receive all the public parameters transmitted by the client. In order to validate the access, the server goes through the following steps:

 - if timestamp is expired (more than 1 minute old), reject the access
 - compute the hash using the same scheme in the client
     - grab client identity from http header
     - grab private key from local key store
     - compute the hash
 - if the computed hash doesn't match the transmitted hash, reject the access
 - everything checks out at this point, proceed the access