diff --git a/resources/static/common/css/style.css b/resources/static/common/css/style.css index c29a95bffb2b1b82c387529fbe41b5b656a71e2f..dfd8cd6d3bfbeb86b3bf7b3814a612276db5b020 100644 --- a/resources/static/common/css/style.css +++ b/resources/static/common/css/style.css @@ -415,6 +415,20 @@ footer .help { color: #333; } +.submit { + margin-top: 10px; + line-height: 14px; +} + +.submit > p { + margin-top: 10px; +} + +.tospp { + line-height: 1.2; +} + + #showDevelopment { position: absolute; top: 0; diff --git a/resources/static/common/js/lib/dom-jquery.js b/resources/static/common/js/lib/dom-jquery.js index 6438fec068304658384f58d1e86e2c0c1c309dcb..0faeb1ccc0db906754e3461716bbfd2b8c3bd1dc 100644 --- a/resources/static/common/js/lib/dom-jquery.js +++ b/resources/static/common/js/lib/dom-jquery.js @@ -313,7 +313,7 @@ BrowserID.DOM = ( function() { }, /** - * Show an element/elements + * Show an element * @method show * @param {selector || element} elementToShow */ @@ -322,15 +322,13 @@ BrowserID.DOM = ( function() { }, /** - * Hide an element/elements + * Hide an element * @method hide * @param {selector || element} elementToHide */ hide: function( elementToHide ) { return jQuery( elementToHide ).hide(); } - - }; function isValBased( target ) { diff --git a/resources/static/common/js/modules/page_module.js b/resources/static/common/js/modules/page_module.js index 36aa78c7c29a72aae98d2d6552b08100467c54b2..2afa4634e9e26725e67933e5c2ab0cd20148162e 100644 --- a/resources/static/common/js/modules/page_module.js +++ b/resources/static/common/js/modules/page_module.js @@ -119,6 +119,8 @@ BrowserID.Modules.PageModule = (function() { self.hideError(); self.hideDelay(); + dom.removeClass("body", "rptospp"); + screens.form.show(template, data); dom.focus("input:visible:not(:disabled):eq(0)"); // XXX jQuery. bleck. diff --git a/resources/static/common/js/user.js b/resources/static/common/js/user.js index f39d3935d9bdae5f9bcdb3cf966f1212769c2318..95b7c0893c34fd7d36fab3942fa6bc589a6ab36f 100644 --- a/resources/static/common/js/user.js +++ b/resources/static/common/js/user.js @@ -264,6 +264,14 @@ BrowserID.User = (function() { return origin; }, + setOriginEmail: function(email) { + storage.site.set(origin, "email", email); + }, + + getOriginEmail: function() { + return storage.site.get(origin, "email"); + }, + /** * Get the hostname for the set origin * @method getHostname diff --git a/resources/static/dialog/css/style.css b/resources/static/dialog/css/style.css index 5edef21780867c23f7855a6b5981cb36fc3e1cd7..fc402c0884959919c6f8c50a1913755e6d201f11 100644 --- a/resources/static/dialog/css/style.css +++ b/resources/static/dialog/css/style.css @@ -284,24 +284,24 @@ section > .contents { #favicon img { display: block; margin: 0 auto; - max-height: 128px; - max-width: 128px; + max-height: 100px; + max-width: 100px; } #favicon h2, #favicon h3 { white-space: nowrap; text-overflow: ellipsis; - line-height: 1.3; /* the 1.3em is to keep y, g, j, etc from having their bottoms chopped off */ + line-height: 1.2em; /* the 1.2em is to keep y, g, j, etc from having their bottoms chopped off */ overflow: hidden; + margin: 10px 0 0 0; } #favicon h2 { - margin: 10px 0 0 0; + font-size: 28px; } #favicon h3 { - font-size: 19px; - margin-top: 0; + font-size: 14px; } #favicon .vertical { @@ -379,19 +379,24 @@ div#required_email { } .submit { - margin-top: 10px; color: #333; font-size: 11px; - line-height: 14px; } -.submit > p { - margin-top: 10px; -} .tospp { - color: #787878; - clear: right; + font-size: 11px; + color: #787878; +} + +#rptospp { + display: none; + margin: 10px auto; + max-width: 280px; +} + +.rptospp #rptospp { + display: block; } a.emphasize { @@ -430,6 +435,7 @@ a.emphasize:active { #back { color: #000; border-bottom: 1px dotted; + font-weight: normal; } .submit > button { diff --git a/resources/static/dialog/js/misc/helpers.js b/resources/static/dialog/js/misc/helpers.js index af595a5338e5dba843f45572329d1c648496daf7..23831652fef2a4e8c5807a1f89b2d7b354faf4da 100644 --- a/resources/static/dialog/js/misc/helpers.js +++ b/resources/static/dialog/js/misc/helpers.js @@ -11,7 +11,8 @@ complete = helpers.complete, user = bid.User, tooltip = bid.Tooltip, - errors = bid.Errors; + errors = bid.Errors, + dom = bid.DOM; function animateClose(callback) { var body = $("body"), @@ -135,6 +136,10 @@ }, self.getErrorDialog(errors.addEmail, callback)); } + function showRPTosPP() { + dom.addClass("body", "rptospp"); + } + helpers.Dialog = helpers.Dialog || {}; helpers.extend(helpers.Dialog, { @@ -145,7 +150,8 @@ addSecondaryEmail: addSecondaryEmail, resetPassword: resetPassword, cancelEvent: helpers.cancelEvent, - animateClose: animateClose + animateClose: animateClose, + showRPTosPP: showRPTosPP }); }()); diff --git a/resources/static/dialog/js/misc/state.js b/resources/static/dialog/js/misc/state.js index 032bd85f683c1f9a9698fcecf87af9a9ad2c5af5..dc228b145d1713516c67e615e9d8307266943cf7 100644 --- a/resources/static/dialog/js/misc/state.js +++ b/resources/static/dialog/js/misc/state.js @@ -1,9 +1,11 @@ -/*jshint browser:true, jQuery: true, forin: true, laxbreak:true */ +/*jshint browser:true, jquery: true, forin: true, laxbreak:true */ /*global BrowserID: true */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ BrowserID.State = (function() { + "use strict"; + var bid = BrowserID, storage = bid.Storage, network = bid.Network, @@ -42,8 +44,7 @@ BrowserID.State = (function() { handleState("start", function(msg, info) { self.hostname = info.hostname; - self.privacyURL = info.privacyURL; - self.tosURL = info.tosURL; + self.siteTOSPP = !!(info.privacyPolicy && info.termsOfService); requiredEmail = info.requiredEmail; startAction(false, "doRPInfo", info); @@ -80,8 +81,10 @@ BrowserID.State = (function() { self.email = requiredEmail; startAction("doAuthenticateWithRequiredEmail", { email: requiredEmail, - privacyURL: self.privacyURL, - tosURL: self.tosURL + // New users are handled by either the "new_user" flow or the + // "primary_user" flow. The Persona TOS/PP will be shown to users in + // these stages. + siteTOSPP: self.siteTOSPP && !user.getOriginEmail() }); } else if (authenticated) { @@ -92,8 +95,7 @@ BrowserID.State = (function() { }); handleState("authenticate", function(msg, info) { - info.privacyURL = self.privacyURL; - info.tosURL = self.tosURL; + info.siteTOSPP = self.siteTOSPP; startAction("doAuthenticate", info); }); @@ -104,9 +106,23 @@ BrowserID.State = (function() { // know when we are losing users due to the email verification. mediator.publish("kpi_data", { new_account: true }); - // cancel is disabled if the user is doing the initial password set - // for a requiredEmail. - info.cancelable = !requiredEmail; + _.extend(info, { + // cancel is disabled if the user is doing the initial password set + // for a requiredEmail. + cancelable: !requiredEmail, + + // New users in the requiredEmail flow are sent directly to the + // set_password screen. If this happens, they have not yet seen the + // TOS/PP agreement. + + // Always show the Persona TOS/PP to new requiredEmail users. + personaTOSPP: !!requiredEmail, + + // The site TOS/PP must be shown to new requiredEmail users if there is + // a site TOS/PP + siteTOSPP: !!requiredEmail && self.siteTOSPP + }); + startAction(false, "doSetPassword", info); }); @@ -176,12 +192,24 @@ BrowserID.State = (function() { }); handleState("primary_user_unauthenticated", function(msg, info) { - info = helpers.extend(info, { + // a user who lands here is not authenticated with their identity + // provider. + _.extend(info, { add: !!addPrimaryUser, email: email, requiredEmail: !!requiredEmail, - privacyURL: self.privacyURL, - tosURL: self.tosURL + + // In the requiredEmail flow, a user who is not authenticated with + // their primary will be sent directly to the "you must verify + // with your IdP" screen. + // + // Show the siteTOSPP to all requiredEmail users who have never visited + // the site before. + siteTOSPP: requiredEmail && self.siteTOSPP && !user.getOriginEmail(), + + // Show the persona TOS/PP only to requiredEmail users who are creating + // a new account. + personaTOSPP: requiredEmail && !addPrimaryUser }); if (primaryVerificationInfo) { @@ -218,8 +246,7 @@ BrowserID.State = (function() { handleState("pick_email", function() { startAction("doPickEmail", { origin: self.hostname, - privacyURL: self.privacyURL, - tosURL: self.tosURL + siteTOSPP: self.siteTOSPP && !user.getOriginEmail() }); }); @@ -260,8 +287,12 @@ BrowserID.State = (function() { startAction("doAuthenticateWithRequiredEmail", { email: email, secondary_auth: true, - privacyURL: self.privacyURL, - tosURL: self.tosURL + + // This is a user is already authenticated to the assertion + // level who has chosen a secondary email address from the + // pick_email screen. They would have been shown the + // siteTOSPP there. + siteTOSPP: false }); } else { @@ -359,12 +390,26 @@ BrowserID.State = (function() { redirectToState("email_chosen", info); }); - handleState("add_email", function(msg, info) { - info = helpers.extend(info, { - privacyURL: self.privacyURL, - tosURL: self.tosURL - }); + handleState("reset_password", function(msg, info) { + info = info || {}; + // reset_password says the user has confirmed that they want to + // reset their password. doResetPassword will attempt to invoke + // the create_user wsapi. If the wsapi call is successful, + // the user will be shown the "go verify your account" message. + + // We have to save the staged email address here for when the user + // verifies their account and user_confirmed is called. + self.stagedEmail = info.email; + startAction(false, "doResetPassword", info); + }); + handleState("add_email", function(msg, info) { + // add_email indicates the user wishes to add an email to the account, + // the add_email screen must be displayed. After the user enters the + // email address they wish to add, add_email will trigger + // either 1) primary_user or 2) email_staged. #1 occurs if the email + // address is a primary address, #2 occurs if the address is a secondary + // and the verification email has been sent. startAction("doAddEmail", info); }); @@ -372,9 +417,26 @@ BrowserID.State = (function() { user.passwordNeededToAddSecondaryEmail(function(passwordNeeded) { if(passwordNeeded) { self.addEmailEmail = info.email; - // cancel is disabled if the user is doing the initial password set - // for a requiredEmail. - info.cancelable = !requiredEmail; + + _.extend(info, { + // cancel is disabled if the user is doing the initial password set + // for a requiredEmail. + cancelable: !requiredEmail, + + // stage_email is called to add an email to an already existing + // account. Since it is an already existing account, the + // personaTOSPP does not need to be shown. + personaTOSPP: false, + + // requiredEmail users who are adding an email but must set their + // password will be redirected here without seeing any other + // screens. non-requiredEmail users will have already seen the site + // TOS/PP in the pick-email screen if it was necessary. Since + // requiredEmail users may not have seen the screen before, show it + // here if there is no originEmail. + siteTOSPP: self.siteTOSPP && requiredEmail && !user.getOriginEmail() + }); + startAction(false, "doSetPassword", info); } else { diff --git a/resources/static/dialog/js/modules/actions.js b/resources/static/dialog/js/modules/actions.js index 3a95c89155d98f12c71b9f8eb11231f0a1f82bfe..9144b37521a54ad9dae4245493476addd06cde77 100644 --- a/resources/static/dialog/js/modules/actions.js +++ b/resources/static/dialog/js/modules/actions.js @@ -57,10 +57,6 @@ BrowserID.Modules.Actions = (function() { if(data.ready) _.defer(data.ready); }, - doRPInfo: function(info) { - startService("rp_info", info); - }, - doCancel: function() { if(onsuccess) onsuccess(null); }, @@ -156,6 +152,10 @@ BrowserID.Modules.Actions = (function() { doGenerateAssertion: function(info) { startService("generate_assertion", info); + }, + + doRPInfo: function(info) { + startService("rp_info", info); } }); diff --git a/resources/static/dialog/js/modules/add_email.js b/resources/static/dialog/js/modules/add_email.js index da642e0d2ced87d3cdf769b0d2389e0b2ad46e9a..07f6242caf302bed2cb3aaa49ee7416522ffb811 100644 --- a/resources/static/dialog/js/modules/add_email.js +++ b/resources/static/dialog/js/modules/add_email.js @@ -1,5 +1,5 @@ /*jshint browser:true, jQuery: true, forin: true, laxbreak:true */ -/*global _: true, BrowserID: true, PageController: true */ +/*global _: true, BrowserID: true, PageController: true, gettext: true */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ @@ -9,6 +9,7 @@ BrowserID.Modules.AddEmail = (function() { var bid = BrowserID, dom = bid.DOM, helpers = bid.Helpers, + user = bid.User, dialogHelpers = helpers.Dialog, errors = bid.Errors, complete = helpers.complete, @@ -54,12 +55,9 @@ BrowserID.Modules.AddEmail = (function() { var Module = bid.Modules.PageModule.extend({ start: function(options) { var self=this, - templateData = helpers.extend({}, options, { - privacy_url: options.privacyURL || null, - tos_url: options.tosURL || null - }); + originEmail = user.getOriginEmail(); - self.renderDialog("add_email", templateData); + self.renderDialog("add_email", options); hideHint("addressInfo"); self.click("#cancel", cancelAddEmail); diff --git a/resources/static/dialog/js/modules/authenticate.js b/resources/static/dialog/js/modules/authenticate.js index c316e55a5e5822825c2ad2bb69f1b32a6bf106fa..d1c13818901917c5ae93120aa100ce0cc6e579c8 100644 --- a/resources/static/dialog/js/modules/authenticate.js +++ b/resources/static/dialog/js/modules/authenticate.js @@ -33,6 +33,7 @@ BrowserID.Modules.Authenticate = (function() { } else { showHint("start"); + enterEmailState.call(self); complete(info.ready); } } @@ -98,7 +99,7 @@ BrowserID.Modules.Authenticate = (function() { function showHint(showSelector, callback) { _.each(hints, function(className) { if(className != showSelector) { - $("." + className).not("." + showSelector).hide(); + dom.hide("." + className + ":not(." + showSelector + ")"); } }); @@ -112,8 +113,8 @@ BrowserID.Modules.Authenticate = (function() { }); } - function enterEmailState(el) { - if (!$("#email").is(":disabled")) { + function enterEmailState() { + if (!dom.is("#email", ":disabled")) { this.submit = checkEmail; showHint("start"); } @@ -129,6 +130,8 @@ BrowserID.Modules.Authenticate = (function() { showHint("returning", function() { dom.focus("#password"); }); + + complete(callback); } @@ -158,12 +161,19 @@ BrowserID.Modules.Authenticate = (function() { var self=this; self.renderDialog("authenticate", { sitename: user.getHostname(), - email: lastEmail, - privacy_url: options.privacyURL, - tos_url: options.tosURL + email: lastEmail }); - $(".returning,.start").hide(); + dom.hide(".returning,.start"); + + // We have to show the TOS/PP agreements to *all* users here. Users who + // are already authenticated to their IdP but do not have a Persona + // account automatically have an account created with no further + // interaction. To make sure they see the TOS/PP agreement, show it + // here. + if (options.siteTOSPP) { + dialogHelpers.showRPTosPP.call(self); + } self.bind("#email", "keyup", emailKeyUp); self.click("#forgotPassword", forgotPassword); diff --git a/resources/static/dialog/js/modules/dialog.js b/resources/static/dialog/js/modules/dialog.js index 1a426a580653df1bfa93e288c8e0b8fa6306ad3f..8a4169fa8e5a3467885c6740109beb6b7ff1a9bc 100644 --- a/resources/static/dialog/js/modules/dialog.js +++ b/resources/static/dialog/js/modules/dialog.js @@ -74,10 +74,6 @@ BrowserID.Modules.Dialog = (function() { channel && channel.detach(); } - function setOrigin(origin) { - user.setOrigin(origin); - } - function onWindowUnload() { this.publish("window_unload"); } @@ -140,7 +136,7 @@ BrowserID.Modules.Dialog = (function() { var self=this, hash = win.location.hash; - setOrigin(origin_url); + user.setOrigin(origin_url); if (startExternalDependencies) { @@ -168,8 +164,8 @@ BrowserID.Modules.Dialog = (function() { if (paramsFromRP.privacyURL) paramsFromRP.privacyPolicy = paramsFromRP.privacyURL; if (paramsFromRP.termsOfService && paramsFromRP.privacyPolicy) { - params.tosURL = fixupURL(origin_url, paramsFromRP.termsOfService); - params.privacyURL = fixupURL(origin_url, paramsFromRP.privacyPolicy); + params.termsOfService = fixupURL(origin_url, paramsFromRP.termsOfService); + params.privacyPolicy = fixupURL(origin_url, paramsFromRP.privacyPolicy); } if (paramsFromRP.siteLogo) { diff --git a/resources/static/dialog/js/modules/pick_email.js b/resources/static/dialog/js/modules/pick_email.js index b666c95e90d2d95f26bb9ca71f65695f1f581466..c28a23babeeefe78540ac346f93f96e5212894b1 100644 --- a/resources/static/dialog/js/modules/pick_email.js +++ b/resources/static/dialog/js/modules/pick_email.js @@ -93,10 +93,13 @@ BrowserID.Modules.PickEmail = (function() { self.renderDialog("pick_email", { identities: identities, - siteemail: storage.site.get(origin, "email"), - privacy_url: options.privacyURL, - tos_url: options.tosURL + siteemail: user.getOriginEmail() }); + + if (options.siteTOSPP) { + dialogHelpers.showRPTosPP.call(self); + } + dom.getElements("body").css("opacity", "1"); if (dom.getElements("#selectEmail input[type=radio]:visible").length === 0) { // If there is only one email address, the radio button is never shown, diff --git a/resources/static/dialog/js/modules/required_email.js b/resources/static/dialog/js/modules/required_email.js index 6e5f97e59d25682fbda2022dba60da2a733440e8..037621924d000b0b2c5925f1ad34b22efd58f550 100644 --- a/resources/static/dialog/js/modules/required_email.js +++ b/resources/static/dialog/js/modules/required_email.js @@ -147,7 +147,13 @@ BrowserID.Modules.RequiredEmail = (function() { // We know the user has control of this address, give them // a chance to hit "sign in" before we kick them off to the // primary flow account. - showTemplate({ signin: true, primary: true }); + + // Show the Persona TOS/PP to any primary user who is authed with + // their IdP but not with Persona. Unfortunately, addressInfo + // does not tell us whether a primary address already has an + // account, so we have to show the personaTOSPP to any user who + // is not authenticated. + showTemplate({ signin: true, primary: true, personaTOSPP: !auth_level }); } else if(info.type === "primary" && !info.authed) { // User who does not control a primary address. @@ -213,12 +219,15 @@ BrowserID.Modules.RequiredEmail = (function() { password: false, secondary_auth: false, primary: false, - privacy_url: options.privacyURL || null, - tos_url: options.tosURL || null + personaTOSPP: false }, templateData); self.renderDialog("required_email", templateData); + if (options.siteTOSPP) { + dialogHelpers.showRPTosPP.call(self); + } + self.click("#sign_in", signIn); self.click("#verify_address", verifyAddress); self.click("#forgotPassword", forgotPassword); diff --git a/resources/static/dialog/js/modules/rp_info.js b/resources/static/dialog/js/modules/rp_info.js index 3bc9b20edd9efb34d9466a815024b6e09c0775e9..55d91d276edf7e861841dc1c3243920fd44f536b 100644 --- a/resources/static/dialog/js/modules/rp_info.js +++ b/resources/static/dialog/js/modules/rp_info.js @@ -7,7 +7,8 @@ /** * Purpose: - * Display to the user RP related data such as hostname, name, and logo. + * Display to the user RP related data such as hostname, sitename, logo, + * TOS/PP, etc. */ BrowserID.Modules.RPInfo = (function() { "use strict"; @@ -32,7 +33,9 @@ BrowserID.Modules.RPInfo = (function() { renderer.render("#rp_info", "rp_info", { hostname: options.hostname, siteName: options.siteName, - siteLogo: options.siteLogo + siteLogo: options.siteLogo, + privacyPolicy: options.privacyPolicy, + termsOfService: options.termsOfService }); sc.start.call(this, options); diff --git a/resources/static/dialog/js/modules/set_password.js b/resources/static/dialog/js/modules/set_password.js index 7bc6848c59663f9f30ea5f8023feb0e97c9cb984..02c6de1038dd03df26c63c2dc377a9708e8af66f 100644 --- a/resources/static/dialog/js/modules/set_password.js +++ b/resources/static/dialog/js/modules/set_password.js @@ -36,9 +36,14 @@ BrowserID.Modules.SetPassword = (function() { self.renderDialog("set_password", { password_reset: !!options.password_reset, - cancelable: options.cancelable !== false + cancelable: options.cancelable !== false, + personaTOSPP: options.personaTOSPP }); + if (options.siteTOSPP) { + dialogHelpers.showRPTosPP.call(self); + } + self.click("#cancel", cancel); sc.start.call(self, options); diff --git a/resources/static/dialog/js/modules/verify_primary_user.js b/resources/static/dialog/js/modules/verify_primary_user.js index b12827f7c6a99f4290df6f81a3483c5c26594371..8a35914e2665c6a07d5814f439da440e5699a752 100644 --- a/resources/static/dialog/js/modules/verify_primary_user.js +++ b/resources/static/dialog/js/modules/verify_primary_user.js @@ -12,7 +12,9 @@ BrowserID.Modules.VerifyPrimaryUser = (function() { add, email, auth_url, + dom = bid.DOM, helpers = bid.Helpers, + dialogHelpers = helpers.Dialog, complete = helpers.complete; function verify(callback) { @@ -46,12 +48,16 @@ BrowserID.Modules.VerifyPrimaryUser = (function() { email = data.email; auth_url = data.auth_url; - var templateData = helpers.extend({}, data, { + self.renderDialog("verify_primary_user", { + email: data.email, + auth_url: data.auth_url, requiredEmail: data.requiredEmail || false, - privacy_url: data.privacyURL || null, - tos_url: data.tosURL || null + personaTOSPP: data.personaTOSPP }); - self.renderDialog("verify_primary_user", templateData); + + if (data.siteTOSPP) { + dialogHelpers.showRPTosPP.call(self); + } self.click("#cancel", cancel); diff --git a/resources/static/dialog/views/add_email.ejs b/resources/static/dialog/views/add_email.ejs index b98b22ab8708478c0dd7392de90e4bd2a78632eb..15ebbad134b0779d228dc3f5cbb9102a1193fa2f 100644 --- a/resources/static/dialog/views/add_email.ejs +++ b/resources/static/dialog/views/add_email.ejs @@ -34,22 +34,8 @@ </ul> <div class="submit cf"> - <% if (privacy_url && tos_url) { %> - <p class="tospp"> - <%= format( - gettext('By clicking %s, you confirm that you accept this site\'s <a %s>Terms of Use</a> and <a %s>Privacy Policy</a>.'), - [ gettext('add'), - format(' href="%s" target="_new"', [tos_url]), - format(' href="%s" target="_new"', [privacy_url]) - ]) %> - </p> - <p> - <% } %> <button id="addNewEmail"><%= gettext('add') %></button> <a href="#" id="cancel" class="action"><%= gettext('cancel') %></a> - <% if (privacy_url && tos_url) { %> - </p> - <% } %> </div> </div> diff --git a/resources/static/dialog/views/authenticate.ejs b/resources/static/dialog/views/authenticate.ejs index 55e461d5ceaed29e52ef2f148466d2698beb7c7e..a95c45b441638b50424e8ca14dc1dc21df6fa421 100644 --- a/resources/static/dialog/views/authenticate.ejs +++ b/resources/static/dialog/views/authenticate.ejs @@ -58,16 +58,15 @@ <button class="start addressInfo" tabindex="3"><%= gettext('next') %></button> <button class="returning" tabindex="3"><%= gettext('sign in') %></button> </p> - <% if (privacy_url && tos_url) { %> - <p class="tospp"> - <%= format( - gettext('By clicking %s, you confirm that you accept this site\'s <a %s>Terms of Use</a> and <a %s>Privacy Policy</a>.'), - [ gettext('next'), - format(' href="%s" target="_new"', [tos_url]), - format(' href="%s" target="_new"', [privacy_url]) - ]) %> + + <p class="tospp"> + <%= format( + gettext('By proceeding, you agree to %s\'s <a %s>Terms</a> and <a %s>Privacy Policy</a>.'), + [ "Persona", + ' href="https://login.persona.org/tos" target="_new"', + ' href="https://login.persona.org/privacy" target="_new"', + ]) %> </p> - <% } %> </div> </div> diff --git a/resources/static/dialog/views/pick_email.ejs b/resources/static/dialog/views/pick_email.ejs index c189f521055d156ee397366df6d6306a22645f98..059072425b93d6be854125b4290d444f26c019ad 100644 --- a/resources/static/dialog/views/pick_email.ejs +++ b/resources/static/dialog/views/pick_email.ejs @@ -23,18 +23,8 @@ <div class="submit add cf"> - <p class="cf"> - <button id="signInButton"><%= gettext('sign in') %></button> - </p> - <% if (privacy_url && tos_url) { %> - <p class="tospp"> - <%= format( - gettext('By clicking %s, you confirm that you accept this site\'s <a %s>Terms of Use</a> and <a %s>Privacy Policy</a>.'), - [ gettext('sign in'), - format(' href="%s" target="_new"', [tos_url]), - format(' href="%s" target="_new"', [privacy_url]) - ]) %> + <p class="cf"> + <button id="signInButton"><%= gettext('sign in') %></button> </p> - <% } %> </div> </div> diff --git a/resources/static/dialog/views/required_email.ejs b/resources/static/dialog/views/required_email.ejs index a1e0fdace2304f322d97fcac29b3cf65a664c10e..5245319c2e48ee6849561757f1a8d9b7b9e7ef83 100644 --- a/resources/static/dialog/views/required_email.ejs +++ b/resources/static/dialog/views/required_email.ejs @@ -50,17 +50,7 @@ </ul> <div class="submit cf"> - <% if (privacy_url && tos_url) { %> - <p class="tospp"> - <%= format( - gettext('By clicking %s, you confirm that you accept this site\'s <a %s>Terms of Use</a> and <a %s>Privacy Policy</a>.'), - [ gettext('sign in'), - format(' href="%s" target="_new"', [tos_url]), - format(' href="%s" target="_new"', [privacy_url]) - ]) %> - </p> - <p> - <% } %> + <p class="cf"> <% if (signin) { %> <button id="sign_in" tabindex="3"><%= gettext("sign in") %></button> <% } else if (verify) { %> @@ -70,8 +60,16 @@ <% if (secondary_auth) { %> <a href="#" id="cancel" class="action" tabindex="4"><%= gettext("cancel") %></a> <% } %> - <% if (privacy_url && tos_url) { %> </p> - <% } %> + <% if (personaTOSPP) { %> + <p class="tospp"> + <%= format( + gettext('By proceeding, you agree to %s\'s <a %s>Terms</a> and <a %s>Privacy Policy</a>.'), + [ "Persona", + ' href="https://login.persona.org/tos" target="_new"', + ' href="https://login.persona.org/privacy" target="_new"', + ]) %> + </p> + <% } %> </div> </div> diff --git a/resources/static/dialog/views/rp_info.ejs b/resources/static/dialog/views/rp_info.ejs index 5928a18d6c945d726598017558fbb69f1f4d16e1..724a3e1925dfbf9a1c5d58d6e8bfc67278d31c44 100644 --- a/resources/static/dialog/views/rp_info.ejs +++ b/resources/static/dialog/views/rp_info.ejs @@ -11,11 +11,18 @@ <h2 id="rp_name"><%= siteName %></h2> <% } %> -<% if(hostname) { %> - <% if(siteName) { %> - <h3 id="rp_hostname"><%= hostname %></h3> - <% } else { %> - <h2 id="rp_hostname"><%= hostname %></h2> - <% } %> +<% if(siteName) { %> + <h3 id="rp_hostname"><%= hostname %></h3> +<% } else { %> + <h2 id="rp_hostname"><%= hostname %></h2> <% } %> +<% if(privacyPolicy && termsOfService) { %> + <p id="rptospp" class="tospp"> + <%= format(gettext("By proceeding, you agree to %s\'s <a %s>Terms</a> and <a %s>Privacy Policy</a>."), + [ siteName || hostname, + ' href="' + termsOfService + '" id="rp_tos" target="_blank"', + ' href="' + privacyPolicy + '" id="rp_pp" target="_blank"' + ]) %> + </p> +<% } %> diff --git a/resources/static/dialog/views/set_password.ejs b/resources/static/dialog/views/set_password.ejs index d244293925fc8e8f299af68f59774d156bc32e87..c16a1f2d9fc6378601fde28faeefe159cbb416e5 100644 --- a/resources/static/dialog/views/set_password.ejs +++ b/resources/static/dialog/views/set_password.ejs @@ -48,11 +48,23 @@ </ul> <div class="submit cf"> + <p class="cf"> <button id="<%= password_reset ? "password_reset" : "verify_user" %>"> <%= password_reset ? gettext('reset password') : gettext('verify email') %> </button> <% if(cancelable) { %> <a id="cancel" class="action" href="#"><%= gettext('cancel') %></a> <% } %> + </p> + <% if (personaTOSPP) { %> + <p id="persona_tospp" class="tospp"> + <%= format( + gettext('By proceeding, you agree to %s\'s <a %s>Terms</a> and <a %s>Privacy Policy</a>.'), + [ "Persona", + ' href="https://login.persona.org/tos" target="_new"', + ' href="https://login.persona.org/privacy" target="_new"', + ]) %> + </p> + <% } %> </div> </div> diff --git a/resources/static/dialog/views/verify_primary_user.ejs b/resources/static/dialog/views/verify_primary_user.ejs index 0a3de6851ed2412d1e3fdefbddf12548b777bb66..c2d4da92de3cdeb7a34d18a1be6a242a1823f370 100644 --- a/resources/static/dialog/views/verify_primary_user.ejs +++ b/resources/static/dialog/views/verify_primary_user.ejs @@ -4,7 +4,7 @@ <% if (requiredEmail) { %> <strong><%= gettext('The site requested you sign in using') %></strong> - <div class="form_section"> + <div id="verify_primary_user" class="cf form_section"> <ul class="inputs"> <li> @@ -15,7 +15,7 @@ </div> </li> - <li> + <li class="small"> <%= gettext("You must sign in with your email provider to verify ownership of this address. This window will be redirected to") %> <p> <strong><%= auth_url %></strong>. @@ -24,48 +24,47 @@ </ul> <div class="submit cf"> - <% if (privacy_url && tos_url) { %> - <p class="tospp"> - <%= format( - gettext('By clicking %s, you confirm that you accept this site\'s <a %s>Terms of Use</a> and <a %s>Privacy Policy</a>.'), - [ gettext('verify'), - format(' href="%s" target="_new"', [tos_url]), - format(' href="%s" target="_new"', [privacy_url]) - ]) %> - </p> - <p> - <% } %> - <button id="verifyWithPrimary"><%= gettext("verify") %></button> - <% if (privacy_url && tos_url) { %> + <p class="cf"> + <button id="verifyWithPrimary"><%= gettext("verify") %></button> </p> - <% } %> + + <% if (personaTOSPP) { %> + <p id="persona_tospp" class="tospp"> + <%= format( + gettext('By proceeding, you agree to %s\'s <a %s>Terms</a> and <a %s>Privacy Policy</a>.'), + [ "Persona", + ' href="https://login.persona.org/tos" target="_new"', + ' href="https://login.persona.org/privacy" target="_new"', + ]) %> + </p> + <% } %> </div> </div> <% } else { %> <strong><%= gettext("Verify With Email Provider") %></strong> - <div class="cf form_section"> - <%= gettext("You must sign in with your email provider to verify ownership of this address. This window will be redirected to") %> - <p> - <strong><%= auth_url %></strong>. - </p> + <div id="verify_primary_user" class="cf form_section"> + <div class="small"> + <%= gettext("You must sign in with your email provider to verify ownership of this address. This window will be redirected to") %> + <p> + <strong><%= auth_url %></strong>. + </p> + </div> <div class="submit cf"> - <% if (privacy_url && tos_url) { %> - <p class="tospp"> - <%= format( - gettext('By clicking %s, you confirm that you accept this site\'s <a %s>Terms of Use</a> and <a %s>Privacy Policy</a>.'), - [ gettext('verify'), - format(' href="%s" target="_new"', [tos_url]), - format(' href="%s" target="_new"', [privacy_url]) - ]) %> - </p> - <p> - <% } %> + <p class="cf"> <button id="verifyWithPrimary"><%= gettext("verify") %></button> <a href="#" id="cancel" class="action"><%= gettext("cancel") %></a> - <% if (privacy_url && tos_url) { %> + </p> + <% if (personaTOSPP) { %> + <p id="persona_tospp" class="tospp"> + <%= format( + gettext('By proceeding, you agree to %s\'s <a %s>Terms</a> and <a %s>Privacy Policy</a>.'), + [ "Persona", + ' href="https://login.persona.org/tos" target="_new"', + ' href="https://login.persona.org/privacy" target="_new"', + ]) %> </p> <% } %> </div> diff --git a/resources/static/pages/css/style.css b/resources/static/pages/css/style.css index 96034587943cb6247e9a382cd8149d6b020691e8..d73c65a9f1fbfe26c3f45fbffef015accc062cf3 100644 --- a/resources/static/pages/css/style.css +++ b/resources/static/pages/css/style.css @@ -447,10 +447,6 @@ button.delete:active { padding: 0; } -#signUpForm .submit { - height: 28px; -} - #signUpForm > .siteinfo { margin-bottom: 10px; } @@ -459,10 +455,18 @@ button.delete:active { display: none; } +.submit > p { + line-height: 28px; +} + .submit .remember { float: left; } +.tospp { + font-size: 13px; +} + .enter_password .password_entry, .enter_verify_password #verify_password, .known_secondary .password_entry, .unknown_secondary #unknown_secondary, .verify_primary #verify_primary { display: block; diff --git a/resources/static/test/cases/common/js/user.js b/resources/static/test/cases/common/js/user.js index 26c47010104631cc42cdd9ac2c77caff04b6c9e5..26813f1815568a5b5626606aeedabed04e7ae751 100644 --- a/resources/static/test/cases/common/js/user.js +++ b/resources/static/test/cases/common/js/user.js @@ -92,6 +92,22 @@ var jwcrypto = require("./lib/jwcrypto"); equal(lib.getReturnTo(), returnTo, "get/setReturnTo work as expected"); }); + test("setOriginEmail/getOriginEmail", function() { + storage.addEmail("testuser@testuser.com", { type: "primary" }); + storage.addEmail("testuser2@testuser.com", { type: "primary" }); + + lib.setOrigin("http://testdomain.org"); + + lib.setOriginEmail("testuser@testuser.com"); + equal(lib.getOriginEmail(), "testuser@testuser.com", "correct email"); + + lib.setOrigin("http://othertestdomain.org"); + lib.setOriginEmail("testuser2@testuser.com"); + + lib.setOrigin("http://testdomain.org"); + equal(lib.getOriginEmail(), "testuser@testuser.com", "correct email"); + }); + test("getStoredEmailKeypairs without key - return all identities", function() { var identities = lib.getStoredEmailKeypairs(); equal("object", typeof identities, "object returned"); diff --git a/resources/static/test/cases/dialog/js/misc/state.js b/resources/static/test/cases/dialog/js/misc/state.js index 8d6850d399428fb18c5348332367ffc39a9db33d..3d384a0eb72c216073c080033acbfdf4d148d6aa 100644 --- a/resources/static/test/cases/dialog/js/misc/state.js +++ b/resources/static/test/cases/dialog/js/misc/state.js @@ -34,6 +34,14 @@ } } + function testActionStarted(actionName, requiredOptions) { + ok(actions.called[actionName], actionName + "called"); + for(var key in requiredOptions) { + equal(actions.info[actionName][key], requiredOptions[key], + actionName + " called with " + key + "=" + requiredOptions[key]); + } + } + function createMachine() { machine = bid.State.create(); actions = new ActionsMock(); @@ -127,6 +135,16 @@ equal(actions.info.doResetPassword.email, TEST_EMAIL, "correct email sent to doResetPassword"); }); + test("start - RPInfo always started", function() { + mediator.publish("start", { + termsOfService: "https://browserid.org/TOS.html", + privacyPolicy: "https://browserid.org/priv.html" + }); + + ok(actions.info.doRPInfo.termsOfService, "doRPInfo called with termsOfService set"); + ok(actions.info.doRPInfo.privacyPolicy, "doRPInfo called with privacyPolicy set"); + }); + test("user_staged - call doConfirmUser", function() { mediator.publish("user_staged", { email: TEST_EMAIL }); @@ -254,13 +272,13 @@ mediator.publish("authenticated", { email: TEST_EMAIL }); }); - test("forgot_password", function() { + test("forgot_password - call doForgotPassword with correct options", function() { + mediator.publish("start", { privacyPolicy: "priv.html", termsOfService: "tos.html" }); mediator.publish("forgot_password", { email: TEST_EMAIL, requiredEmail: true }); - equal(actions.info.doForgotPassword.email, TEST_EMAIL, "correct email passed"); - equal(actions.info.doForgotPassword.requiredEmail, true, "correct requiredEmail passed"); + testActionStarted("doForgotPassword", { email: TEST_EMAIL, requiredEmail: true }); }); test("password_reset to user_confirmed - call doUserStaged then doEmailConfirmed", function() { @@ -379,12 +397,11 @@ ok(actions.called.doNotMe, "doNotMe has been called"); }); - test("authenticate", function() { - mediator.publish("authenticate", { - email: TEST_EMAIL - }); + test("authenticate - call doAuthenticate with the correct options", function() { + mediator.publish("start", { privacyPolicy: "priv.html", termsOfService: "tos.html" }); + mediator.publish("authenticate", { email: TEST_EMAIL }); - equal(actions.info.doAuthenticate.email, TEST_EMAIL, "authenticate with testuser@testuser.com"); + testActionStarted("doAuthenticate", { email: TEST_EMAIL, siteTOSPP: true }); }); test("start with no special parameters - go straight to checking auth", function() { @@ -410,16 +427,23 @@ }); + test("add_email - call doAddEmail with correct options", function() { + mediator.publish("start", { privacyPolicy: "priv.html", termsOfService: "tos.html" }); + mediator.publish("add_email"); + testActionStarted("doAddEmail"); + }); + asyncTest("email_chosen with secondary email, user must authenticate - call doAuthenticateWithRequiredEmail", function() { var email = TEST_EMAIL; storage.addEmail(email, { type: "secondary" }); xhr.setContextInfo("auth_level", "assertion"); + mediator.publish("start", { privacyPolicy: "priv.html", termsOfService: "tos.html" }); mediator.publish("email_chosen", { email: email, complete: function() { - equal(actions.called.doAuthenticateWithRequiredEmail, true, "doAuthenticateWithRequiredEmail called"); + testActionStarted("doAuthenticateWithRequiredEmail", { siteTOSPP: false }); start(); } }); @@ -469,15 +493,14 @@ test("null assertion generated - preserve original options in doPickEmail", function() { mediator.publish("start", { hostname: "http://example.com", - privacyURL: "http://example.com/priv.html", - tosURL: "http://example.com/tos.html" + privacyPolicy: "http://example.com/priv.html", + termsOfService: "http://example.com/tos.html" }); mediator.publish("assertion_generated", { assertion: null }); equal(actions.called.doPickEmail, true, "doPickEmail callled"); equal(actions.info.doPickEmail.origin, "http://example.com", "hostname preserved"); - equal(actions.info.doPickEmail.privacyURL, "http://example.com/priv.html", "privacyURL preserved"); - equal(actions.info.doPickEmail.tosURL, "http://example.com/tos.html", "tosURL preserved"); + equal(actions.info.doPickEmail.siteTOSPP, true, "siteTOSPP preserved"); }); test("add_email - call doAddEmail", function() { diff --git a/resources/static/test/cases/dialog/js/modules/actions.js b/resources/static/test/cases/dialog/js/modules/actions.js index 8d90d69f88dfd2bcd2b72865732ff267e1593e3a..27c54f781f818759fa4527d1c1c0910675b5bcee 100644 --- a/resources/static/test/cases/dialog/js/modules/actions.js +++ b/resources/static/test/cases/dialog/js/modules/actions.js @@ -88,7 +88,6 @@ testActionStartsModule('doGenerateAssertion', { email: TEST_EMAIL }, "generate_assertion"); }); - asyncTest("doStageUser with successful creation - trigger user_staged", function() { createController({ ready: function() { @@ -109,5 +108,21 @@ asyncTest("doForgotPassword - call the set_password controller with reset_password true", function() { testActionStartsModule('doForgotPassword', { email: TEST_EMAIL }, "set_password"); }); + + asyncTest("doRPInfo - start the rp_info service", function() { + createController({ + ready: function() { + var error; + try { + controller.doRPInfo({ name: "browserid.org" }); + } catch(e) { + error = e; + } + + equal(error, "module not registered for rp_info", "correct service started"); + start(); + } + }); + }); }()); diff --git a/resources/static/test/cases/dialog/js/modules/add_email.js b/resources/static/test/cases/dialog/js/modules/add_email.js index 6d635e82286fcb606da9e1fe8dd8c99307b40b9e..43f19e385b3091fcdd8411ee30f0c6891f38a123 100644 --- a/resources/static/test/cases/dialog/js/modules/add_email.js +++ b/resources/static/test/cases/dialog/js/modules/add_email.js @@ -41,16 +41,6 @@ controller.start(options || {}); } - test("privacyURL and tosURL specified - show TOS/PP", function() { - equal($(".tospp").length, 0, "tospp has not yet been added to the DOM"); - createController({ - privacyURL: "http://testuser.com/priv.html", - tosURL: "http://testuser.com/tos.html", - }); - - equal($(".tospp").length, 1, "tospp has been added to the DOM"); - }); - test("addEmail with specified email address - fill in email", function() { createController({ email: "testuser@testuser.com" }); ok($("#newEmail").val(), "testuser@testuser.com", "email prepopulated"); diff --git a/resources/static/test/cases/dialog/js/modules/dialog.js b/resources/static/test/cases/dialog/js/modules/dialog.js index 0a6c14d5f3ba78f1e537426c2ede9608fd1ece13..2519af8c14c3c13e0c77ae4b66b80fcd156036fc 100644 --- a/resources/static/test/cases/dialog/js/modules/dialog.js +++ b/resources/static/test/cases/dialog/js/modules/dialog.js @@ -208,7 +208,8 @@ }); }); - asyncTest("get with relative tosURL & valid privacyURL - print error screen", function() { + + asyncTest("get with relative termsOfService & valid privacyPolicy - print error screen", function() { createController({ ready: function() { mediator.subscribe("start", function(msg, info) { @@ -216,8 +217,8 @@ }); var retval = controller.get(HTTP_TEST_DOMAIN, { - tosURL: "relative.html", - privacyURL: "/privacy.html" + termsOfService: "relative.html", + privacyPolicy: "/privacy.html" }); equal(retval, "relative urls not allowed: (relative.html)", "expected error"); testErrorVisible(); @@ -226,7 +227,7 @@ }); }); - asyncTest("get with script containing tosURL - print error screen", function() { + asyncTest("get with script containing termsOfService - print error screen", function() { createController({ ready: function() { mediator.subscribe("start", function(msg, info) { @@ -234,11 +235,11 @@ }); var retval = controller.get(HTTP_TEST_DOMAIN, { - tosURL: "relative.html<script>window.scriptRun=true;</script>", - privacyURL: "/privacy.html" + termsOfService: "relative.html<script>window.scriptRun=true;</script>", + privacyPolicy: "/privacy.html" }); - // If tosURL is not properly escaped, scriptRun will be true. + // If termsOfService is not properly escaped, scriptRun will be true. equal(typeof window.scriptRun, "undefined", "script was not run"); equal(retval, "relative urls not allowed: (relative.html<script>window.scriptRun=true;</script>)", "expected error"); testErrorVisible(); @@ -247,7 +248,7 @@ }); }); - asyncTest("get with valid tosURL & relative privacyURL - print error screen", function() { + asyncTest("get with valid termsOfService & relative privacyPolicy - print error screen", function() { createController({ ready: function() { mediator.subscribe("start", function(msg, info) { @@ -255,8 +256,8 @@ }); var retval = controller.get(HTTP_TEST_DOMAIN, { - tosURL: "/tos.html", - privacyURL: "relative.html" + termsOfService: "/tos.html", + privacyPolicy: "relative.html" }); equal(retval, "relative urls not allowed: (relative.html)", "expected error"); testErrorVisible(); @@ -265,7 +266,7 @@ }); }); - asyncTest("get with script containing privacyURL - print error screen", function() { + asyncTest("get with script containing privacyPolicy - print error screen", function() { createController({ ready: function() { mediator.subscribe("start", function(msg, info) { @@ -273,11 +274,11 @@ }); var retval = controller.get(HTTP_TEST_DOMAIN, { - tosURL: "/tos.html", - privacyURL: "relative.html<script>window.scriptRun=true;</script>" + termsOfService: "/tos.html", + privacyPolicy: "relative.html<script>window.scriptRun=true;</script>" }); - // If privacyURL is not properly escaped, scriptRun will be true. + // If privacyPolicy is not properly escaped, scriptRun will be true. equal(typeof window.scriptRun, "undefined", "script was not run"); equal(retval, "relative urls not allowed: (relative.html<script>window.scriptRun=true;</script>)", "expected error"); testErrorVisible(); @@ -286,7 +287,7 @@ }); }); - asyncTest("get with privacyURL - print error screen", function() { + asyncTest("get with privacyPolicy - print error screen", function() { createController({ ready: function() { mediator.subscribe("start", function(msg, info) { @@ -294,11 +295,11 @@ }); var retval = controller.get(HTTP_TEST_DOMAIN, { - tosURL: "/tos.html", - privacyURL: "relative.html<script>window.scriptRun=true;</script>" + termsOfService: "/tos.html", + privacyPolicy: "relative.html<script>window.scriptRun=true;</script>" }); - // If privacyURL is not properly escaped, scriptRun will be true. + // If privacyPolicy is not properly escaped, scriptRun will be true. equal(typeof window.scriptRun, "undefined", "script was not run"); equal(retval, "relative urls not allowed: (relative.html<script>window.scriptRun=true;</script>)", "expected error"); testErrorVisible(); @@ -307,7 +308,7 @@ }); }); - asyncTest("get with javascript protocol for privacyURL - print error screen", function() { + asyncTest("get with javascript protocol for privacyPolicy - print error screen", function() { createController({ ready: function() { mediator.subscribe("start", function(msg, info) { @@ -315,8 +316,8 @@ }); var retval = controller.get(HTTP_TEST_DOMAIN, { - tosURL: "/tos.html", - privacyURL: "javascript:alert(1)" + termsOfService: "/tos.html", + privacyPolicy: "javascript:alert(1)" }); equal(retval, "relative urls not allowed: (javascript:alert(1))", "expected error"); @@ -326,7 +327,7 @@ }); }); - asyncTest("get with invalid httpg protocol for privacyURL - print error screen", function() { + asyncTest("get with invalid httpg protocol for privacyPolicy - print error screen", function() { createController({ ready: function() { mediator.subscribe("start", function(msg, info) { @@ -334,8 +335,8 @@ }); var retval = controller.get(HTTP_TEST_DOMAIN, { - tosURL: "/tos.html", - privacyURL: "httpg://testdomain.com/privacy.html" + termsOfService: "/tos.html", + privacyPolicy: "httpg://testdomain.com/privacy.html" }); equal(retval, "relative urls not allowed: (httpg://testdomain.com/privacy.html)", "expected error"); @@ -346,7 +347,7 @@ }); - asyncTest("get with valid absolute tosURL & privacyURL - go to start", function() { + asyncTest("get with valid absolute termsOfService & privacyPolicy - go to start", function() { createController({ ready: function() { var startInfo; @@ -355,13 +356,13 @@ }); var retval = controller.get(HTTP_TEST_DOMAIN, { - tosURL: "/tos.html", - privacyURL: "/privacy.html" + termsOfService: "/tos.html", + privacyPolicy: "/privacy.html" }); testHelpers.testObjectValuesEqual(startInfo, { - tosURL: HTTP_TEST_DOMAIN + "/tos.html", - privacyURL: HTTP_TEST_DOMAIN + "/privacy.html" + termsOfService: HTTP_TEST_DOMAIN + "/tos.html", + privacyPolicy: HTTP_TEST_DOMAIN + "/privacy.html" }); equal(typeof retval, "undefined", "no error expected"); @@ -371,7 +372,7 @@ }); }); - asyncTest("get with valid fully qualified http tosURL & privacyURL - go to start", function() { + asyncTest("get with valid fully qualified http termsOfService & privacyPolicy - go to start", function() { createController({ ready: function() { var startInfo; @@ -380,13 +381,13 @@ }); var retval = controller.get(HTTP_TEST_DOMAIN, { - tosURL: HTTP_TEST_DOMAIN + "/tos.html", - privacyURL: HTTP_TEST_DOMAIN + "/privacy.html" + termsOfService: HTTP_TEST_DOMAIN + "/tos.html", + privacyPolicy: HTTP_TEST_DOMAIN + "/privacy.html" }); testHelpers.testObjectValuesEqual(startInfo, { - tosURL: HTTP_TEST_DOMAIN + "/tos.html", - privacyURL: HTTP_TEST_DOMAIN + "/privacy.html" + termsOfService: HTTP_TEST_DOMAIN + "/tos.html", + privacyPolicy: HTTP_TEST_DOMAIN + "/privacy.html" }); equal(typeof retval, "undefined", "no error expected"); @@ -397,7 +398,7 @@ }); - asyncTest("get with valid fully qualified https tosURL & privacyURL - go to start", function() { + asyncTest("get with valid fully qualified https termsOfService & privacyPolicy - go to start", function() { createController({ ready: function() { var startInfo; @@ -406,13 +407,13 @@ }); var retval = controller.get(HTTP_TEST_DOMAIN, { - tosURL: HTTPS_TEST_DOMAIN + "/tos.html", - privacyURL: HTTPS_TEST_DOMAIN + "/privacy.html" + termsOfService: HTTPS_TEST_DOMAIN + "/tos.html", + privacyPolicy: HTTPS_TEST_DOMAIN + "/privacy.html" }); testHelpers.testObjectValuesEqual(startInfo, { - tosURL: HTTPS_TEST_DOMAIN + "/tos.html", - privacyURL: HTTPS_TEST_DOMAIN + "/privacy.html" + termsOfService: HTTPS_TEST_DOMAIN + "/tos.html", + privacyPolicy: HTTPS_TEST_DOMAIN + "/privacy.html" }); equal(typeof retval, "undefined", "no error expected"); testErrorNotVisible(); diff --git a/resources/static/test/cases/dialog/js/modules/required_email.js b/resources/static/test/cases/dialog/js/modules/required_email.js index 53fbed0c1c6c2290a752ec66f4c88cd2de427581..97800512f5c0df71e88c4529c20d7fc3e71b3658 100644 --- a/resources/static/test/cases/dialog/js/modules/required_email.js +++ b/resources/static/test/cases/dialog/js/modules/required_email.js @@ -95,17 +95,16 @@ } - asyncTest("privacyURL and tosURL specified - show TOS/PP", function() { + asyncTest("siteTOSPP specified - show TOS/PP", function() { var email = "registered@testuser.com"; xhr.useResult("known_secondary"); + xhr.setContextInfo("auth_level", "password"); - equal($(".tospp").length, 0, "tospp has not yet been added to the DOM"); createController({ - email: "registered@testuser.com", - privacyURL: "http://testuser.com/priv.html", - tosURL: "http://testuser.com/tos.html", + email: email, + siteTOSPP: true, ready: function() { - equal($(".tospp").length, 1, "tospp has been added to the DOM"); + testHelpers.testRPTosPPShown(); start(); } }); diff --git a/resources/static/test/cases/dialog/js/modules/rp_info.js b/resources/static/test/cases/dialog/js/modules/rp_info.js index 0b89868ab973653fcec4d665f707b5f77b5580dc..c50a3127c4253f84ef0663a2e1836b3db32ecfb5 100644 --- a/resources/static/test/cases/dialog/js/modules/rp_info.js +++ b/resources/static/test/cases/dialog/js/modules/rp_info.js @@ -13,8 +13,11 @@ register = bid.TestHelpers.register, WindowMock = bid.Mocks.WindowMock, RP_HOSTNAME = "hostname.org", - RP_NAME = "RP Name", - RP_HTTPS_LOGO = "https://en.gravatar.com/userimage/6966791/c4feac761b8544cce13e0406f36230aa.jpg"; + RP_NAME = "The Planet's Most Awesome Site", + RP_TOS_URL = "https://browserid.org/TOS.html", + RP_PP_URL = "https://browserid.org/priv.html", + RP_HTTPS_LOGO = "https://en.gravatar.com/userimage/6966791/c4feac761b8544cce13e0406f36230aa.jpg", + mediator = bid.Mediator; module("controllers/rp_info", { setup: testHelpers.setup, @@ -84,5 +87,17 @@ equal($("#rp_logo").attr("src"), RP_HTTPS_LOGO, "rp logo shown"); }); + test("privacyPolicy, termsOfService specified - show TOS/PP info", function() { + createController({ + siteName: RP_NAME, + privacyPolicy: RP_PP_URL, + termsOfService: RP_TOS_URL + }); + + equal($("#rp_name").text(), RP_NAME, "RP's name is set"); + equal($("#rp_tos").attr("href"), RP_TOS_URL, "RP's TOS is set"); + equal($("#rp_pp").attr("href"), RP_PP_URL, "RP's Privacy Policy is set"); + }); + }()); diff --git a/resources/static/test/cases/dialog/js/modules/set_password.js b/resources/static/test/cases/dialog/js/modules/set_password.js index a1ae3b3c683434ebf000678e3b77943fbaf15d82..0d64302f07c16ac0042558e60dd26840fdc97db3 100644 --- a/resources/static/test/cases/dialog/js/modules/set_password.js +++ b/resources/static/test/cases/dialog/js/modules/set_password.js @@ -10,6 +10,8 @@ el = $("body"), bid = BrowserID, testHelpers = bid.TestHelpers, + testElementExists = testHelpers.testElementExists, + testElementNotExists = testHelpers.testElementDoesNotExist, register = testHelpers.register, controller; @@ -33,22 +35,29 @@ test("create with no options - show template, user must verify email, can cancel", function() { ok($("#set_password").length, "set_password template added"); - equal($("#verify_user").length, 1, "correct button shown"); - equal($("#cancel").length, 1, "cancel button shown"); + testElementExists("#verify_user"); + testElementExists("#cancel"); + testElementNotExists("#persona_tospp"); }); test("create with password_reset option - show template, show reset password button", function() { controller.destroy(); createController({ password_reset: true }); - ok($("#set_password").length, "set_password template added"); - equal($("#password_reset").length, 1, "correct button shown"); - equal($("#cancel").length, 1, "cancel button shown"); + testElementExists("#set_password"); + testElementExists("#password_reset"); + testElementExists("#cancel"); + }); + + test("create with personaTOSPP option - show Persona TOS/PP", function() { + controller.destroy(); + createController({ personaTOSPP: true }); + testElementExists("#persona_tospp"); }); test("create with cancelable=false option - cancel button not shown", function() { controller.destroy(); createController({ cancelable: false }); - equal($("#cancel").length, 0, "cancel button not shown"); + testElementNotExists("#cancel"); }); asyncTest("submit with good password/vpassword - password_set message raised", function() { diff --git a/resources/static/test/cases/dialog/js/modules/verify_primary_user.js b/resources/static/test/cases/dialog/js/modules/verify_primary_user.js index 0bd75f72e9456e2fc72097969fc46d4a2b7766a4..08083a9fe9d3d0ef7908a0d18c1e958a8bed00e9 100644 --- a/resources/static/test/cases/dialog/js/modules/verify_primary_user.js +++ b/resources/static/test/cases/dialog/js/modules/verify_primary_user.js @@ -10,6 +10,8 @@ controller, el, testHelpers = bid.TestHelpers, + testElementExists = testHelpers.testElementExists, + testElementNotExists = testHelpers.testElementDoesNotExist, WindowMock = bid.Mocks.WindowMock, win, mediator = bid.Mediator; @@ -33,31 +35,30 @@ } }); - test("create with privacyURL and tosURL defined - show TOS/PP", function() { + test("personaTOSPP true, requiredEmail: true - show TOS/PP", function() { createController({ window: win, add: false, email: "unregistered@testuser.com", auth_url: "http://testuser.com/sign_in", - privacyURL: "http://testuser.com/priv.html", - tosURL: "http://testuser.com/tos.html" + requiredEmail: true, + personaTOSPP: false }); - equal($(".tospp").length, 1, "tospp has been added to the DOM"); + testElementNotExists("#persona_tospp"); }); - test("create with requiredEmail, privacyURL and tosURL defined - show TOS/PP", function() { + test("personaTOSPP true, requiredEmail: false - show TOS/PP", function() { createController({ window: win, add: false, - requiredEmail: "unregistered@testuser.com", email: "unregistered@testuser.com", auth_url: "http://testuser.com/sign_in", - privacyURL: "http://testuser.com/priv.html", - tosURL: "http://testuser.com/tos.html" + requiredEmail: false, + personaTOSPP: false }); - equal($(".tospp").length, 1, "tospp has been added to the DOM"); + testElementNotExists("#persona_tospp"); }); asyncTest("submit with `add: false` option opens a new tab with proper URL (updated for sessionStorage)", function() { @@ -66,8 +67,12 @@ window: win, add: false, email: "unregistered@testuser.com", - auth_url: "http://testuser.com/sign_in" + auth_url: "http://testuser.com/sign_in", + personaTOSPP: true }); + + testElementExists("#persona_tospp"); + mediator.subscribe("primary_user_authenticating", function() { messageTriggered = true; }); @@ -88,9 +93,12 @@ window: win, add: true, email: "unregistered@testuser.com", - auth_url: "http://testuser.com/sign_in" + auth_url: "http://testuser.com/sign_in", + personaTOSPP: true }); + testElementExists("#persona_tospp"); + // Also checking to make sure the NATIVE is stripped out. win.document.location.href = "sign_in"; win.document.location.hash = "#NATIVE"; diff --git a/resources/static/test/testHelpers/helpers.js b/resources/static/test/testHelpers/helpers.js index 119bd73f64a8f23eec6b6655e63781e11459b751..66868076a8c8cd477b25b2db0e5e1e6023595037 100644 --- a/resources/static/test/testHelpers/helpers.js +++ b/resources/static/test/testHelpers/helpers.js @@ -221,10 +221,6 @@ BrowserID.TestHelpers = (function() { } }, - testHasClass: function(selector, className, msg) { - ok($(selector).hasClass(className), msg || selector + " has className: " + className); - }, - testUndefined: function(toTest, msg) { equal(typeof toTest, "undefined", msg || "object is undefined"); }, @@ -235,8 +231,33 @@ BrowserID.TestHelpers = (function() { testVisible: function(selector, msg) { ok($(selector).is(":visible"), msg || selector + " should be visible"); - } + }, + testHasClass: function(selector, className, msg) { + ok($(selector).hasClass(className), + msg || (selector + " has className " + className)); + }, + + testNotHasClass: function(selector, className, msg) { + ok(!$(selector).hasClass(className), + msg || (selector + " does not have className " + className)); + }, + + testElementExists: function(selector, msg) { + ok($(selector).length, msg || ("element '" + selector + "' exists")); + }, + + testElementDoesNotExist: function(selector, msg) { + ok(!$(selector).length, msg || ("element '" + selector + "' does not exist")); + }, + + testRPTosPPShown: function(msg) { + TestHelpers.testHasClass("body", "rptospp", msg || "RP TOS/PP shown"); + }, + + testRPTosPPNotShown: function(msg) { + TestHelpers.testNotHasClass("body", "rptospp", msg || "RP TOS/PP not shown"); + } }; return TestHelpers; diff --git a/resources/views/signup.ejs b/resources/views/signup.ejs index dcf66e0702c932803c7ca991217b509a4e69323e..9e92bd83b6e5be5865af429ece9f1b226ddd9cb6 100644 --- a/resources/views/signup.ejs +++ b/resources/views/signup.ejs @@ -82,10 +82,20 @@ </ul> <div class="submit cf forminputs"> - <button>Verify Email</button> - <div class="remember cf"> - <a class="action" href="/signin" tabindex="2">Existing account? Sign in.</a> - </div> + <p class="cf"> + <button>Verify Email</button> + <a class="action remember" href="/signin" tabindex="2">Existing account? Sign in.</a> + </p> + + <p class="tospp"> + <%- format( + gettext('By proceeding, you agree to %s\'s <a %s>Terms</a> and <a %s>Privacy Policy</a>.'), + [ "Persona", + ' href="https://login.persona.org/tos" target="_new"', + ' href="https://login.persona.org/privacy" target="_new"', + ]) %> + </p> + </div> <ul class="notifications">