From 5065f1caaa97c377af72b6e3f37025777ccad271 Mon Sep 17 00:00:00 2001 From: Mark Donnelly Date: Thu, 16 Oct 2014 15:53:26 -0400 Subject: [PATCH] Rework the injected script: * Make it object-based * Functions now take hashes (like jQuery) instead of parameter lists * There is now a single response dispatcher instead of writing one per GSS method call * Implement the gss_error C-macro as a JavaScript function * Split the callback into two callbacks: success and error. * Add checking for whether the message returned from the C code has a matching nonce/method tuple. --- chrome/app/navigator.gss.js | 173 ++++++++++++++++++++++++++++++-------------- chrome/test/test.html | 32 +++++--- 2 files changed, 139 insertions(+), 66 deletions(-) diff --git a/chrome/app/navigator.gss.js b/chrome/app/navigator.gss.js index b011894..7af3b44 100644 --- a/chrome/app/navigator.gss.js +++ b/chrome/app/navigator.gss.js @@ -1,68 +1,133 @@ -console.log('Loading navigator.gss.js - #5'); +console.log('Loading navigator.gss.js - #7'); /* This file gets injected into the web page verbatim */ -navigator.gss_callbacks = {}; -/* -navigator.generateNonce = function() { - // TODO: Make sure that we don't have a collision! - // Random integer in the range [0..(2^32-1)] - return Math.floor(Math.random() * ( 4294967295 )) ; -} -*/ -navigator.gss_import_name = function(name, mech, callbackFn, appTag){ - var nonce = navigator.generateNonce(); - navigator.gss_callbacks[nonce] = callbackFn; - - /* Listen for a message back from the content script */ - window.addEventListener( - "message", - function(event) - { - var app_tag; - var name; - var callback; +var GSSEap = (function () + { + function GSSEap(config) + { + // Public attributes + this.version = "0.0.1"; + this.callbacks = {}; + this.methods = {}; + this.appTag = config.appTag || ""; + this.error = config.error || function (major, minor, error, appTag) { + console.warn(error); + }; + window.addEventListener("message", this.dispatch_responses.bind(this)); + } + GSSEap.prototype.dispatch_responses = function (event) + { + var method; var nonce; - - if (event.data.method != "gss_import_name" || - (typeof(event.data.return_values) == "undefined") ) + var callback; + var app_tag; + + /* This message is destined for us only if all the following apply: + * - The data.method_name is one of the methods implemented by this + * object + * - data.return_values exists + * - data.cookies exists + * - One of my callbacks matches the nonce in data.cookies.navigator_gss_tag + * - One of my methods matches the nonce in data.cookies.navigator_gss_tag + * and that method matches data.method + */ + method = event.data.method; + if ( + (method != "gss_import_name") || + ("undefined" == typeof (event.data.return_values)) || + ("undefined" == typeof (event.data.cookies))) { - return; + return; } - - var nonce = event.data.cookies.navigator_gss_tag; + + nonce = event.data.cookies.navigator_gss_tag; event.data.cookies.navigator_gss_tag = undefined; - callback = navigator.gss_callbacks[nonce]; - navigator.gss_callbacks[nonce] = undefined; - - // Extract the data from the returned JSON - name = event.data.return_values.gss_name; + callback = this.callbacks[nonce]; + if ("undefined" == typeof (callback) || this.methods[nonce] != method) { + return; + } + + // We now know that this message is for us! + this.callbacks[nonce] = undefined; app_tag = event.data.cookies.app_tag; - major = event.data.return_values.major_status; - minor = event.data.return_values.minor_status; - - // Invoke the callback with the extracted data - callback(name, major, minor, app_tag); - } - ); - /* Send a message off to the extension that we want to - * call gss_import_name - */ - window.postMessage({ - "method":"gss_import_name", - "arguments": - { - "input_name": name, - "input_name_type": mech - }, - "cookies": + if (this.gss_error(event.data.return_values.major_status)) + { + var errMsg = "Error during " + method + ": " + + "Major status message: " + + event.data.return_values.errors.major_status_message + + "; Minor status message: " + + event.data.return_values.errors.minor_status_message; + this.error( + event.data.return_values.major_status, + event.data.return_values.minor_status, + errMsg, + app_tag); + } else { + if ("gss_import_name" == method) + { callback(event.data.return_values.gss_name, app_tag); } + // if( "gss_X" == method ) { callback(event.data.return_values.x, app_tag);} + } + }; + + GSSEap.prototype.import_name = function (params) + { + /* variables */ + var nonce; + var name = params.name; + var name_type = params.name_type || "{1 2 840 113554 1 2 1 4 }"; + var callback = params.success; + var error = params.error || this.error; + var app_tag = params.app_tag || this.appTag; + + /* Erorr checking */ + // Call an error if we don't have the required parameters. + // - name + // - success() + if ( "undefined" == typeof(name) || + "undefined" == typeof(success) ) { - "navigator_gss_tag": nonce, - "app_tag": appTag + this.error(-1, -1, + "import_name called missing either name or success callback" + ); + return; } - }, "*"); + + nonce = navigator.generateNonce(); + this.callbacks[nonce] = callback; + this.methods[nonce] = "gss_import_name"; + window.postMessage({ + "method":"gss_import_name", + "arguments": + { + "input_name": name, + "input_name_type": name_type + }, + "cookies": + { + "navigator_gss_tag": nonce, + "app_tag": app_tag + } + }, "*"); + + }; + + GSSEap.prototype.gss_error = function (major) + { + var callingMask; + var routineMask; + var mask; + + callingMask = 377 << 24; + routineMask = 377 << 16; + mask = callingMask | routineMask; + + return (0 != (major & mask)); + }; + return GSSEap; +})(); -}; +navigator.gss_eap = GSSEap; diff --git a/chrome/test/test.html b/chrome/test/test.html index 650a065..f5cb715 100644 --- a/chrome/test/test.html +++ b/chrome/test/test.html @@ -8,22 +8,30 @@ } function doImportName() { - var ret = navigator.gss_import_name( - document.getElementById('import_name_name').value, - document.getElementById('import_name_mech').value, - 'nonce', - function(name, nonce, major, minor) { - report('GSS imported name: ' + name); - report('GSS imported nonce: ' + nonce); - report('GSS imported major status: ' + major); - report('GSS imported minor status: ' + minor); - } - ); + var gss = new navigator.gss({ + appTag: "TestApp", + error: function(major, minor, errMsg, appTag) + { + report("Error"); + report("Major: " + major + "; Minor: " + minor); + report("
" + errMsg + "
"); + report("appTag: " + appTag); + } + }); + gss.import_name({ + name: document.getElementById('import_name_name').value, + name_type: document.getElementById('import_name_mech').value, + success: function(name, appTag) { + report("GSS imported name: " + name); + report("appTag: " + appTag); + } + }); } document.addEventListener('DOMContentLoaded', function () { document.getElementById('import_name').addEventListener( - 'click', doImportName); + 'click', doImportName + ); console.log('DOMContentLoaded.'); }); -- 2.1.4