Bug 1559427 - Display data from Lockwise on the Monitor card. r=MattN

Depends on D38228

Differential Revision: https://phabricator.services.mozilla.com/D38385

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Micah Tigley 2019-07-23 18:22:28 +00:00
Родитель 2e658e3d4b
Коммит 3ec2df99e1
7 изменённых файлов: 110 добавлений и 63 удалений

Просмотреть файл

@ -20,6 +20,11 @@ ChromeUtils.defineModuleGetter(
"fxAccounts",
"resource://gre/modules/FxAccounts.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"LoginHelper",
"resource://gre/modules/LoginHelper.jsm"
);
XPCOMUtils.defineLazyServiceGetter(
this,
@ -170,11 +175,13 @@ var AboutProtectionsHandler = {
* @return {{ monitoredEmails: Number,
* numBreaches: Number,
* passwords: Number,
* potentiallyBreachedLogins: Number,
* error: Boolean }}
* Monitor data.
*/
async getMonitorData() {
let monitorData = {};
let potentiallyBreachedLogins = 0;
const hasFxa = await fxAccounts.accountStatus();
if (hasFxa) {
@ -201,6 +208,12 @@ var AboutProtectionsHandler = {
monitorData.errorMessage = e.message;
}
}
// Get the stats for number of potentially breached Lockwise passwords
const logins = await LoginHelper.getAllUserFacingLogins();
potentiallyBreachedLogins = await LoginHelper.getBreachesForLogins(
logins
);
} else {
// If no account exists, then the user is not logged in with an fxAccount.
monitorData = {
@ -210,6 +223,7 @@ var AboutProtectionsHandler = {
return {
...monitorData,
potentiallyBreachedLogins: potentiallyBreachedLogins.size,
error: !!monitorData.errorMessage,
};
},

Просмотреть файл

@ -24,11 +24,6 @@ ChromeUtils.defineModuleGetter(
"MigrationUtils",
"resource:///modules/MigrationUtils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"RemoteSettings",
"resource://services-settings/remote-settings.js"
);
ChromeUtils.defineModuleGetter(
this,
"Services",
@ -67,14 +62,10 @@ const EXPECTED_ABOUTLOGINS_REMOTE_TYPE = PRIVILEGEDABOUT_PROCESS_ENABLED
? E10SUtils.PRIVILEGEDABOUT_REMOTE_TYPE
: E10SUtils.DEFAULT_REMOTE_TYPE;
const isValidLogin = login => {
return !(login.origin || "").startsWith("chrome://");
};
const convertSubjectToLogin = subject => {
subject.QueryInterface(Ci.nsILoginMetaInfo).QueryInterface(Ci.nsILoginInfo);
const login = LoginHelper.loginToVanillaObject(subject);
if (!isValidLogin(login)) {
if (!LoginHelper.isUserFacingLogin(login)) {
return null;
}
return augmentVanillaLoginObject(login);
@ -188,22 +179,22 @@ var AboutLoginsParent = {
this._subscribers.add(message.target);
let messageManager = message.target.messageManager;
this.getAllLogins().then(async logins => {
messageManager.sendAsyncMessage("AboutLogins:AllLogins", logins);
if (!BREACH_ALERTS_ENABLED) {
return;
}
const breaches = await RemoteSettings("fxmonitor-breaches").get();
const breachesByLoginGUID = await this.getBreachesForLogins(
logins,
breaches
);
messageManager.sendAsyncMessage(
"AboutLogins:UpdateBreaches",
breachesByLoginGUID
);
});
const logins = await this.getAllLogins();
messageManager.sendAsyncMessage("AboutLogins:AllLogins", logins);
if (!BREACH_ALERTS_ENABLED) {
return;
}
const breachesByLoginGUID = await LoginHelper.getBreachesForLogins(
logins
);
messageManager.sendAsyncMessage(
"AboutLogins:UpdateBreaches",
breachesByLoginGUID
);
break;
}
case "AboutLogins:UpdateLogin": {
@ -375,9 +366,8 @@ var AboutLoginsParent = {
async getAllLogins() {
try {
let logins = await Services.logins.getAllLoginsAsync();
let logins = await LoginHelper.getAllUserFacingLogins();
return logins
.filter(isValidLogin)
.map(LoginHelper.loginToVanillaObject)
.map(augmentVanillaLoginObject);
} catch (e) {
@ -388,23 +378,4 @@ var AboutLoginsParent = {
throw e;
}
},
async getBreachesForLogins(logins, breaches) {
const breachesByLoginGUID = new Map();
for (const login of logins) {
const loginURI = Services.io.newURI(login.origin);
for (const breach of breaches) {
if (!breach.Domain) {
continue;
}
if (
Services.eTLD.hasRootDomain(loginURI.host, breach.Domain) &&
login.timePasswordChanged < new Date(breach.BreachDate).getTime()
) {
breachesByLoginGUID.set(login.guid, breach);
}
}
}
return breachesByLoginGUID;
},
};

Просмотреть файл

@ -1,5 +1,5 @@
/**
* Test AboutLoginsParent.getBreachesForLogins
* Test LoginHelper.getBreachesForLogins
*/
"use strict";
@ -9,6 +9,12 @@ const { AboutLoginsParent } = ChromeUtils.import(
"resource:///modules/AboutLoginsParent.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"LoginHelper",
"resource://gre/modules/LoginHelper.jsm"
);
const TEST_BREACHES = [
{
AddedDate: "2018-12-20T23:56:26Z",
@ -65,7 +71,7 @@ const BREACHED_SUBDOMAIN_LOGIN = LoginTestUtils.testData.formLogin({
add_task(async function test_getBreachesForLogins_notBreachedLogin() {
Services.logins.addLogin(NOT_BREACHED_LOGIN);
const breachesByLoginGUID = await AboutLoginsParent.getBreachesForLogins(
const breachesByLoginGUID = await LoginHelper.getBreachesForLogins(
[NOT_BREACHED_LOGIN],
TEST_BREACHES
);
@ -79,7 +85,7 @@ add_task(async function test_getBreachesForLogins_notBreachedLogin() {
add_task(async function test_getBreachesForLogins_breachedLogin() {
Services.logins.addLogin(BREACHED_LOGIN);
const breachesByLoginGUID = await AboutLoginsParent.getBreachesForLogins(
const breachesByLoginGUID = await LoginHelper.getBreachesForLogins(
[NOT_BREACHED_LOGIN, BREACHED_LOGIN],
TEST_BREACHES
);
@ -93,7 +99,7 @@ add_task(async function test_getBreachesForLogins_breachedLogin() {
add_task(async function test_getBreachesForLogins_notBreachedSubdomain() {
Services.logins.addLogin(NOT_BREACHED_SUBDOMAIN_LOGIN);
const breachesByLoginGUID = await AboutLoginsParent.getBreachesForLogins(
const breachesByLoginGUID = await LoginHelper.getBreachesForLogins(
[NOT_BREACHED_LOGIN, NOT_BREACHED_SUBDOMAIN_LOGIN],
TEST_BREACHES
);
@ -107,7 +113,7 @@ add_task(async function test_getBreachesForLogins_notBreachedSubdomain() {
add_task(async function test_getBreachesForLogins_breachedSubdomain() {
Services.logins.addLogin(BREACHED_SUBDOMAIN_LOGIN);
const breachesByLoginGUID = await AboutLoginsParent.getBreachesForLogins(
const breachesByLoginGUID = await LoginHelper.getBreachesForLogins(
[NOT_BREACHED_SUBDOMAIN_LOGIN, BREACHED_SUBDOMAIN_LOGIN],
TEST_BREACHES
);

Просмотреть файл

@ -78,14 +78,13 @@ export default class MonitorClass {
"span[data-type='exposed-passwords']"
);
const exposedLockwisePasswords = this.doc.querySelector(
".number-of-breaches.block"
"span[data-type='breached-lockwise-passwords']"
);
storedEmail.textContent = monitorData.monitoredEmails;
knownBreaches.textContent = monitorData.numBreaches;
exposedPasswords.textContent = monitorData.passwords;
// TODO: Bug 1559427: Display data from Lockwise here
exposedLockwisePasswords.textContent = 2;
exposedLockwisePasswords.textContent =
monitorData.potentiallyBreachedLogins;
}
}

Просмотреть файл

@ -138,12 +138,12 @@
<a href="">Firefox Monitor</a>
</div>
<div class="monitor-breached-passwords">
<span class="number-of-breaches block">
<span data-type="breached-lockwise-passwords" class="number-of-breaches block">
<!-- Display number of exposed stored passwords here. -->
</span>
<span class="">
Saved passwords have appeared in known data breaches. Change these passwords to protect your accounts.
<a href="">Open Lockwise</a>
<span>
Passwords saved in Firefox may have been exposed in a data breach. Change these passwords to protect your accounts.
<a href="">View Saved Logins</a>
</span>
</div>
</div>

Просмотреть файл

@ -28,7 +28,7 @@ let fakeDataWithNoError = {
monitoredEmails: 1,
numBreaches: 11,
passwords: 8,
lockwisePasswords: 2,
potentiallyBreachedLogins: 2,
error: false,
};
@ -36,7 +36,7 @@ let fakeDataWithError = {
monitoredEmails: null,
numBreaches: null,
passwords: null,
lockwisePasswords: null,
potentiallyBreachedLogins: null,
error: true,
};
@ -108,10 +108,18 @@ add_task(async function() {
const breaches = content.document.querySelector(
".monitor-stat span[data-type='known-breaches']"
);
const breachedLockwisePasswords = content.document.querySelector(
".monitor-breached-passwords span[data-type='breached-lockwise-passwords']"
);
is(emails.textContent, 1, "1 monitored email is displayed");
is(passwords.textContent, 8, "8 exposed stored passwords is displayed");
is(breaches.textContent, 11, "11 known data breaches is displayed.");
is(passwords.textContent, 8, "8 exposed passwords are displayed");
is(breaches.textContent, 11, "11 known data breaches are displayed.");
is(
breachedLockwisePasswords.textContent,
2,
"2 saved passwords are displayed."
);
});
info(

Просмотреть файл

@ -21,6 +21,12 @@ const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"RemoteSettings",
"resource://services-settings/remote-settings.js"
);
/**
* Contains functions shared by different Login Manager components.
*/
@ -1082,6 +1088,49 @@ this.LoginHelper = {
changeType
);
},
isUserFacingLogin(login) {
return !login.origin.startsWith("chrome://");
},
async getAllUserFacingLogins() {
try {
let logins = await Services.logins.getAllLoginsAsync();
return logins.filter(this.isUserFacingLogin);
} catch (e) {
if (e.result == Cr.NS_ERROR_ABORT) {
// If the user cancels the MP prompt then return no logins.
return [];
}
throw e;
}
},
async getBreachesForLogins(logins, breaches = null) {
if (!breaches) {
breaches = await RemoteSettings("fxmonitor-breaches").get();
}
// Determine potentially breached logins by checking their origin and the last time
// they were changed. It's important to note here that we are NOT considering the
// username and password of that login.
const breachesByLoginGUID = new Map();
for (const login of logins) {
const loginURI = Services.io.newURI(login.origin);
for (const breach of breaches) {
if (!breach.Domain) {
continue;
}
if (
Services.eTLD.hasRootDomain(loginURI.host, breach.Domain) &&
login.timePasswordChanged < new Date(breach.BreachDate).getTime()
) {
breachesByLoginGUID.set(login.guid, breach);
}
}
}
return breachesByLoginGUID;
},
};
LoginHelper.init();