зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1564539 - Add breach alerts to login items r=jaws,fluent-reviewers,flod
Differential Revision: https://phabricator.services.mozilla.com/D38571 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
8e83d4b8ba
Коммит
1b17257b95
|
@ -1757,6 +1757,9 @@ pref("signon.management.page.feedbackURL",
|
|||
"https://www.surveygizmo.com/s3/5036102/Lockwise-feedback?ver=%VERSION%");
|
||||
pref("signon.management.page.mobileAndroidURL", "https://app.adjust.com/6tteyjo?redirect=https%3A%2F%2Fplay.google.com%2Fstore%2Fapps%2Fdetails%3Fid%3Dmozilla.lockbox&utm_campaign=Desktop&utm_adgroup=InProduct&utm_creative=Elipsis_Menu");
|
||||
pref("signon.management.page.mobileAppleURL", "https://app.adjust.com/6tteyjo?redirect=https%3A%2F%2Fitunes.apple.com%2Fapp%2Fid1314000270%3Fmt%3D8&utm_campaign=Desktop&utm_adgroup=InProduct&utm_creative=Elipsis_Menu");
|
||||
pref("signon.management.page.breachAlertUrl",
|
||||
"https://monitor.firefox.com/breach-details/");
|
||||
|
||||
// Enable the "Simplify Page" feature in Print Preview. This feature
|
||||
// is disabled by default in toolkit.
|
||||
pref("print.use_simplify_page", true);
|
||||
|
|
|
@ -195,7 +195,6 @@ var AboutLoginsParent = {
|
|||
const logins = await this.getAllLogins();
|
||||
try {
|
||||
messageManager.sendAsyncMessage("AboutLogins:AllLogins", logins);
|
||||
|
||||
if (!BREACH_ALERTS_ENABLED) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -82,6 +82,10 @@
|
|||
<link rel="stylesheet" href="chrome://global/skin/in-content/common.css">
|
||||
<link rel="stylesheet" href="chrome://browser/content/aboutlogins/common.css">
|
||||
<link rel="stylesheet" href="chrome://browser/content/aboutlogins/components/login-item.css">
|
||||
<div class="breach-alert">
|
||||
<span class="breach-alert-text" data-l10n-id="breach-alert-text"></span>
|
||||
<a class="breach-alert-link" data-l10n-id="breach-alert-link" rel="noopener noreferer" target="_blank"></a>
|
||||
</div>
|
||||
<div class="header">
|
||||
<h2 class="title">
|
||||
<span class="login-item-title"></span>
|
||||
|
|
|
@ -33,6 +33,7 @@ window.addEventListener("AboutLoginsChromeToContent", event => {
|
|||
}
|
||||
case "UpdateBreaches": {
|
||||
gElements.loginList.updateBreaches(event.detail.value);
|
||||
gElements.loginItem.updateBreaches(event.detail.value);
|
||||
break;
|
||||
}
|
||||
case "LoginAdded": {
|
||||
|
|
|
@ -11,17 +11,6 @@
|
|||
--success-color: #00c100;
|
||||
}
|
||||
|
||||
@supports -moz-bool-pref("browser.in-content.dark-mode") {
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:host {
|
||||
--reveal-checkbox-opacity: .8;
|
||||
--reveal-checkbox-opacity-hover: 1;
|
||||
--reveal-checkbox-opacity-active: .6;
|
||||
--success-color: #86DE74;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:host([data-editing]) .edit-button,
|
||||
:host([data-editing]) .copy-button,
|
||||
:host([data-editing]) .open-site-button,
|
||||
|
@ -200,3 +189,48 @@
|
|||
-moz-outline-radius: 3px;
|
||||
box-shadow: 0 0 0 4px var(--in-content-border-active-shadow);
|
||||
}
|
||||
|
||||
.breach-alert {
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--in-content-border-color);
|
||||
background-color: #FFFF98;
|
||||
background-image: url("chrome://global/skin/icons/warning.svg");
|
||||
background-repeat: no-repeat;
|
||||
background-position: left 10px top 10px;
|
||||
-moz-context-properties: fill;
|
||||
fill: var(--red-90);
|
||||
box-shadow: 0 2px 8px 0 rgba(12,12,13,0.1);
|
||||
font-size: .9em;
|
||||
font-weight: 300;
|
||||
line-height: 1.4;
|
||||
padding-block: 12px;
|
||||
padding-inline-start: 36px;
|
||||
padding-inline-end: 92px;
|
||||
margin-block-end: 40px;
|
||||
}
|
||||
|
||||
.breach-alert:dir(rtl) {
|
||||
background-position: right 10px top 10px;
|
||||
}
|
||||
|
||||
a.breach-alert-link {
|
||||
color: inherit;
|
||||
text-decoration: underline;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
@supports -moz-bool-pref("browser.in-content.dark-mode") {
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:host {
|
||||
--reveal-checkbox-opacity: .8;
|
||||
--reveal-checkbox-opacity-hover: 1;
|
||||
--reveal-checkbox-opacity-active: .6;
|
||||
--success-color: #86DE74;
|
||||
}
|
||||
|
||||
.breach-alert {
|
||||
box-shadow: 0 2px 8px 0 rgba(249,249,250,0.1);
|
||||
color: #0C0C0D;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,7 @@ export default class LoginItem extends HTMLElement {
|
|||
this._timeCreated = this.shadowRoot.querySelector(".time-created");
|
||||
this._timeChanged = this.shadowRoot.querySelector(".time-changed");
|
||||
this._timeUsed = this.shadowRoot.querySelector(".time-used");
|
||||
this._breachAlert = this.shadowRoot.querySelector(".breach-alert");
|
||||
|
||||
this.render();
|
||||
|
||||
|
@ -77,6 +78,15 @@ export default class LoginItem extends HTMLElement {
|
|||
}
|
||||
|
||||
render() {
|
||||
this._breachAlert.hidden = true;
|
||||
if (this._breachesMap && this._breachesMap.has(this._login.guid)) {
|
||||
const breachDetails = this._breachesMap.get(this._login.guid);
|
||||
const breachAlertLink = this._breachAlert.querySelector(
|
||||
".breach-alert-link"
|
||||
);
|
||||
breachAlertLink.href = breachDetails.breachAlertURL;
|
||||
this._breachAlert.hidden = false;
|
||||
}
|
||||
document.l10n.setAttributes(this._timeCreated, "login-item-time-created", {
|
||||
timeCreated: this._login.timeCreated || "",
|
||||
});
|
||||
|
@ -100,6 +110,11 @@ export default class LoginItem extends HTMLElement {
|
|||
this._updatePasswordRevealState();
|
||||
}
|
||||
|
||||
updateBreaches(breachesByLoginGUID) {
|
||||
this._breachesMap = breachesByLoginGUID;
|
||||
this.render();
|
||||
}
|
||||
|
||||
handleEvent(event) {
|
||||
switch (event.type) {
|
||||
case "AboutLoginsCreateLogin": {
|
||||
|
|
|
@ -79,10 +79,6 @@ ol {
|
|||
background-color: var(--in-content-box-background-hover);
|
||||
}
|
||||
|
||||
.login-list-item.breached {
|
||||
border-inline-start-color: var(--in-content-border-invalid);
|
||||
}
|
||||
|
||||
.login-list-item.selected .title {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
@ -99,3 +95,24 @@ ol {
|
|||
font-size: 0.85em;
|
||||
color: var(--in-content-deemphasized-text);
|
||||
}
|
||||
|
||||
.login-list-item.breached {
|
||||
padding-inline-end: 48px;
|
||||
background-image: url("chrome://global/skin/icons/warning.svg");
|
||||
background-position: right 24px center;
|
||||
background-repeat: no-repeat;
|
||||
-moz-context-properties: fill;
|
||||
fill: var(--red-90);
|
||||
}
|
||||
|
||||
.login-list-item.breached:dir(rtl) {
|
||||
background-position: left 24px center;
|
||||
}
|
||||
|
||||
@supports -moz-bool-pref("browser.in-content.dark-mode") {
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.login-list-item.breached {
|
||||
fill: var(--red-60);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,14 @@ const TEST_LOGIN_2 = {
|
|||
timeLastUsed: "8000",
|
||||
};
|
||||
|
||||
const TEST_BREACH = {
|
||||
Name: "Test-Breach",
|
||||
breachAlertURL: "https://monitor.firefox.com/breach-details/Test-Breach",
|
||||
};
|
||||
|
||||
const TEST_BREACHES_MAP = new Map();
|
||||
TEST_BREACHES_MAP.set(TEST_LOGIN_1.guid, TEST_BREACH);
|
||||
|
||||
add_task(async function setup() {
|
||||
let templateFrame = document.getElementById("templateFrame");
|
||||
let displayEl = document.getElementById("display");
|
||||
|
@ -81,6 +89,26 @@ add_task(async function test_set_login() {
|
|||
ok(copyButtons.every(button => !isHidden(button)), "The copy buttons should be visible when viewing a login");
|
||||
});
|
||||
|
||||
add_task(async function test_update_breaches() {
|
||||
gLoginItem.setLogin(TEST_LOGIN_1);
|
||||
gLoginItem.updateBreaches(TEST_BREACHES_MAP);
|
||||
await asyncElementRendered();
|
||||
|
||||
let correspondingBreach = TEST_BREACHES_MAP.get(gLoginItem._login.guid);
|
||||
let breachAlert = gLoginItem.shadowRoot.querySelector(".breach-alert");
|
||||
ok(!breachAlert.hidden, "Breach alert should be visible");
|
||||
is(breachAlert.querySelector(".breach-alert-link").href, correspondingBreach.breachAlertURL, "Breach alert link should be equal to the correspondingBreach.breachAlertURL.");
|
||||
});
|
||||
|
||||
add_task(async function test_breach_alert_is_correctly_hidden() {
|
||||
gLoginItem.setLogin(TEST_LOGIN_2);
|
||||
gLoginItem.updateBreaches(TEST_BREACHES_MAP);
|
||||
await asyncElementRendered();
|
||||
|
||||
let breachAlert = gLoginItem.shadowRoot.querySelector(".breach-alert");
|
||||
ok(breachAlert.hidden, "Breach alert should not be visible on login without an associated breach.");
|
||||
});
|
||||
|
||||
add_task(async function test_edit_login() {
|
||||
gLoginItem.setLogin(TEST_LOGIN_1);
|
||||
gLoginItem.shadowRoot.querySelector(".edit-button").click();
|
||||
|
|
|
@ -57,6 +57,14 @@ const TEST_LOGIN_3 = {
|
|||
timePasswordChanged: 1559361600000,
|
||||
};
|
||||
|
||||
const TEST_BREACH = {
|
||||
Name: "Test-Breach",
|
||||
breachAlertURL: "https://monitor.firefox.com/breach-details/Test-Breach",
|
||||
};
|
||||
|
||||
const TEST_BREACHES_MAP = new Map();
|
||||
TEST_BREACHES_MAP.set(TEST_LOGIN_1.guid, TEST_BREACH);
|
||||
|
||||
add_task(async function setup() {
|
||||
let templateFrame = document.getElementById("templateFrame");
|
||||
let displayEl = document.getElementById("display");
|
||||
|
@ -149,6 +157,13 @@ add_task(async function test_populated_list() {
|
|||
ok(!loginListItems[1].classList.contains("selected"), "The second item should still not be selected");
|
||||
});
|
||||
|
||||
add_task(async function test_breach_indicator() {
|
||||
gLoginList.updateBreaches(TEST_BREACHES_MAP);
|
||||
let loginListItems = gLoginList.shadowRoot.querySelectorAll(".login-list-item");
|
||||
ok(loginListItems[0].classList.contains("breached"), "The first login should have the .breached class.");
|
||||
ok(!loginListItems[1].classList.contains("breached"), "The second login should not have the .breached class");
|
||||
});
|
||||
|
||||
add_task(async function test_filtered_list() {
|
||||
is(gLoginList.shadowRoot.querySelectorAll(".login-list-item:not([hidden])").length, 2, "Both logins should be visible");
|
||||
let countSpan = gLoginList.shadowRoot.querySelector(".count");
|
||||
|
|
|
@ -10,6 +10,7 @@ login-filter =
|
|||
create-login-button = Create New Login
|
||||
|
||||
## The ⋯ menu that is in the top corner of the page
|
||||
|
||||
menu =
|
||||
.title = Open menu
|
||||
# This menuitem is only visible on Windows
|
||||
|
@ -25,6 +26,7 @@ menu-menuitem-download-android = Lockwise for Android
|
|||
menu-menuitem-download-iphone = Lockwise for iPhone and iPad
|
||||
|
||||
## Login List
|
||||
|
||||
login-list =
|
||||
.aria-label = Logins matching search query
|
||||
login-list-count =
|
||||
|
@ -41,6 +43,7 @@ login-list-item-subtitle-new-login = Enter your login credentials
|
|||
login-list-item-subtitle-missing-username = (no username)
|
||||
|
||||
## Login
|
||||
|
||||
login-item-new-login-title = Create New Login
|
||||
login-item-edit-button = Edit
|
||||
login-item-delete-button = Delete
|
||||
|
@ -68,6 +71,7 @@ login-item-time-created = Created: { DATETIME($timeCreated, day: "numeric", mont
|
|||
login-item-time-used = Last used: { DATETIME($timeUsed, day: "numeric", month: "long", year: "numeric") }
|
||||
|
||||
## Master Password notification
|
||||
|
||||
master-password-notification-message = Please enter your master password to view saved logins & passwords
|
||||
master-password-reload-button =
|
||||
.label = Log in
|
||||
|
@ -79,3 +83,8 @@ confirm-delete-dialog-dismiss-button =
|
|||
.title = Cancel
|
||||
confirm-delete-dialog-cancel-button = Cancel
|
||||
confirm-delete-dialog-confirm-button = Delete
|
||||
|
||||
## Breach Alert notification
|
||||
|
||||
breach-alert-text = Passwords were leaked or stolen from this website since you last updated your login details. Change your password to protect your account.
|
||||
breach-alert-link = Learn more about this breach.
|
||||
|
|
|
@ -1110,6 +1110,10 @@ this.LoginHelper = {
|
|||
if (!breaches) {
|
||||
breaches = await RemoteSettings("fxmonitor-breaches").get();
|
||||
}
|
||||
const BREACH_ALERT_URL = Services.prefs.getStringPref(
|
||||
"signon.management.page.breachAlertUrl"
|
||||
);
|
||||
const baseBreachAlertURL = new URL(BREACH_ALERT_URL);
|
||||
|
||||
// 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
|
||||
|
@ -1125,6 +1129,8 @@ this.LoginHelper = {
|
|||
Services.eTLD.hasRootDomain(loginURI.host, breach.Domain) &&
|
||||
login.timePasswordChanged < new Date(breach.BreachDate).getTime()
|
||||
) {
|
||||
let breachAlertURL = new URL(breach.Name, baseBreachAlertURL);
|
||||
breach.breachAlertURL = breachAlertURL.href;
|
||||
breachesByLoginGUID.set(login.guid, breach);
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче