From 7c07097b69b3f6e1b2c68a74447c6e5e38a5b3d7 Mon Sep 17 00:00:00 2001 From: Luke Crouch Date: Fri, 5 Jul 2019 20:31:06 +0000 Subject: [PATCH] Bug 1559365: UI indication of breached logins r=jaws Differential Revision: https://phabricator.services.mozilla.com/D35105 --HG-- extra : moz-landing-system : lando --- browser/components/BrowserGlue.jsm | 1 + .../aboutlogins/AboutLoginsChild.jsm | 3 ++ .../aboutlogins/AboutLoginsParent.jsm | 32 +++++++++++++++++-- .../aboutlogins/content/aboutLogins.js | 4 +++ .../content/components/login-list-item.css | 4 +++ .../content/components/login-list.js | 14 ++++++++ 6 files changed, 56 insertions(+), 2 deletions(-) diff --git a/browser/components/BrowserGlue.jsm b/browser/components/BrowserGlue.jsm index c87c6e06a238..f9fb463342bc 100644 --- a/browser/components/BrowserGlue.jsm +++ b/browser/components/BrowserGlue.jsm @@ -103,6 +103,7 @@ let LEGACY_ACTORS = { }, messages: [ "AboutLogins:AllLogins", + "AboutLogins:UpdateBreaches", "AboutLogins:LoginAdded", "AboutLogins:LoginModified", "AboutLogins:LoginRemoved", diff --git a/browser/components/aboutlogins/AboutLoginsChild.jsm b/browser/components/aboutlogins/AboutLoginsChild.jsm index c2bcbd7540b0..64f65a43e381 100644 --- a/browser/components/aboutlogins/AboutLoginsChild.jsm +++ b/browser/components/aboutlogins/AboutLoginsChild.jsm @@ -111,6 +111,9 @@ class AboutLoginsChild extends ActorChild { case "AboutLogins:AllLogins": this.sendToContent("AllLogins", message.data); break; + case "AboutLogins:UpdateBreaches": + this.sendToContent("UpdateBreaches", message.data); + break; case "AboutLogins:LoginAdded": this.sendToContent("LoginAdded", message.data); break; diff --git a/browser/components/aboutlogins/AboutLoginsParent.jsm b/browser/components/aboutlogins/AboutLoginsParent.jsm index 2c8bff98fb02..505496fc372e 100644 --- a/browser/components/aboutlogins/AboutLoginsParent.jsm +++ b/browser/components/aboutlogins/AboutLoginsParent.jsm @@ -24,6 +24,11 @@ ChromeUtils.defineModuleGetter( "MigrationUtils", "resource:///modules/MigrationUtils.jsm" ); +ChromeUtils.defineModuleGetter( + this, + "RemoteSettings", + "resource://services-settings/remote-settings.js" +); ChromeUtils.defineModuleGetter( this, "Services", @@ -175,9 +180,12 @@ var AboutLoginsParent = { this._subscribers.add(message.target); let messageManager = message.target.messageManager; + const logins = await this.getAllLogins(); + messageManager.sendAsyncMessage("AboutLogins:AllLogins", logins); + const breachesByLoginGUID = await this.getBreachesForLogins(logins); messageManager.sendAsyncMessage( - "AboutLogins:AllLogins", - await this.getAllLogins() + "AboutLogins:UpdateBreaches", + breachesByLoginGUID ); break; } @@ -363,4 +371,24 @@ var AboutLoginsParent = { throw e; } }, + + async getBreachesForLogins(logins) { + const breaches = await RemoteSettings("fxmonitor-breaches").get(); + const breachHostMap = new Map(); + for (const breach of breaches) { + breachHostMap.set(breach.Domain, breach); + } + const breachesByLoginGUID = new Map(); + for (const login of logins) { + const loginURI = Services.io.newURI(login.origin); + const breach = breachHostMap.get(loginURI.host) || false; + if ( + breach && + login.timePasswordChanged < new Date(breach.BreachDate).getTime() + ) { + breachesByLoginGUID.set(login.guid, breach); + } + } + return breachesByLoginGUID; + }, }; diff --git a/browser/components/aboutlogins/content/aboutLogins.js b/browser/components/aboutlogins/content/aboutLogins.js index 796f578e6acf..d7c8823b7c37 100644 --- a/browser/components/aboutlogins/content/aboutLogins.js +++ b/browser/components/aboutlogins/content/aboutLogins.js @@ -39,6 +39,10 @@ window.addEventListener("AboutLoginsChromeToContent", event => { gElements.loginList.setLogins(event.detail.value); break; } + case "UpdateBreaches": { + gElements.loginList.updateBreaches(event.detail.value); + break; + } case "LoginAdded": { gElements.loginList.loginAdded(event.detail.value); gElements.loginItem.loginAdded(event.detail.value); diff --git a/browser/components/aboutlogins/content/components/login-list-item.css b/browser/components/aboutlogins/content/components/login-list-item.css index c2425e6f596c..6783daa7fade 100644 --- a/browser/components/aboutlogins/content/components/login-list-item.css +++ b/browser/components/aboutlogins/content/components/login-list-item.css @@ -29,6 +29,10 @@ background-color: var(--in-content-box-background-hover); } +:host(.breached) { + border-inline-start-color: var(--in-content-border-invalid); +} + .title { font-weight: bold; } diff --git a/browser/components/aboutlogins/content/components/login-list.js b/browser/components/aboutlogins/content/components/login-list.js index 83a96b411e57..02ec9e7c7dd6 100644 --- a/browser/components/aboutlogins/content/components/login-list.js +++ b/browser/components/aboutlogins/content/components/login-list.js @@ -79,6 +79,12 @@ export default class LoginList extends HTMLElement { listItem.setAttribute("aria-selected", "true"); this._list.setAttribute("aria-activedescendant", listItem.id); } + if ( + this._breachesByLoginGUID && + this._breachesByLoginGUID.has(login.guid) + ) { + listItem.classList.add("breached"); + } this._list.append(listItem); } @@ -162,6 +168,14 @@ export default class LoginList extends HTMLElement { } } + /** + * @param {Map} breachesByLoginGUID A Map of breaches by login GUIDs used for displaying breached login indicators. + */ + updateBreaches(breachesByLoginGUID) { + this._breachesByLoginGUID = breachesByLoginGUID; + this.render(); + } + /** * @param {login} login A login that was added to storage. */