Friday 6 November 2015

Checking VPN with Javascript

The problem: When working outside the office, there are two ways to access the company’s services (e.g. email, time sheets, …)
  1. access the company URLs directly using company VPN: e.g. https://email.company.com
  2. access the company URLs via company’s web portal, where the portal acts as a proxy. The company URLs are replaced like this: https://webportal.company.com/prx/000/https/email.company.com
So to access company service, I would have to type different URLs in the browser depending on whether I am on VPN or not. This can be tedious. So I wrote a little cheat sheet as my home page to automate this for me. The following Javascript goes in the head section of the HTML file.

    var webgatePrefix="https://webportal.company.com/prx/000/";
    
    var addrText='{ "links" : ['+
        '{"name": "Web Mail", "url":"https://mail.company.com/owa"},'+
        '{"name":"Travel", "url":"https://ecc.company.com/irj/portal"},'+
        '{"name":"Expense", "url":"http://iler.company.com:8007/OA_HTML/OA.jsp?OAFunc=OAHOMEPAGE&SSO_RESP=FN"},'+
        '{"name":"Wiki", "url":"http://creativity/SpaceDirectory/Sites/wiki/default.aspx"}'+
    ']}';
    
    
    var addrDb ;
    

    function checkVpn() {
        if (window.XMLHttpRequest) xmlhttp = new XMLHttpRequest();
        else xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        xmlhttp.open("HEAD","http://wh/wh");
        
        xmlhttp.onreadystatechange=function() {
            // IE reports 12007 if no network
            if(200 == this.status) {
                document.getElementById("vpn").innerHTML="Got VPN!";
                addrDb = JSON.parse(addrText);
            } else {
                document.getElementById("vpn").innerHTML="No VPN! "+this.status;
                addrDb = JSON.parse(addrText, function(key, value) {
                    if (key === 'url' && typeof value === 'string') {
                        return webgatePrefix+value.replace(":/", "")
                    } else
                        return value
                })
            }
            var ul=document.getElementById("ox");
            ul.innerHTML="";
            
            for (i in addrDb.links) {
                var link=addrDb.links[i];
                var li = document.createElement("li");
                var a=document.createElement("a");
                a.setAttribute("href", link.url);
                a.innerHTML=link.name;
                li.appendChild(a);
                ul.appendChild(li);
            };
        }
        
        xmlhttp.send();
    }
    window.onload = function() {
        checkVpn();
        
    }

The body section of the HTML is then quite simple:

   
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript"><!-- the javascript code goes here --></script>
</head>
<body>
    <div id="vpn">Checking VPN...</div>
<h1>Company Links</h1>
<ul id="ox"></ul>
</body>
</html>


The approach is very simple: try to access a URL that is only available in VPN. If it is accessible, then we are on VPN; otherwise, we are not.
Notes:
  1. this only works on IE using the ActiveX object (I have only tested on IE8, which is required by company’s web mail). It does not work on Chrome because Chrome does not bubble the XmlHttpRequest.send() error to the Javascript to handle - the XHR spec simply does not distinguish between network error and CORS denial.
  2. the first line '&lt!DOCTYPE html&gt' is very important in IE, otherwise, IE will complain JSON undefined.