chrome token signing Extension

214 views
Skip to first unread message

Hela Guesmi

unread,
May 25, 2017, 8:38:19 AM5/25/17
to Native-Client-Discuss

I am trying to make an extension that will communicate with a native messaging host [chrome-token-signing](https://github.com/open-eid/chrome-token-signing). I use gemalto smart card  reader .  I installed extension , it return  an cmd window when I exit or put any string  . I have message log `TEST: ERROR  {"message":"Error when communicating with the native messaging host."}`
Do I need to do Something
I have installed the host in the registry like `HKEY_LOCAL_MACHINE\software\Google\Chrome\NativeMessagingHosts\ee.ria.esteid` and value `C:\Users\dev\Desktop\chrome-token-signing\host-windows\ee.ria.esteid.json`
 
**The native application manifest.json:**
 
    {
     "name": "ee.ria.esteid",
     "description": "Give signatures with your eID on the web",
     "path": "chrome-token-signing.exe",
     "type": "stdio",
     "allowed_origins": [
    "chrome-extension://ckjefchnfjhjfedoccjbhjpbncimppeg/"
    ]
     }  
  **manifest.json of extension**
     {
      "name": "Token signing",
      "version": "0.0.24",
      "minimum_chrome_version": "40.0",
      "manifest_version": 2,
      "description": "Use your eID smart card on the web",
      "icons": {
      "48": "icon48.png",
      "128": "icon128.png"
      },
      "content_scripts": [{
      "matches": ["*://*/*", "file:///*"],
      "exclude_matches": ["*://www.overdrive.com/*"],
      "js": ["content.js"],
      "run_at": "document_end",
      "all_frames": true
      }],
      "background": {
      "scripts": ["background.js"]
      },
      "permissions": ["nativeMessaging"],
      "applications": {
      "gecko": {
        "id": "{443830f0-1fff-4f9a-aa1e-444bafbc7319}"
        }
        }
         }
**background.js**
            
      var NO_NATIVE_URL = "https://open-eid.github.io/chrome-token-  signing/missing.html";
      var DEVELOPER_URL = "https://github.com/open-eid/chrome-token-  signing/wiki/DeveloperTips";
      var NATIVE_HOST = "ee.ria.esteid";
      var K_SRC = "src";
      var K_ORIGIN = "origin";
      var K_NONCE = "nonce";
      var K_RESULT = "result";
      var K_TAB = "tab";
      var K_EXTENSION = "extension";
      // Stores the longrunning ports per tab
      // Used to route all request from a tab to the same host instance
      var ports = {};
      // Probed to false if host component is OK.
       var missing = true;
      console.log("Background page activated");
        // XXX: probe test, because connectNative() does not allow to check the presence
       // of native component for some reason
          typeof chrome.runtime.onStartup !== 'undefined' &&       chrome.runtime.onStartup.addListener(function() {
       // Also probed for in onInstalled()
      _testNativeComponent().then(function(result) {
    if (result === "ok") {
        missing = false;
    }
      });
         });
      // Force kill of native process
      // Becasue Port.disconnect() does not work
       function _killPort(tab) {
      if (tab in ports) {
       console.log("KILL " + tab);
        // Force killing with an empty message
        ports[tab].postMessage({});
     }
     }
       // Check if native implementation is OK resolves with "ok", "missing" or "forbidden"
      function _testNativeComponent() {
        return new Promise(function(resolve, reject) {
    chrome.runtime.sendNativeMessage(NATIVE_HOST, {}, function(response) {
        if (!response) {
            console.log("TEST: ERROR " + JSON.stringify(chrome.runtime.lastError));
            // Try to be smart and do some string matching
            var permissions = "Access to the specified native messaging host is forbidden.";
            var missing = "Specified native messaging host not found.";
            if (chrome.runtime.lastError.message === permissions) {
                resolve("forbidden")
            } else if (chrome.runtime.lastError.message === missing) {
                resolve("missing");
            } else {
                resolve("missing");
            }
        } else {
            console.log("TEST: " + JSON.stringify(response));
            if (response["result"] === "invalid_argument") {
                resolve("ok");
            } else {
                resolve("missing"); // TODO: something better here
            }
        }
          });
           });
           }
        // When extension is installed, check for native component or direct to helping page
      typeof chrome.runtime.onInstalled !== 'undefined' &&  chrome.runtime.onInstalled.addListener(function(details) {
      if (details.reason === "install" || details.reason === "update") {
    _testNativeComponent().then(function(result) {
            var url = null;
            if (result === "ok" && details.reason === "install") {
                // Also set the flag, onStartup() shall be called only
                // on next startup
                missing = false;
                // TODO: Add back HELLO page on install
                // once there is a nice tutorial
                 url = HELLO_URL;
            } else if (result === "forbidden") {
                url = DEVELOPER_URL;
            } else if (result === "missing"){
                url = NO_NATIVE_URL;
            }
            if (url) {
                chrome.tabs.create({'url': url + "?" + details.reason});
            }
             });
               }
                 });
       // When message is received from page send it to native
       chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
     if(sender.id !== chrome.runtime.id && sender.extensionId !==   chrome.runtime.id) {
    console.log('WARNING: Ignoring message not from our extension');
    // Not our extension, do nothing
    return;
    }
     if (sender.tab) {
    // Check if page is DONE and close the native component without doing anything else
    if (request["type"] === "DONE") {
        console.log("DONE " + sender.tab.id);
        if (sender.tab.id in ports) {
            // FIXME: would want to use Port.disconnect() here
            _killPort(sender.tab.id);
        }
    } else {
        request[K_TAB] = sender.tab.id;
        if (missing) {
            _testNativeComponent().then(function(result) {
                if (result === "ok") {
                    missing = false;
                    _forward(request);
                } else {
                    return _fail_with (request, "no_implementation");
                }
            });
        } else {
            // TODO: Check if the URL is in allowed list or not
            // Either way forward to native currently
            _forward(request);
        }
    }
    }
        });
    // Send the message back to the originating tab
    function _reply(tab, msg) {
    msg[K_SRC] = "background.js";
    msg[K_EXTENSION] = chrome.runtime.getManifest().version;
    chrome.tabs.sendMessage(tab, msg);
     }
     // Fail an incoming message if the underlying implementation is not
      // present
      function _fail_with(msg, result) {
     var resp = {};
     resp[K_NONCE] = msg[K_NONCE];
     resp[K_RESULT] = result;
    _reply(msg[K_TAB], resp);
      }
     // Forward a message to the native component
     function _forward(message) {
       var tabid = message[K_TAB];
     console.log("SEND " + tabid + ": " + JSON.stringify(message));
     // Open a port if necessary
        if(!ports[tabid]) {
     // For some reason there does not seem to be a way to detect missing components from longrunning ports
     // So we probe before opening a new port.
    console.log("OPEN " + tabid + ": " + NATIVE_HOST);
     // create a new port
    var port = chrome.runtime.connectNative(NATIVE_HOST);
    // XXX: does not indicate anything for some reason.
    if (!port) {
        console.log("OPEN ERROR: " + JSON.stringify(chrome.runtime.lastError));
    }
    port.onMessage.addListener(function(response) {
        if (response) {
            console.log("RECV "+tabid+": " + JSON.stringify(response));
            _reply(tabid, response);
        } else {
            console.log("ERROR "+tabid+": " + JSON.stringify(chrome.runtime.lastError));
            _fail_with(message, "technical_error");
        }
    });
    port.onDisconnect.addListener(function() {
        console.log("QUIT " + tabid);
        delete ports[tabid];
        // TODO: reject all pending promises for tab, if any
    });
    ports[tabid] = port;
    ports[tabid].postMessage(message);
    } else {
    // Port already open
    ports[tabid].postMessage(message);
     }
         }
