65.9K
CodeProject is changing. Read more.
Home

Read Emirates ID in a Web Application

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.50/5 (6 votes)

Oct 31, 2018

CPOL

5 min read

viewsIcon

18456

Read Emirates ID in a web application, using JavaScript, chrome extension and desktop application

Introduction

As of writing this document, the only applicable way to read emirates ID is to have a desktop application. The official SDK provided by Emirates ID authority included some Java applet examples which will not work anymore on recent browsers. But everyone is going now to web applications instead of desktop applications, so how can we design a workaround to achieve this?

Background

For security reasons, Java applet is obsolete in recent browsers, and this does not end here. In Chrome, you cannot run a client EXE from your web application. You cannot access the clipboard... Ok! you cannot directly, but you can using extensions.

Using the Code

We have to use the official SDK, so we need a desktop application; however, using Chrome extension, you can execute the desktop application in the background. That application will read the Emirates ID data, push the data to the clipboard, then close. Once closed, the chrome extension will read the clipboard, and send the data back to the webpage.

Look at the image below to understand the general concept:

Now, let us start with the solution.

A. Create the Desktop Application

Create a simple console application, that

  1. reads Emirates ID
  2. serializes it into JSON format
  3. pushes it to clipboard
  4. then closes

I will not go through the creation of the EXE application, as you can find the source code on github. Also, this article is not to explain how we read the Emirates ID from a desktop application. However, this application must use the official SDK from the Emirates ID Authority.

Code sample:

        [STAThread]
        static void Main(string[] args)
        {
            var model = Controller.CreateFromEIDReader();
            if (model.HasData)
            {
                Clipboard.SetText(Newtonsoft.Json.JsonConvert.SerializeObject(model));
            }
            else
                Clipboard.SetText("NO DATA");
        }

B. Authorize Application with Chrome

Chrome cannot call EXE unless it's pre-authorized. Don't worry, authorization is very simple, and it uses chrome Native Messaging, so please refer to the official documentation.

  1. Copy the EXE application, created in the previous step, with all required DLLs to a new folder.
  2. Create a json file called ae.eid.chrome.json.
  3. Add a Key to the registry to define a unique name of your application, and let it point to a json file. The json file explains what to run and who can run the application. The easiest way is to create a batch file in the same directory and add the following code:
REG ADD "HKLM\Software\Google\Chrome\NativeMessagingHosts\ae.eid.chrome" 
/ve /t REG_SZ /d "%~dp0ae.eid.chrome.json" /f
Quote:

%~dp0 is the current folder from where you run the command.

So here we are saying:

Quote:

Hey chrome... you can run the application ae.eid.chrome, and to know how please check the file ae.eid.chrome.json

So what is there in the ae.eid.chrome.json?

Two values are important to us here:

  1. path to specify the EXE file
  2. allowed_origins to specify which chrome extension can call this EXE. This is the chrome extension id that you will create right now.
{
  "name": "ae.eid.chrome",
  "description": "chrome extension to read EID",
  "path": "EIDSampleConsole.exe",
  "type": "stdio",
  "allowed_origins": [
    "chrome-extension://elgjklijpoecdfbjejecncdpggdphnle/"
  ]
}

C. Create Chrome Extension

The main file in any Chrome Extension is the manifest. Other than that, a Chrome extension can have many other files depending on what you want to achieve. In our case, I'm using a content_script and a background process. So what are these files?

The background process is isolated from the web pages opened in Chrome. This means it cannot contact the Chrome tabs directly. It has to go through the content_script. content_script can contact both the background process and the pages opened in Chrome. Being isolated, the background process can call an EXE, and read the Clipboard data. Both functions are not allowed directly in Chrome.

Quote:

In my case, the background file is eid.js, the content_script is content_script.js, and since I use jquery, I also add the jquery

manifest.json

Any Chrome extension will have a manifest.json file. It lists the behavior and the permissions of the extension. The most important permissions required are nativeMessaging and clipboardRead. It's here also where we specify the content_script files and the background file. You can notice the listing of jquery because I'm using some jquery in the content_script file, and not only JavaScript.

{
  "name": "EID Reader",
  "version": "1.0",
  "manifest_version": 2,
  "description": "Read Emirates ID",

  "permissions": [ "contextMenus", "activeTab", "clipboardRead", "nativeMessaging" ],
  "icons": {
    "16": "eid16.png",
    "48": "eid48.png",
    "128": "eid128.png"
  },
  "background": {
    "scripts": [ "eid.js" ]
  },
  "content_scripts": [
    {
      "matches": [ "http://*/*", "https://*/*", "file://*/*"],
      "js": [ "content_script.js", "jquery-3.3.1.js" ],
      "all_frames": true,
      "run_at": "document_start"
    }
  ]
}

