diff --git a/example/index.html b/example/index.html index 6c822dde4f7cacec015d2ebad3ced592181be7b3..3f50bea7a0de7c89f24147596eafbcbd6e074878 100644 --- a/example/index.html +++ b/example/index.html @@ -124,7 +124,7 @@ navigator.id.get(function(assertion) { $("#oAssertion").text(assertion); checkAssertion(assertion); }; - }); + }, {persistent: true}); }); $("#logout").click(function(event) { diff --git a/resources/static/dialog/controllers/dialog_controller.js b/resources/static/dialog/controllers/dialog_controller.js index 3386e7f0b4671ed661b1be3eba1a50907186c72f..c69e8a8e172ffbc1adc4105611b7eb4270fe57fc 100644 --- a/resources/static/dialog/controllers/dialog_controller.js +++ b/resources/static/dialog/controllers/dialog_controller.js @@ -92,10 +92,19 @@ }, getVerifiedEmail: function(origin_url, onsuccess, onerror) { + return this.get(origin_url, {}, onsuccess, onerror); + }, + + get: function(origin_url, params, onsuccess, onerror) { var self=this; self.onsuccess = onsuccess; self.onerror = onerror; - self.allowPersistent = true; // XXX We need to get this info from somewhere. + + if (typeof(params) == 'undefined') { + params = {}; + } + + self.allowPersistent = (params.persistent == true); if('onLine' in navigator && !navigator.onLine) { self.doOffline(); diff --git a/resources/static/dialog/resources/channel.js b/resources/static/dialog/resources/channel.js index 68caa5235e6c9e8edd8461fbd112c09f756ac2c5..455cd6dd0018ff29bec16877df218794be53fe3b 100644 --- a/resources/static/dialog/resources/channel.js +++ b/resources/static/dialog/resources/channel.js @@ -74,22 +74,24 @@ // (has window.opener) as well as whether the relay function exists. // If these conditions are not met, then print an appropriate message. - function onsuccess(rv) { - onCompleteCallback(rv, null); - } - - function onerror(error) { - onCompleteCallback(null, error); - } - + var REGISTERED_METHODS = { + 'get': function(origin, params, onsuccess, onerror) { + // check for old controller methods + // FIXME KILL THIS SOON + if (controller.get) { + return controller.get(origin, params, onsuccess, onerror); + } else { + return controller.getVerifiedEmail(origin, onsuccess, onerror); + } + } + }; + // The relay frame will give us the origin and a function to call when // dialog processing is complete. var frameWindow = getRelayWindow(); + if (frameWindow) { - frameWindow.BrowserID.Relay.registerClient(function(origin, onComplete) { - onCompleteCallback = onComplete; - controller.getVerifiedEmail(origin, onsuccess, onerror); - }); + frameWindow.BrowserID.Relay.registerClient(REGISTERED_METHODS); } else { throw "relay frame not found"; diff --git a/resources/static/include.js b/resources/static/include.js index 3fb15233716286dad61c72ae74603f78c9fe3872..c64c128c037eab4339ebc935164a0a62c39124aa 100644 --- a/resources/static/include.js +++ b/resources/static/include.js @@ -756,7 +756,8 @@ // we now have the relay iframe and channel already // we just message it. relay_chan.call({ - method: "getVerifiedEmail", + method: "get", + params: options, success: function(rv) { if (callback) { // return the string representation of the JWT, the client is responsible for unpacking it. diff --git a/resources/static/relay/relay.js b/resources/static/relay/relay.js index d919aa8ff2bd51110e6f76a3d82ec75ce9f52b57..28b6441e74171c55959af7f58a7636a3d9a9b4cd 100644 --- a/resources/static/relay/relay.js +++ b/resources/static/relay/relay.js @@ -46,15 +46,15 @@ }; BrowserID.Relay = (function() { - var transaction, - origin, - channel = Channel, - win = window, - registerCB; + var channel = Channel, + win = window; + // captured method calls + var METHODS = ["get"]; + var registeredMethods, pendingCall; function init(options) { - origin = transaction = registerCB = undefined; + registeredMethods = pendingCall = undefined; if(options.window) { win = options.window; @@ -65,6 +65,46 @@ } } + // try to forward the transaction, otherwise + // stash it away for later. Assumes only one + // transaction at a time for now. + function forwardCall(methodCall) { + // forwarding pending call? + if (!methodCall) { + methodCall = pendingCall; + pendingCall = null; + } + + // no call still? + if (!methodCall) + return; + + // ready to go? + if (!registeredMethods) { + // no, stash it for later + pendingCall = methodCall; + return; + } + + // ok, we can make the call + var method = methodCall.method; + var transaction = methodCall.transaction; + var origin = transaction.origin; + var params = methodCall.params; + + // have the call? + if (registeredMethods[method]) { + registeredMethods[method]( + origin, params, + function(result) { + transaction.complete(result); + }, function(error) { + transaction.error(error, getVerboseMessage(error)); + } + ); + } + } + function open() { var rpc = channel.build({ window: win, @@ -72,66 +112,34 @@ scope: "mozid" }); - rpc.bind("getVerifiedEmail", function(trans, s) { - trans.delayReturn(true); - origin = trans.origin; - transaction = trans; - - // If the client has run early and already registered its registration - // callback, call it now. - if (registerCB) { - registerCB(origin, completionCB); - } - }); - } - - function registerClient(callback) { - // If the origin is ready, call the callback immediately. - if (origin) { - callback(origin, completionCB); - } - else { - registerCB = callback; + for (var i=0; i<METHODS.length; i++) { + var method = METHODS[i]; + rpc.bind(method, function(trans, params) { + trans.delayReturn(true); + forwardCall({method: method, transaction: trans, params: params}); + }); } } - function errorOut(code) { - function getVerboseMessage(code) { - var msgs = { - "canceled": "user canceled selection", - "notImplemented": "the user tried to invoke behavior that's not yet implemented", - "serverError": "a technical problem was encountered while trying to communicate with BrowserID servers." - }; - var msg = msgs[code]; - if (!msg) { - alert("need verbose message for " + code); - msg = "unknown error"; - } - return msg; - } - transaction.error(code, getVerboseMessage(code)); + function registerClient(methods) { + registeredMethods = methods; + forwardCall(); } - /** - * The client calls this to relay a message back to the RP whenever it is - * complete. This function is passed to the client when the client does - * its registerClient. - */ - function completionCB(status, error) { - if(error) { - errorOut(error); - } - else { - try { - transaction.complete(status); - } catch(e) { - // The relay function is called a second time after the - // initial success, when the window is closing. - } - } + function getVerboseMessage(code) { + var msgs = { + "canceled": "user canceled selection", + "notImplemented": "the user tried to invoke behavior that's not yet implemented", + "serverError": "a technical problem was encountered while trying to communicate with BrowserID servers." + }; + var msg = msgs[code]; + if (!msg) { + alert("need verbose message for " + code); + msg = "unknown error"; + } + return msg; } - - + return { /** * Initialize the relay. diff --git a/resources/static/test/qunit/relay/relay_unit_test.js b/resources/static/test/qunit/relay/relay_unit_test.js index 566c5a90fc9dee8a9662ffe2c27d1b97e60338c6..58ea7e93ddfa4dd79e3fcd82004c5e2187afb163 100644 --- a/resources/static/test/qunit/relay/relay_unit_test.js +++ b/resources/static/test/qunit/relay/relay_unit_test.js @@ -56,7 +56,7 @@ steal.plugins("jquery").then("/lib/jschannel", "/relay/relay", function() { }, // Mock in the receiving of the RPC call from the RP. - receiveGetVerifiedEmail: function() { + receiveGet: function() { // cb is the mock callback that is passed to Channel.bind channelMock.cb({ origin: "Origin", @@ -102,20 +102,20 @@ steal.plugins("jquery").then("/lib/jschannel", "/relay/relay", function() { /** * Check to make sure the correct message is bound */ - equal(channelMock.bindMessage, "getVerifiedEmail", "bound to getVerifiedEmail"); + equal(channelMock.bindMessage, "get", "bound to get"); }); - test("channel.getVerifiedEmail before registerDialog", function() { + test("channel.get before registerDialog", function() { relay.open(); - channelMock.receiveGetVerifiedEmail(); + channelMock.receiveGet(); - relay.registerClient(function(origin, completeCB) { + relay.registerClient({'get': function(origin, params, completeCB) { equal(origin, "Origin", "Origin set correctly"); equal(typeof completeCB, "function", "A completion callback is specified"); start(); - }); + }}); stop(); }); @@ -123,14 +123,14 @@ steal.plugins("jquery").then("/lib/jschannel", "/relay/relay", function() { test("registerDialog before channel.getVerifiedEmail", function() { relay.open(); - relay.registerClient(function(origin, completeCB) { + relay.registerClient({'get': function(origin, params, completeCB) { equal(origin, "Origin", "Origin set correctly"); equal(typeof completeCB, "function", "A completion callback is specified"); start(); - }); + }}); - channelMock.receiveGetVerifiedEmail(); + channelMock.receiveGet(); stop(); }); @@ -138,13 +138,13 @@ steal.plugins("jquery").then("/lib/jschannel", "/relay/relay", function() { test("calling the completeCB with assertion", function() { relay.open(); - channelMock.receiveGetVerifiedEmail(); + channelMock.receiveGet(); - relay.registerClient(function(origin, completeCB) { + relay.registerClient({'get': function(origin, params, completeCB) { completeCB("assertion", null); equal(channelMock.status, "assertion", "channel gets the correct assertion"); start(); - }); + }}); stop(); }); @@ -153,30 +153,30 @@ steal.plugins("jquery").then("/lib/jschannel", "/relay/relay", function() { test("calling the completeCB with null assertion", function() { relay.open(); - channelMock.receiveGetVerifiedEmail(); + channelMock.receiveGet(); - relay.registerClient(function(origin, completeCB) { + relay.registerClient({'get': function(origin, params, completeCB) { completeCB(null, null); strictEqual(channelMock.status, null, "channel gets the null assertion"); start(); - }); + }}); stop(); }); - test("calling the completeCB with error", function() { + test("calling the onerror callback", function() { relay.open(); - channelMock.receiveGetVerifiedEmail(); + channelMock.receiveGet(); - relay.registerClient(function(origin, completeCB) { - completeCB(null, "canceled"); + relay.registerClient({'get': function(origin, params, onsuccess, onerror) { + onerror("canceled"); equal(channelMock.errorCode, "canceled", "error callback called with error code"); ok(channelMock.verboseError, "verbose error code set"); start(); - }); + }}); stop(); }); diff --git a/resources/static/test/qunit/resources/channel_unit_test.js b/resources/static/test/qunit/resources/channel_unit_test.js index 94c2df40addc07c35e08a4c5371f7bd23c6e7d95..58f63786ea068ba6a76b404ea0b2ed8a9622212e 100644 --- a/resources/static/test/qunit/resources/channel_unit_test.js +++ b/resources/static/test/qunit/resources/channel_unit_test.js @@ -54,10 +54,11 @@ steal.then("/dialog/resources/channel", function() { browserid_relay_1234: { BrowserID: { Relay: { - registerClient: function(callback) { + registerClient: function(methods) { // mock of the registerClient function in the BrowserID.Channel. - callback("origin", function onComplete(success, error) { + methods["get"]("foo.com", {}, function onComplete(success) { winMock.success = success; + }, function onerror(error) { winMock.error = error; }); } @@ -90,7 +91,6 @@ steal.then("/dialog/resources/channel", function() { navigator: navMock }); - channel.open({ getVerifiedEmail: function(origin, onsuccess, onerror) { onsuccess("assertion");