**content.js**
  
      /*
     * Chrome token signing extension
     *
     * This library is free software; you can redistribute it and/or
     * modify it under the terms of the GNU Lesser General Public
     * License as published by the Free Software Foundation; either
     * version 2.1 of the License, or (at your option) any later version.
     *
     * This library is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     * Lesser General Public License for more details.
     *
     * You should have received a copy of the GNU Lesser General Public
     * License along with this library; if not, write to the Free Software
     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     */
     var inuse = false;
      // Forward the message from page.js to background.js
       window.addEventListener("message", function(event) {
    // We only accept messages from ourselves
    if (event.source !== window)
        return;
    // and forward to extension
    if (event.data.src && (event.data.src === "page.js")) {
        event.data["origin"] = location.origin;
        chrome.runtime.sendMessage(event.data, function(response) {});
        // Only add unload handler if extension has been used
        if (!inuse) {
            // close the native component if page unloads
            window.addEventListener("beforeunload", function(event) {
                chrome.runtime.sendMessage({src: 'page.js', type: 'DONE'});
            }, false);
            inuse = true;
        }
    }
      }, false);
    // post messages from extension to page
      chrome.runtime.onMessage.addListener(function(request, sender,  sendResponse) {
    window.postMessage(request, '*');
    });
    // inject content of page.js to the DOM of every page
    // FIXME: maybe not ?
    var s = document.createElement('script');
    s.type = 'text/javascript';
    s.innerHTML='// Promises \n\
    var _eid_promises = {}; \n\
    // Turn the incoming message from extension \n\
    // into pending Promise resolving \n\
     window.addEventListener("message", function(event) { \n\
    if(event.source !== window) return; \n\
    if(event.data.src && (event.data.src === "background.js")) { \n\
        console.log("Page received: "); \n\
        console.log(event.data); \n\
        // Get the promise \n\
        if(event.data.nonce) { \n\
            var p = _eid_promises[event.data.nonce]; \n\
            // resolve \n\
            if(event.data.result === "ok") { \n\
                if(event.data.signature !== undefined) { \n\
                    p.resolve({hex: event.data.signature}); \n\
                } else if(event.data.version !== undefined) { \n\
                    p.resolve(event.data.extension + "/" + event.data.version); \n\
                } else if(event.data.cert !== undefined) { \n\
                    p.resolve({hex: event.data.cert}); \n\
                } else { \n\
                    console.log("No idea how to handle message"); \n\
                    console.log(event.data); \n\
                } \n\
            } else { \n\
                // reject \n\
                p.reject(new Error(event.data.result)); \n\
            } \n\
            delete _eid_promises[event.data.nonce]; \n\
        } else { \n\
            console.log("No nonce in event msg"); \n\
        } \n\
    } \n\
    }, false); \n\
    \n\
    \n\
    function TokenSigning() { \n\
    function nonce() { \n\
        var val = ""; \n\
        var hex = "abcdefghijklmnopqrstuvwxyz0123456789"; \n\
        for(var i = 0; i < 16; i++) val += hex.charAt(Math.floor(Math.random() * hex.length)); \n\
        return val; \n\
    } \n\
     \n\
    function messagePromise(msg) { \n\
        return new Promise(function(resolve, reject) { \n\
            // amend with necessary metadata \n\
            msg["nonce"] = nonce(); \n\
            msg["src"] = "page.js"; \n\
            // send message \n\
            window.postMessage(msg, "*"); \n\
            // and store promise callbacks \n\
            _eid_promises[msg.nonce] = { \n\
                resolve: resolve, \n\
                reject: reject \n\
            }; \n\
        }); \n\
         } \n\
    this.getCertificate = function(options) { \n\
        var msg = {type: "CERT", lang: options.lang}; \n\
        console.log("getCertificate()"); \n\
        return messagePromise(msg); \n\
    }; \n\
    this.sign = function(cert, hash, options) { \n\
        var msg = {type: "SIGN", cert: cert.hex, hash: hash.hex, hashtype: hash.type, lang: options.lang}; \n\
        console.log("sign()"); \n\
        return messagePromise(msg); \n\
    }; \n\
    this.getVersion = function() { \n\
        console.log("getVersion()"); \n\
        return messagePromise({ \n\
            type: "VERSION" \n\
        }); \n\
    }; \n\
    }';
         (document.head || document.documentElement).appendChild(s);
