diff --git a/resources/static/common/js/models/interaction_data.js b/resources/static/common/js/models/interaction_data.js index c1df7522cdaea83ba6545fd4c8b3eec39d7ded75..d40da5139bb7ea9923e14662c365911297b6f6a7 100644 --- a/resources/static/common/js/models/interaction_data.js +++ b/resources/static/common/js/models/interaction_data.js @@ -22,7 +22,8 @@ BrowserID.Models.InteractionData = (function() { 'number_sites_remembered', 'orphaned', 'new_account', - 'email_type' + 'email_type', + 'rp_api' ]; diff --git a/resources/static/dialog/js/misc/internal_api.js b/resources/static/dialog/js/misc/internal_api.js index 5a5e644c0dbd2cd6c1038c7ede4c8f937d25cf1f..ffc1e91ee90664b2f2bb5f66ef59384f385afb0b 100644 --- a/resources/static/dialog/js/misc/internal_api.js +++ b/resources/static/dialog/js/misc/internal_api.js @@ -89,6 +89,7 @@ // options block directly to the dialog. var controller = moduleManager.getRunningModule("dialog"); if(controller) { + options.rp_api = "internal"; controller.get(origin, options, complete, complete); } else { diff --git a/resources/static/dialog/js/modules/dialog.js b/resources/static/dialog/js/modules/dialog.js index 6566944dd2739f4fe43e9d56ad1aa8765189e436..00d6e8f8b6f27f888a3b8555a779f1e4ae94792a 100644 --- a/resources/static/dialog/js/modules/dialog.js +++ b/resources/static/dialog/js/modules/dialog.js @@ -110,6 +110,20 @@ BrowserID.Modules.Dialog = (function() { throw "must be an absolute path: (" + path + ")"; } + function validateRPAPI(rpAPI) { + var VALID_RP_API_VALUES = [ + "watch_without_onready", + "watch_with_onready", + "get", + "getVerifiedEmail", + "internal" + ]; + + if (_.indexOf(VALID_RP_API_VALUES, rpAPI) === -1) { + throw "invalid value for rp_api: " + rpAPI; + } + } + var Dialog = bid.Modules.PageModule.extend({ start: function(options) { var self=this; @@ -170,6 +184,13 @@ BrowserID.Modules.Dialog = (function() { // verify params try { + var rpAPI = paramsFromRP.rp_api; + if (rpAPI) { + // throws if an invalid rp_api value + validateRPAPI(rpAPI); + self.publish("kpi_data", { rp_api: rpAPI }); + } + if (paramsFromRP.requiredEmail) { helpers.log("requiredEmail has been deprecated"); } diff --git a/resources/static/include_js/include.js b/resources/static/include_js/include.js index 3b775cca607c2274b5016b0c8d5b8ac0cd07c421..4fd51d0e0e0a670c949bc0c8055fe42f3a6f30ed 100644 --- a/resources/static/include_js/include.js +++ b/resources/static/include_js/include.js @@ -1125,6 +1125,17 @@ _open_hidden_iframe(); } + var api_called; + function getRPAPI() { + var rp_api = api_called; + if (rp_api === "request") { + if (observers.ready) rp_api = "watch_with_onready"; + else rp_api = "watch_without_onready"; + } + + return rp_api; + } + function internalRequest(options) { checkDeprecated(options, "requiredEmail"); checkRenamed(options, "tosURL", "termsOfService"); @@ -1138,6 +1149,11 @@ warn("privacyPolicy ignored unless termsOfService also defined"); } + options.rp_api = getRPAPI(); + // reset the api_called in case the site implementor changes which api + // method called the next time around. + api_called = null; + // focus an existing window if (w) { try { @@ -1216,6 +1232,7 @@ throw new Error("all navigator.id calls must be made on the navigator.id object"); options = options || {}; checkCompat(false); + api_called = "request"; // returnTo is used for post-email-verification redirect if (!options.returnTo) options.returnTo = document.location.pathname; return internalRequest(options); @@ -1251,7 +1268,8 @@ opts.tosURL = passedOptions.tosURL || undefined; opts.siteName = passedOptions.siteName || undefined; opts.siteLogo = passedOptions.siteLogo || undefined; - + // api_called could have been set to getVerifiedEmail already + api_called = api_called || "get"; if (checkDeprecated(passedOptions, "silent")) { // Silent has been deprecated, do nothing. Placing the check here // prevents the callback from being called twice, once with null and @@ -1283,6 +1301,7 @@ getVerifiedEmail: function(callback) { warn("navigator.id.getVerifiedEmail has been deprecated"); checkCompat(true); + api_called = "getVerifiedEmail"; navigator.id.get(callback); }, // required for forwards compatibility with native implementations diff --git a/resources/static/test/cases/common/js/models/interaction_data.js b/resources/static/test/cases/common/js/models/interaction_data.js index deab52638ea8db94cd15649f2c3410dd09523e84..c0d79f4f4a44fdcdfb0282f0d5e77207ecafd251 100644 --- a/resources/static/test/cases/common/js/models/interaction_data.js +++ b/resources/static/test/cases/common/js/models/interaction_data.js @@ -100,7 +100,8 @@ number_sites_remembered: 3, orphaned: false, new_account: true, - email_type: "assertion" + email_type: "assertion", + rp_api: "watch_without_onready" }); model.stageCurrent(); @@ -123,7 +124,8 @@ number_sites_remembered: 3, orphaned: false, new_account: true, - email_type: "assertion" + email_type: "assertion", + rp_api: "watch_without_onready" }); testHelpers.testUndefined(mostRecentSessionData.local_timestamp, "non-whitelisted valued stripped"); diff --git a/resources/static/test/cases/dialog/js/modules/dialog.js b/resources/static/test/cases/dialog/js/modules/dialog.js index 5bb1d19f4636ed9c45f2213713bed1b97efd0a3b..052f05da04812b546db6305620948d3f5df232f7 100644 --- a/resources/static/test/cases/dialog/js/modules/dialog.js +++ b/resources/static/test/cases/dialog/js/modules/dialog.js @@ -68,6 +68,35 @@ controller.start(options); } + function testMessageNotExpected(msg) { + mediator.subscribe(msg, function(msg, info) { + ok(false, "unexpected message: " + msg); + }); + } + + function testExpectGetFailure(options, expectedErrorMessage) { + _.extend(options, { + ready: function() { + testMessageNotExpected("kpi_data"); + testMessageNotExpected("start"); + + var retval = controller.get(HTTPS_TEST_DOMAIN, options); + + if (expectedErrorMessage) { + equal(retval, expectedErrorMessage, "expected error: " + expectedErrorMessage); + } + else { + ok(retval, "error message returned"); + } + + testErrorVisible(); + start(); + } + }); + createController(options); + } + + module("dialog/js/modules/dialog", { setup: function() { winMock = new WinMock(); @@ -620,5 +649,26 @@ } }); }); + + asyncTest("get with valid rp_api - allowed", function() { + createController({ + ready: function() { + mediator.subscribe("kpi_data", function(msg, info) { + equal(info.rp_api, "get"); + start(); + }); + + controller.get(HTTPS_TEST_DOMAIN, { + rp_api: "get" + }); + } + }); + }); + + asyncTest("get with invalid rp_api - not allowed", function() { + testExpectGetFailure({ + rp_api: "invalid_value" + }, "invalid value for rp_api: invalid_value"); + }); }());