content_script.js

This file is playing a role of translator. It can listen to whatever happens in your web pages, and transfer these actions to the background process by sending messages. It can also receive messages from background process and transfer it again to the web pages. Keep in mind that your web pages cannot access the background process directly, and it has to be through content_script.

Technically, content_script will contain two listeners: one to receive messages from web pages, and another one to receive messages from background process.

// Listener to catch the event raised by the webpage button
document.addEventListener("EID_EVENT", function (data) {
    // send message to background process to read emirates ID and send back the data
    chrome.runtime.sendMessage("test", function (response) {
    });
});

// Listener to catch the data coming from the background process
chrome.extension.onMessage.addListener(function (msg, sender, sendResponse) {
    if (msg.action == 'EID_DATA') {
        //Parse the data and fill the form accordingly
        try {
            var json = $.parseJSON(msg.response);
            $(json).each(function (i, val) {
                $.each(val, function (key, value) {
                    if (key == 'EIDNumber')
                        $("#txtNumber").val(value);
                    if (key == 'Name')
                        $("#txtName").val(value);
                    if (key == 'Email')
                        $("#txtEmail").val(value);
                    if (key == 'PassportNumber')
                        $("#txtPassport").val(value);
                });
            });
        }
        catch (e) {
            var error = "error" + e;
        }
    }
});

eid.js

This is where we do the main processes. Here, we will call the EXE application, and here is where we read the clipboard. Here is also where we send the data back to content_script, which will parse it and push it to web pages.

Technically, this will have a listener to receive messages from content_script. Once received, it calls the EXE application asynchronously, and will wait until the EXE finish his task (Read Emirates ID, and put it in clipboard). Once finished, an event will be fired, to read the clipboard and send it to content_script to parse it and push it to the web page.

var port = null;
var tabId = null;
/* listener for messages coming from the content_scrip */
chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
    tabId=sender.tab.id;
    var hostName = "ae.eid.chrome";
    port = chrome.runtime.connectNative(hostName);
    port.onDisconnect.addListener(onDisconnected);
});

/* THIS WILL BE CALLED ONCE EXE FINISH */
function onDisconnected() {
    port = null;
    SendResponse();
}

function SendResponse() {
    //create a textarea, focus on it, 
    //and make a "paste" command to get the clipboard, 
    //then send the pasted value back to the content_script
    bg = chrome.extension.getBackgroundPage();
    bg.document.body.innerHTML = ""; // clear the background page
    var helper = null;
    if (helper == null) {
        helper = bg.document.createElement("textarea");
        helper.style.position = "absolute";
        helper.style.border = "none";
        document.body.appendChild(helper);
    }

    //Focus the textarea
    helper.select();

    // perform a Paste in the selected control, here the textarea
    bg.document.execCommand("Paste"); 

    // Send data back to content_script
    chrome.tabs.sendMessage(tabId, 
         { action: "EID_DATA", response: helper.value }, function (response) { });
}

Add Extension to Chrome

  1. Open Chrome and type chrome://extensions/
  2. Press on Load unpacked
  3. Select the extension folder
  4. Chrome will load the extension and give it an id.
Quote:

Remember to copy the extension id and put it in the file ae.eid.chrome.json to authorize this extension to execute the exe application.

Test the solution

Now create a web page, add a button that raise an event, and add few inputs to be filled by the data captured from Emirates ID.

<body>
    <div class="form-group">
        <a class="btn btn-primary" href="javascript:readeid();">Read EID</a>
    </div>
    <div class="form-group">
        <label for="txtNumber">Number</label>
        <input type="text" class="form-control" id="txtNumber" placeholder="Number">
    </div>
    <div class="form-group">
        <label for="txtName">Name</label>
        <input type="text" class="form-control" id="txtName" placeholder="Name">
    </div>
    <div class="form-group">
        <label for="txtEmail">Email address</label>
        <input type="email" class="form-control" id="txtEmail" placeholder="Email">
    </div>
    <div class="form-group">
        <label for="txtPassport">Passport</label>
        <input type="text" class="form-control" id="txtPassport" placeholder="Passport">
    </div>

    <script>
        var readeid = function () {
            var event = document.createEvent('Event');
            event.initEvent('EID_EVENT');
            document.dispatchEvent(event);
        }
    </script>
</body>

Summary

Remember, this is a workaround, not a native solution. Native solution must come from the SDK developers.

For more information, please visit the project on github.