**page.js**
     /*
      * Chrome token signing extension
      *
      * This library is free software; you can redistribute it and/or
      * modify it under the terms of the GNU Lesser General Public
      * License as published by the Free Software Foundation; either
      * version 2.1 of the License, or (at your option) any later version.
      *
      * This library is distributed in the hope that it will be useful,
      * but WITHOUT ANY WARRANTY; without even the implied warranty of
      * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      * Lesser General Public License for more details.
      *
      * You should have received a copy of the GNU Lesser General Public
      * License along with this library; if not, write to the Free Software
      * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
      */
      // Promises
      var _eid_promises = {};
      // Turn the incoming message from extension
      // into pending Promise resolving
      window.addEventListener("message", function(event) {
    if(event.source !== window) return;
    if(event.data.src && (event.data.src === "background.js")) {
        console.log("Page received: ");
        console.log(event.data);
        // Get the promise
        if(event.data.nonce) {
            var p = _eid_promises[event.data.nonce];
            // resolve
            if(event.data.result === "ok") {
                if(event.data.signature !== undefined) {
                    p.resolve({hex: event.data.signature});
                } else if(event.data.version !== undefined) {
                    p.resolve(event.data.extension + "/" + event.data.version);
                } else if(event.data.cert !== undefined) {
                    p.resolve({hex: event.data.cert});
                } else {
                    console.log("No idea how to handle message");
                    console.log(event.data);
                }
            } else {
                // reject
                p.reject(new Error(event.data.result));
            }
            delete _eid_promises[event.data.nonce];
        } else {
            console.log("No nonce in event msg");
        }
    }
      }, false);
    function TokenSigning() {
    function nonce() {
        var val = "";
        var hex = "abcdefghijklmnopqrstuvwxyz0123456789";
        for(var i = 0; i < 16; i++) val += hex.charAt(Math.floor(Math.random() * hex.length));
        return val;
    }
    function messagePromise(msg) {
        return new Promise(function(resolve, reject) {
            // amend with necessary metadata
            msg["nonce"] = nonce();
            msg["src"] = "page.js";
            // send message
            window.postMessage(msg, "*");
            // and store promise callbacks
            _eid_promises[msg.nonce] = {
                resolve: resolve,
                reject: reject
            };
        });
    }
    this.getCertificate = function(options) {
        var msg = {type: "CERT", lang: options.lang};
        console.log("getCertificate()");
        return messagePromise(msg);
    };
    this.sign = function(cert, hash, options) {
        var msg = {type: "SIGN", cert: cert.hex, hash: hash.hex, hashtype: hash.type, lang: options.lang};
        console.log("sign()");
        return messagePromise(msg);
    };
    this.getVersion = function() {
        console.log("getVersion()");
        return messagePromise({
            type: "VERSION"
        });
    };
      }
when I run the extension I have:
[![enter image description here][1]][1]

And when I whrite somethig or click 2 times at Enter touch or close the cmd I have this:[![enter image description here][2]][2]

when I run the extension I have:
[![enter image description here][1]][1]

And when I whrite something or click 2 times at Enter touch or close the cmd I have this:[![enter image description here][2]][2]
Reply all
Reply to author
Forward
0 new messages