зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1613620 - Provide an option to remove all logins at once from about:logins. r=prathiksha,fluent-reviewers,sfoster,markh
Depends on D89078 Differential Revision: https://phabricator.services.mozilla.com/D91198
This commit is contained in:
Родитель
f776631bec
Коммит
973bb4dad6
|
@ -155,6 +155,7 @@ let JSWINDOWACTORS = {
|
|||
AboutLoginsOpenPreferences: { wantUntrusted: true },
|
||||
AboutLoginsOpenSite: { wantUntrusted: true },
|
||||
AboutLoginsRecordTelemetryEvent: { wantUntrusted: true },
|
||||
AboutLoginsRemoveAllLogins: { wantUntrusted: true },
|
||||
AboutLoginsSortChanged: { wantUntrusted: true },
|
||||
AboutLoginsSyncEnable: { wantUntrusted: true },
|
||||
AboutLoginsSyncOptions: { wantUntrusted: true },
|
||||
|
|
|
@ -180,6 +180,10 @@ class AboutLoginsChild extends JSWindowActorChild {
|
|||
recordTelemetryEvent(event.detail);
|
||||
break;
|
||||
}
|
||||
case "AboutLoginsRemoveAllLogins": {
|
||||
this.sendAsyncMessage("AboutLogins:RemoveAllLogins");
|
||||
break;
|
||||
}
|
||||
case "AboutLoginsSortChanged": {
|
||||
this.sendAsyncMessage("AboutLogins:SortChanged", event.detail);
|
||||
break;
|
||||
|
|
|
@ -426,6 +426,10 @@ class AboutLoginsParent extends JSWindowActorParent {
|
|||
fp.open(fpCallback);
|
||||
break;
|
||||
}
|
||||
case "AboutLogins:RemoveAllLogins": {
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -790,12 +794,14 @@ var AboutLogins = {
|
|||
// authenticated. More diagnostics and error states can be handled
|
||||
// by other more Sync-specific pages.
|
||||
const loggedIn = state.status != UIState.STATUS_NOT_CONFIGURED;
|
||||
const passwordSyncEnabled = state.syncEnabled && PASSWORD_SYNC_ENABLED;
|
||||
|
||||
return {
|
||||
loggedIn,
|
||||
email: state.email,
|
||||
avatarURL: state.avatarURL,
|
||||
fxAccountsEnabled: FXA_ENABLED,
|
||||
passwordSyncEnabled,
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -815,6 +821,7 @@ var AboutLogins = {
|
|||
onPasswordSyncEnabledPreferenceChange(data, previous, latest) {
|
||||
Services.prefs.clearUserPref(SHOW_PASSWORD_SYNC_NOTIFICATION_PREF);
|
||||
this.updatePasswordSyncNotificationState(this.getSyncState(), latest);
|
||||
this.messageSubscribers("AboutLogins:SyncState", this.getSyncState());
|
||||
},
|
||||
};
|
||||
var _AboutLogins = AboutLogins;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
<link rel="localization" href="browser/branding/brandings.ftl">
|
||||
<link rel="localization" href="browser/aboutLogins.ftl">
|
||||
<script type="module" src="chrome://browser/content/aboutlogins/components/confirmation-dialog.js"></script>
|
||||
<script type="module" src="chrome://browser/content/aboutlogins/components/remove-logins-dialog.js"></script>
|
||||
<script type="module" src="chrome://browser/content/aboutlogins/components/fxaccounts-button.js"></script>
|
||||
<script type="module" src="chrome://browser/content/aboutlogins/components/login-filter.js"></script>
|
||||
<script type="module" src="chrome://browser/content/aboutlogins/components/login-intro.js"></script>
|
||||
|
@ -37,6 +38,7 @@
|
|||
<login-item></login-item>
|
||||
<login-intro></login-intro>
|
||||
<confirmation-dialog hidden></confirmation-dialog>
|
||||
<remove-logins-dialog hidden></remove-logins-dialog>
|
||||
<div id="master-password-required-overlay"></div>
|
||||
|
||||
<template id="confirmation-dialog-template">
|
||||
|
@ -61,6 +63,31 @@
|
|||
</div>
|
||||
</template>
|
||||
|
||||
<template id="remove-logins-dialog-template">
|
||||
<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/remove-logins-dialog.css">
|
||||
<div class="overlay">
|
||||
<div class="container" role="dialog" aria-labelledby="title" aria-describedby="message">
|
||||
<button class="dismiss-button" data-l10n-id="confirmation-dialog-dismiss-button">
|
||||
<img class="dismiss-icon" src="chrome://global/skin/icons/close.svg"/>
|
||||
</button>
|
||||
<div class="content">
|
||||
<img class="warning-icon" src="chrome://global/skin/icons/delete.svg"/>
|
||||
<h1 class="title" id="title"></h1>
|
||||
<p class="message" id="message"></p>
|
||||
<div class="checkbox-wrapper">
|
||||
<input id="confirmation-checkbox" type="checkbox" class="checkbox"></input>
|
||||
<label for="confirmation-checkbox"></label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<button class="confirm-button danger-button"></button>
|
||||
<button class="cancel-button" data-l10n-id="confirmation-dialog-cancel-button"></button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="fxaccounts-button-template">
|
||||
<link rel="stylesheet" href="chrome://global/skin/in-content/common.css">
|
||||
<link rel="stylesheet" href="chrome://browser/content/aboutlogins/common.css">
|
||||
|
@ -275,6 +302,7 @@
|
|||
<button role="menuitem" class="menuitem-button menuitem-import-browser ghost-button" hidden data-supported-platforms="Win32,MacIntel" data-event-name="AboutLoginsImportFromBrowser" data-l10n-id="about-logins-menu-menuitem-import-from-another-browser"></button>
|
||||
<button role="menuitem" class="menuitem-button menuitem-import-file ghost-button" data-event-name="AboutLoginsImportFromFile" data-l10n-id="about-logins-menu-menuitem-import-from-a-file"></button>
|
||||
<button role="menuitem" class="menuitem-button menuitem-export ghost-button" data-event-name="AboutLoginsExportPasswordsDialog" data-l10n-id="about-logins-menu-menuitem-export-logins"></button>
|
||||
<button role="menuitem" class="menuitem-button menuitem-remove-all-logins ghost-button" data-event-name="AboutLoginsRemoveAllLoginsDialog" data-l10n-id="about-logins-menu-menuitem-remove-all-logins"></button>
|
||||
<hr role="separator" class="menuitem-separator"></hr>
|
||||
<button role="menuitem" class="menuitem-button menuitem-preferences ghost-button" data-event-name="AboutLoginsOpenPreferences" data-l10n-id="menu-menuitem-preferences"></button>
|
||||
<hr role="separator" class="menuitem-separator"></hr>
|
||||
|
|
|
@ -15,6 +15,13 @@ const gElements = {
|
|||
loginIntro: document.querySelector("login-intro"),
|
||||
loginItem: document.querySelector("login-item"),
|
||||
loginFilter: document.querySelector("login-filter"),
|
||||
menuButton: document.querySelector("menu-button"),
|
||||
// removeAllLogins button is nested inside of menuButton
|
||||
get removeAllButton() {
|
||||
return this.menuButton.shadowRoot.querySelector(
|
||||
".menuitem-remove-all-logins"
|
||||
);
|
||||
},
|
||||
};
|
||||
|
||||
let numberOfLogins = 0;
|
||||
|
@ -23,6 +30,7 @@ function updateNoLogins() {
|
|||
document.documentElement.classList.toggle("no-logins", numberOfLogins == 0);
|
||||
gElements.loginList.classList.toggle("no-logins", numberOfLogins == 0);
|
||||
gElements.loginItem.classList.toggle("no-logins", numberOfLogins == 0);
|
||||
gElements.removeAllButton.disabled = numberOfLogins == 0;
|
||||
}
|
||||
|
||||
function handleAllLogins(logins) {
|
||||
|
@ -31,9 +39,14 @@ function handleAllLogins(logins) {
|
|||
updateNoLogins();
|
||||
}
|
||||
|
||||
let fxaLoggedIn = null;
|
||||
let passwordSyncEnabled = null;
|
||||
|
||||
function handleSyncState(syncState) {
|
||||
gElements.fxAccountsButton.updateState(syncState);
|
||||
gElements.loginIntro.updateState(syncState);
|
||||
fxaLoggedIn = syncState.loggedIn;
|
||||
passwordSyncEnabled = syncState.passwordSyncEnabled;
|
||||
}
|
||||
|
||||
window.addEventListener("AboutLoginsChromeToContent", event => {
|
||||
|
@ -115,6 +128,40 @@ window.addEventListener("AboutLoginsChromeToContent", event => {
|
|||
}
|
||||
});
|
||||
|
||||
window.addEventListener("AboutLoginsRemoveAllLoginsDialog", () => {
|
||||
let options = {};
|
||||
if (fxaLoggedIn && passwordSyncEnabled) {
|
||||
options.title = "about-logins-confirm-remove-all-sync-dialog-title";
|
||||
options.message = "about-logins-confirm-remove-all-sync-dialog-message";
|
||||
} else {
|
||||
options.title = "about-logins-confirm-remove-all-dialog-title";
|
||||
options.message = "about-logins-confirm-remove-all-dialog-message";
|
||||
}
|
||||
options.confirmCheckboxLabel =
|
||||
"about-logins-confirm-remove-all-dialog-checkbox-label";
|
||||
options.confirmButtonLabel =
|
||||
"about-logins-confirm-remove-all-dialog-confirm-button";
|
||||
options.count = numberOfLogins;
|
||||
|
||||
let dialog = document.querySelector("remove-logins-dialog");
|
||||
let dialogPromise = dialog.show(options);
|
||||
try {
|
||||
dialogPromise.then(
|
||||
() => {
|
||||
let removeAllEvt = new CustomEvent("AboutLoginsRemoveAllLogins", {
|
||||
bubbles: true,
|
||||
});
|
||||
window.dispatchEvent(removeAllEvt);
|
||||
},
|
||||
() => {}
|
||||
);
|
||||
} catch (e) {
|
||||
if (e != undefined) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener("AboutLoginsExportPasswordsDialog", async event => {
|
||||
recordTelemetryEvent({
|
||||
object: "export",
|
||||
|
|
|
@ -78,6 +78,10 @@
|
|||
background-image: url("chrome://browser/skin/save.svg");
|
||||
}
|
||||
|
||||
.menuitem-remove-all-logins {
|
||||
background-image: url("chrome://global/skin/icons/delete.svg");
|
||||
}
|
||||
|
||||
.menuitem-preferences {
|
||||
background-image: url("chrome://global/skin/icons/settings.svg");
|
||||
}
|
||||
|
|
|
@ -129,6 +129,13 @@ export default class MenuButton extends HTMLElement {
|
|||
if (this._menu.hidden) {
|
||||
this._showMenu();
|
||||
}
|
||||
if (successor.disabled) {
|
||||
if (next) {
|
||||
successor = items[activeItemIndex + 2];
|
||||
} else {
|
||||
successor = items[activeItemIndex - 2];
|
||||
}
|
||||
}
|
||||
successor.focus();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
/* 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/. */
|
||||
|
||||
.overlay {
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
inset: 0;
|
||||
/* TODO: this color is used in the about:preferences overlay, but
|
||||
why isn't it declared as a variable? */
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.container {
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 300px;
|
||||
max-width: 660px;
|
||||
min-height: 200px;
|
||||
align-self: center;
|
||||
margin-inline-start: calc(var(--sidebar-width) - 48px);
|
||||
background-color: var(--in-content-page-background);
|
||||
color: var(--in-content-text-color);
|
||||
box-shadow: var(--shadow-30);
|
||||
/* show a border in high contrast mode */
|
||||
outline: 1px solid transparent;
|
||||
}
|
||||
|
||||
.title {
|
||||
grid-area: 1 / 2 / 2 / 8;
|
||||
}
|
||||
|
||||
.message {
|
||||
font-weight: 600;
|
||||
grid-area: 2 / 2 / 3 / 8;
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
label[for="confirmation-checkbox"] {
|
||||
font-size: 1.25em;
|
||||
}
|
||||
|
||||
.dismiss-button {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
inset-inline-end: 0;
|
||||
min-width: 20px;
|
||||
min-height: 20px;
|
||||
margin: 16px;
|
||||
padding: 0;
|
||||
line-height: 0;
|
||||
}
|
||||
|
||||
.dismiss-icon {
|
||||
-moz-context-properties: fill, fill-opacity;
|
||||
fill: currentColor;
|
||||
fill-opacity: 0;
|
||||
}
|
||||
|
||||
.warning-icon {
|
||||
-moz-context-properties: fill;
|
||||
fill: currentColor;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin: 8px;
|
||||
}
|
||||
|
||||
.content,
|
||||
.buttons {
|
||||
padding: 36px 48px;
|
||||
padding-bottom: 24px;
|
||||
}
|
||||
|
||||
.content {
|
||||
display: grid;
|
||||
grid-template-columns: 0.5fr 1fr 1fr 1fr 1fr 1fr 1fr;
|
||||
grid-template-rows: 0.5fr 0.5fr 0.5fr;
|
||||
}
|
||||
|
||||
.checkbox-wrapper {
|
||||
display: flex;
|
||||
grid-area: 3 / 2 / 4 / 8;
|
||||
align-self: first baseline;
|
||||
}
|
||||
|
||||
.warning-icon {
|
||||
grid-area: 1 / 1 / 2 / 2;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
grid-area: 3 / 2 / 4 / 8;
|
||||
font-size: 1.1em;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
padding-block: 16px 32px;
|
||||
padding-inline: 48px 0;
|
||||
border-top: 1px solid var(--in-content-border-color);
|
||||
margin-inline: 48px;
|
||||
}
|
||||
|
||||
.buttons.macosx > .confirm-button {
|
||||
order: 1;
|
||||
}
|
||||
|
||||
.buttons > button {
|
||||
min-width: 140px;
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/* 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/. */
|
||||
|
||||
import { setKeyboardAccessForNonDialogElements } from "../aboutLoginsUtils.js";
|
||||
|
||||
export default class RemoveLoginsDialog extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this._promise = null;
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
if (this.shadowRoot) {
|
||||
return;
|
||||
}
|
||||
let template = document.querySelector("#remove-logins-dialog-template");
|
||||
let shadowRoot = this.attachShadow({ mode: "open" });
|
||||
document.l10n.connectRoot(shadowRoot);
|
||||
shadowRoot.appendChild(template.content.cloneNode(true));
|
||||
|
||||
this._buttons = this.shadowRoot.querySelector(".buttons");
|
||||
this._cancelButton = this.shadowRoot.querySelector(".cancel-button");
|
||||
this._confirmButton = this.shadowRoot.querySelector(".confirm-button");
|
||||
this._dismissButton = this.shadowRoot.querySelector(".dismiss-button");
|
||||
this._message = this.shadowRoot.querySelector(".message");
|
||||
this._overlay = this.shadowRoot.querySelector(".overlay");
|
||||
this._title = this.shadowRoot.querySelector(".title");
|
||||
this._checkbox = this.shadowRoot.querySelector(".checkbox");
|
||||
this._checkboxLabel = this.shadowRoot.querySelector(
|
||||
"label[for='confirmation-checkbox']"
|
||||
);
|
||||
|
||||
this._buttons.classList.toggle("macosx", navigator.platform == "MacIntel");
|
||||
}
|
||||
|
||||
handleEvent(event) {
|
||||
switch (event.type) {
|
||||
case "keydown":
|
||||
if (event.key === "Escape" && !event.defaultPrevented) {
|
||||
this.onCancel();
|
||||
}
|
||||
break;
|
||||
case "click":
|
||||
if (
|
||||
event.target.classList.contains("cancel-button") ||
|
||||
event.currentTarget.classList.contains("dismiss-button") ||
|
||||
event.target.classList.contains("overlay")
|
||||
) {
|
||||
this.onCancel();
|
||||
} else if (event.target.classList.contains("confirm-button")) {
|
||||
this.onConfirm();
|
||||
} else if (event.target.classList.contains("checkbox")) {
|
||||
this._confirmButton.disabled = !this._checkbox.checked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hide() {
|
||||
setKeyboardAccessForNonDialogElements(true);
|
||||
this._cancelButton.removeEventListener("click", this);
|
||||
this._confirmButton.removeEventListener("click", this);
|
||||
this._dismissButton.removeEventListener("click", this);
|
||||
this._overlay.removeEventListener("click", this);
|
||||
this._checkbox.removeEventListener("click", this);
|
||||
window.removeEventListener("keydown", this);
|
||||
|
||||
this._checkbox.checked = false;
|
||||
|
||||
this.hidden = true;
|
||||
}
|
||||
|
||||
show({ title, message, confirmButtonLabel, confirmCheckboxLabel, count }) {
|
||||
setKeyboardAccessForNonDialogElements(false);
|
||||
this.hidden = false;
|
||||
|
||||
document.l10n.setAttributes(this._title, title, {
|
||||
count,
|
||||
});
|
||||
document.l10n.setAttributes(this._message, message, {
|
||||
count,
|
||||
});
|
||||
document.l10n.setAttributes(this._confirmButton, confirmButtonLabel);
|
||||
document.l10n.setAttributes(this._checkboxLabel, confirmCheckboxLabel, {
|
||||
count,
|
||||
});
|
||||
|
||||
this._checkbox.addEventListener("click", this);
|
||||
this._cancelButton.addEventListener("click", this);
|
||||
this._confirmButton.addEventListener("click", this);
|
||||
this._dismissButton.addEventListener("click", this);
|
||||
this._overlay.addEventListener("click", this);
|
||||
window.addEventListener("keydown", this);
|
||||
|
||||
this._confirmButton.disabled = true;
|
||||
// For speed-of-use, focus the confirmation checkbox when the dialog loads.
|
||||
// Introducing this checkbox provides enough of a buffer for accidental deletions.
|
||||
this._checkbox.focus();
|
||||
|
||||
this._promise = new Promise((resolve, reject) => {
|
||||
this._resolve = resolve;
|
||||
this._reject = reject;
|
||||
});
|
||||
|
||||
return this._promise;
|
||||
}
|
||||
|
||||
onCancel() {
|
||||
this._reject();
|
||||
this.hide();
|
||||
}
|
||||
|
||||
onConfirm() {
|
||||
this._resolve();
|
||||
this.hide();
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("remove-logins-dialog", RemoveLoginsDialog);
|
|
@ -5,6 +5,8 @@
|
|||
browser.jar:
|
||||
content/browser/aboutlogins/components/confirmation-dialog.css (content/components/confirmation-dialog.css)
|
||||
content/browser/aboutlogins/components/confirmation-dialog.js (content/components/confirmation-dialog.js)
|
||||
content/browser/aboutlogins/components/remove-logins-dialog.css (content/components/remove-logins-dialog.css)
|
||||
content/browser/aboutlogins/components/remove-logins-dialog.js (content/components/remove-logins-dialog.js)
|
||||
content/browser/aboutlogins/components/fxaccounts-button.css (content/components/fxaccounts-button.css)
|
||||
content/browser/aboutlogins/components/fxaccounts-button.js (content/components/fxaccounts-button.js)
|
||||
content/browser/aboutlogins/components/login-filter.css (content/components/login-filter.css)
|
||||
|
|
|
@ -37,6 +37,7 @@ skip-if = (os != "win" && os != "mac") # import is only available on Windows and
|
|||
[browser_openSite.js]
|
||||
[browser_osAuthDialog.js]
|
||||
skip-if = (os == 'linux') # bug 1527745
|
||||
[browser_removeAllDialog.js]
|
||||
[browser_sessionRestore.js]
|
||||
skip-if = debug # Bug 1576876
|
||||
[browser_tabKeyNav.js]
|
||||
|
|
|
@ -50,7 +50,7 @@ add_task(async function setup() {
|
|||
});
|
||||
registerCleanupFunction(() => {
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@ add_task(async function setup() {
|
|||
});
|
||||
registerCleanupFunction(() => {
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ add_task(async function setup() {
|
|||
});
|
||||
registerCleanupFunction(() => {
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ add_task(async function setup() {
|
|||
});
|
||||
registerCleanupFunction(() => {
|
||||
BrowserTestUtils.removeTab(aboutLoginsTab);
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ add_task(async function setup() {
|
|||
});
|
||||
registerCleanupFunction(() => {
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -124,7 +124,7 @@ add_task(async function test_all_logins_removed() {
|
|||
);
|
||||
});
|
||||
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
|
||||
await SpecialPowers.spawn(browser, [], async () => {
|
||||
let loginList = Cu.waiveXrays(content.document.querySelector("login-list"));
|
||||
|
|
|
@ -25,7 +25,7 @@ add_task(async function setup() {
|
|||
TEST_LOGIN3 = await addLogin(TEST_LOGIN3);
|
||||
info(`TEST_LOGIN3 added with guid=${TEST_LOGIN3.guid}`);
|
||||
registerCleanupFunction(() => {
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
Services.prefs.clearUserPref(SORT_PREF_NAME);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -43,7 +43,7 @@ add_task(async function test() {
|
|||
await mpDialogShown;
|
||||
|
||||
registerCleanupFunction(async function() {
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ add_task(async function setup() {
|
|||
await tabOpenedPromise;
|
||||
registerCleanupFunction(() => {
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ add_task(async function setup() {
|
|||
});
|
||||
registerCleanupFunction(() => {
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ add_task(async function test() {
|
|||
});
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,326 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
/* eslint-disable mozilla/no-arbitrary-setTimeout */
|
||||
|
||||
ChromeUtils.import("resource://testing-common/OSKeyStoreTestUtils.jsm", this);
|
||||
|
||||
async function openRemoveAllDialog(browser) {
|
||||
await SimpleTest.promiseFocus(browser);
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter("menu-button", {}, browser);
|
||||
function getRemoveAllMenuButton() {
|
||||
let menuButton = window.document.querySelector("menu-button");
|
||||
return menuButton.shadowRoot.querySelector(".menuitem-remove-all-logins");
|
||||
}
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter(
|
||||
getRemoveAllMenuButton,
|
||||
{},
|
||||
browser
|
||||
);
|
||||
info("remove all dialog should be opened");
|
||||
}
|
||||
|
||||
async function waitForRemoveAllLogins() {
|
||||
return new Promise(resolve => {
|
||||
Services.obs.addObserver(function observer(subject, topic, changeType) {
|
||||
if (changeType != "removeAllLogins") {
|
||||
return;
|
||||
}
|
||||
|
||||
Services.obs.removeObserver(observer, "passwordmgr-storage-changed");
|
||||
resolve();
|
||||
}, "passwordmgr-storage-changed");
|
||||
});
|
||||
}
|
||||
|
||||
add_task(async function setup() {
|
||||
await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser,
|
||||
url: "about:logins",
|
||||
});
|
||||
registerCleanupFunction(() => {
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
TEST_LOGIN1 = await addLogin(TEST_LOGIN1);
|
||||
});
|
||||
|
||||
add_task(async function test_remove_all_dialog_l10n() {
|
||||
ok(TEST_LOGIN1, "test_login1");
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
await openRemoveAllDialog(browser);
|
||||
await SpecialPowers.spawn(browser, [], async () => {
|
||||
const EventUtils = ContentTaskUtils.getEventUtils(content);
|
||||
let dialog = Cu.waiveXrays(
|
||||
content.document.querySelector("remove-logins-dialog")
|
||||
);
|
||||
ok(!dialog.hidden);
|
||||
let title = dialog.shadowRoot.querySelector(".title");
|
||||
let message = dialog.shadowRoot.querySelector(".message");
|
||||
let label = dialog.shadowRoot.querySelector(
|
||||
"label[for='confirmation-checkbox']"
|
||||
);
|
||||
let cancelButton = dialog.shadowRoot.querySelector(".cancel-button");
|
||||
let removeAllButton = dialog.shadowRoot.querySelector(".confirm-button");
|
||||
await content.document.l10n.translateElements([
|
||||
title,
|
||||
message,
|
||||
label,
|
||||
cancelButton,
|
||||
removeAllButton,
|
||||
]);
|
||||
is(
|
||||
title.dataset.l10nId,
|
||||
"about-logins-confirm-remove-all-dialog-title",
|
||||
"Title contents should match l10n-id attribute set on element"
|
||||
);
|
||||
is(
|
||||
message.dataset.l10nId,
|
||||
"about-logins-confirm-remove-all-dialog-message",
|
||||
"Message contents should match l10n-id attribute set on element"
|
||||
);
|
||||
is(
|
||||
label.dataset.l10nId,
|
||||
"about-logins-confirm-remove-all-dialog-checkbox-label",
|
||||
"Label contents should match l10n-id attribute set on outer element"
|
||||
);
|
||||
is(
|
||||
cancelButton.dataset.l10nId,
|
||||
"confirmation-dialog-cancel-button",
|
||||
"Cancel button contents should match l10n-id attribute set on outer element"
|
||||
);
|
||||
is(
|
||||
removeAllButton.dataset.l10nId,
|
||||
"about-logins-confirm-remove-all-dialog-confirm-button",
|
||||
"Remove all button contents should match l10n-id attribute set on outer element"
|
||||
);
|
||||
is(
|
||||
JSON.parse(title.dataset.l10nArgs).count,
|
||||
1,
|
||||
"Title contents should match l10n-args attribute set on element"
|
||||
);
|
||||
is(
|
||||
JSON.parse(message.dataset.l10nArgs).count,
|
||||
1,
|
||||
"Message contents should match l10n-args attribute set on element"
|
||||
);
|
||||
is(
|
||||
JSON.parse(label.dataset.l10nArgs).count,
|
||||
1,
|
||||
"Label contents should match l10n-id attribute set on outer element"
|
||||
);
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
dialog.shadowRoot.querySelector(".cancel-button"),
|
||||
{},
|
||||
content
|
||||
);
|
||||
await ContentTaskUtils.waitForCondition(
|
||||
() => dialog.hidden,
|
||||
"Waiting for the dialog to be hidden after clicking cancel button"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_remove_all_dialog_keyboard_navigation() {
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
await openRemoveAllDialog(browser);
|
||||
await SpecialPowers.spawn(browser, [], async () => {
|
||||
const EventUtils = ContentTaskUtils.getEventUtils(content);
|
||||
let dialog = Cu.waiveXrays(
|
||||
content.document.querySelector("remove-logins-dialog")
|
||||
);
|
||||
let cancelButton = dialog.shadowRoot.querySelector(".cancel-button");
|
||||
let removeAllButton = dialog.shadowRoot.querySelector(".confirm-button");
|
||||
is(
|
||||
removeAllButton.disabled,
|
||||
true,
|
||||
"Remove all should be disabled on dialog open"
|
||||
);
|
||||
await EventUtils.synthesizeKey(" ", {}, content);
|
||||
is(
|
||||
removeAllButton.disabled,
|
||||
false,
|
||||
"Remove all should be enabled when activating the checkbox"
|
||||
);
|
||||
await EventUtils.synthesizeKey(" ", {}, content);
|
||||
is(
|
||||
removeAllButton.disabled,
|
||||
true,
|
||||
"Remove all should be disabled after deactivating the checkbox"
|
||||
);
|
||||
await EventUtils.synthesizeKey("KEY_Tab", {}, content);
|
||||
is(
|
||||
dialog.shadowRoot.activeElement,
|
||||
cancelButton,
|
||||
"Cancel button should be the next element in tab order"
|
||||
);
|
||||
await EventUtils.synthesizeKey(" ", {}, content);
|
||||
await ContentTaskUtils.waitForCondition(
|
||||
() => dialog.hidden,
|
||||
"Waiting for the dialog to be hidden after activating cancel button via Space key"
|
||||
);
|
||||
});
|
||||
await openRemoveAllDialog(browser);
|
||||
await SpecialPowers.spawn(browser, [], async () => {
|
||||
let dialog = Cu.waiveXrays(
|
||||
content.document.querySelector("remove-logins-dialog")
|
||||
);
|
||||
await EventUtils.synthesizeKey("KEY_Escape", {}, content);
|
||||
await ContentTaskUtils.waitForCondition(
|
||||
() => dialog.hidden,
|
||||
"Waiting for the dialog to be hidden after activating Escape key"
|
||||
);
|
||||
});
|
||||
await openRemoveAllDialog(browser);
|
||||
await SpecialPowers.spawn(browser, [], async () => {
|
||||
let dialog = Cu.waiveXrays(
|
||||
content.document.querySelector("remove-logins-dialog")
|
||||
);
|
||||
let dismissButton = dialog.shadowRoot.querySelector(".dismiss-button");
|
||||
await EventUtils.synthesizeKey("KEY_Tab", { shiftKey: true }, content);
|
||||
is(
|
||||
dialog.shadowRoot.activeElement,
|
||||
dismissButton,
|
||||
"dismiss button should be focused"
|
||||
);
|
||||
await EventUtils.synthesizeKey(" ", {}, content);
|
||||
await ContentTaskUtils.waitForCondition(
|
||||
() => dialog.hidden,
|
||||
"Waiting for the dialog to be hidden after activating X button"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
add_task(async function test_remove_all_dialog_remove_logins() {
|
||||
TEST_LOGIN2 = await addLogin(TEST_LOGIN2);
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
let removeAllPromise = waitForRemoveAllLogins();
|
||||
|
||||
await openRemoveAllDialog(browser);
|
||||
await SpecialPowers.spawn(browser, [], async () => {
|
||||
let dialog = Cu.waiveXrays(
|
||||
content.document.querySelector("remove-logins-dialog")
|
||||
);
|
||||
let title = dialog.shadowRoot.querySelector(".title");
|
||||
let message = dialog.shadowRoot.querySelector(".message");
|
||||
let label = dialog.shadowRoot.querySelector(
|
||||
"label[for='confirmation-checkbox']"
|
||||
);
|
||||
let cancelButton = dialog.shadowRoot.querySelector(".cancel-button");
|
||||
let removeAllButton = dialog.shadowRoot.querySelector(".confirm-button");
|
||||
|
||||
let checkbox = dialog.shadowRoot.querySelector(".checkbox");
|
||||
|
||||
await content.document.l10n.translateElements([
|
||||
title,
|
||||
message,
|
||||
cancelButton,
|
||||
removeAllButton,
|
||||
label,
|
||||
checkbox,
|
||||
]);
|
||||
is(
|
||||
dialog.shadowRoot.activeElement,
|
||||
checkbox,
|
||||
"Checkbox should be the focused element on dialog open"
|
||||
);
|
||||
is(
|
||||
title.dataset.l10nId,
|
||||
"about-logins-confirm-remove-all-dialog-title",
|
||||
"Title contents should match l10n-id attribute set on element"
|
||||
);
|
||||
is(
|
||||
JSON.parse(title.dataset.l10nArgs).count,
|
||||
2,
|
||||
"Title contents should match l10n-args attribute set on element"
|
||||
);
|
||||
is(
|
||||
message.dataset.l10nId,
|
||||
"about-logins-confirm-remove-all-dialog-message",
|
||||
"Message contents should match l10n-id attribute set on element"
|
||||
);
|
||||
is(
|
||||
JSON.parse(message.dataset.l10nArgs).count,
|
||||
2,
|
||||
"Message contents should match l10n-args attribute set on element"
|
||||
);
|
||||
is(
|
||||
label.dataset.l10nId,
|
||||
"about-logins-confirm-remove-all-dialog-checkbox-label",
|
||||
"Label contents should match l10n-id attribute set on outer element"
|
||||
);
|
||||
is(
|
||||
JSON.parse(label.dataset.l10nArgs).count,
|
||||
2,
|
||||
"Label contents should match l10n-id attribute set on outer element"
|
||||
);
|
||||
is(
|
||||
cancelButton.dataset.l10nId,
|
||||
"confirmation-dialog-cancel-button",
|
||||
"Cancel button contents should match l10n-id attribute set on outer element"
|
||||
);
|
||||
is(
|
||||
removeAllButton.dataset.l10nId,
|
||||
"about-logins-confirm-remove-all-dialog-confirm-button",
|
||||
"Remove all button contents should match l10n-id attribute set on outer element"
|
||||
);
|
||||
is(
|
||||
removeAllButton.disabled,
|
||||
true,
|
||||
"Remove all button should be disabled on dialog open"
|
||||
);
|
||||
});
|
||||
function activateConfirmCheckbox() {
|
||||
let dialog = window.document.querySelector("remove-logins-dialog");
|
||||
return dialog.shadowRoot.querySelector(".checkbox");
|
||||
}
|
||||
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter(
|
||||
activateConfirmCheckbox,
|
||||
{},
|
||||
browser
|
||||
);
|
||||
|
||||
await SpecialPowers.spawn(browser, [], async () => {
|
||||
let dialog = Cu.waiveXrays(
|
||||
content.document.querySelector("remove-logins-dialog")
|
||||
);
|
||||
let removeAllButton = dialog.shadowRoot.querySelector(".confirm-button");
|
||||
is(
|
||||
removeAllButton.disabled,
|
||||
false,
|
||||
"Remove all should be enabled after clicking the checkbox"
|
||||
);
|
||||
});
|
||||
function getDialogRemoveAllButton() {
|
||||
let dialog = window.document.querySelector("remove-logins-dialog");
|
||||
return dialog.shadowRoot.querySelector(".confirm-button");
|
||||
}
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter(
|
||||
getDialogRemoveAllButton,
|
||||
{},
|
||||
browser
|
||||
);
|
||||
await removeAllPromise;
|
||||
await SpecialPowers.spawn(browser, [], async () => {
|
||||
let loginList = Cu.waiveXrays(content.document.querySelector("login-list"));
|
||||
await ContentTaskUtils.waitForCondition(
|
||||
() => content.document.documentElement.classList.contains("no-logins"),
|
||||
"Waiting for no logins view since all logins should be deleted"
|
||||
);
|
||||
await ContentTaskUtils.waitForCondition(
|
||||
() => loginList.classList.contains("no-logins"),
|
||||
"Waiting for login-list to be in no logins view as all logins should be deleted"
|
||||
);
|
||||
});
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter("menu-button", {}, browser);
|
||||
await SpecialPowers.spawn(browser, [], async () => {
|
||||
let menuButton = content.document.querySelector("menu-button");
|
||||
let removeAllMenuButton = menuButton.shadowRoot.querySelector(
|
||||
".menuitem-remove-all-logins"
|
||||
);
|
||||
ok(
|
||||
removeAllMenuButton.disabled,
|
||||
"Remove all logins menu button is disabled if there are no logins"
|
||||
);
|
||||
});
|
||||
});
|
|
@ -23,7 +23,7 @@ async function checkLoginDisplayed(browser, testGuid) {
|
|||
add_task(async function() {
|
||||
TEST_LOGIN1 = await addLogin(TEST_LOGIN1);
|
||||
registerCleanupFunction(() => {
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
|
||||
const testGuid = TEST_LOGIN1.guid;
|
||||
|
|
|
@ -22,7 +22,7 @@ add_task(async function setup() {
|
|||
});
|
||||
registerCleanupFunction(() => {
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ add_task(async function setup() {
|
|||
});
|
||||
registerCleanupFunction(() => {
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ add_task(async function setup() {
|
|||
|
||||
registerCleanupFunction(async () => {
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
await BrowserTestUtils.closeWindow(newWin);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -95,6 +95,7 @@ add_task(async function test_menu_open_close() {
|
|||
sendKey("TAB"); // Import from file
|
||||
}
|
||||
sendKey("TAB"); // Export
|
||||
sendKey("TAB"); // Remove All Logins
|
||||
|
||||
if (navigator.platform == "Win32" || navigator.platform == "MacIntel") {
|
||||
// The Import menuitem is only visible on Windows/macOS, where we will need another Tab
|
||||
|
@ -145,6 +146,7 @@ add_task(async function test_menu_keyboard_cycling() {
|
|||
|
||||
let allItems = [
|
||||
"menuitem-export",
|
||||
"menuitem-remove-all-logins",
|
||||
"menuitem-preferences",
|
||||
"menuitem-help",
|
||||
];
|
||||
|
|
|
@ -199,7 +199,7 @@ add_task(async function test_breachAlertHiddenAfterDismissal() {
|
|||
);
|
||||
|
||||
info("Clear login storage");
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
|
||||
const breachesByLoginGUID2 = await LoginBreaches.getPotentialBreachesByLoginGUID(
|
||||
[BREACHED_LOGIN, NOT_BREACHED_LOGIN],
|
||||
|
|
|
@ -38,7 +38,7 @@ function addLogin(host, timestamp) {
|
|||
}
|
||||
|
||||
async function setupPasswords() {
|
||||
loginManager.removeAllLogins();
|
||||
loginManager.removeAllUserFacingLogins();
|
||||
addLogin(FXA_HOST, REFERENCE_DATE);
|
||||
addLogin(NEW_HOST, REFERENCE_DATE);
|
||||
addLogin(OLD_HOST, REFERENCE_DATE - 10000);
|
||||
|
|
|
@ -272,7 +272,7 @@ add_task(async function setup() {
|
|||
}
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
if (loginCrypto.finalize) {
|
||||
loginCrypto.finalize();
|
||||
}
|
||||
|
@ -327,7 +327,7 @@ add_task(async function test_importExistingLogins() {
|
|||
"Sanity check the source exists"
|
||||
);
|
||||
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
let logins = Services.logins.getAllLogins();
|
||||
Assert.equal(
|
||||
logins.length,
|
||||
|
|
|
@ -50,7 +50,7 @@ add_task(async function setup() {
|
|||
}
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1293,7 +1293,7 @@ add_task(async function test_passwordsAvailable() {
|
|||
let hashes = []; // the hashes of all migrator websites, this is going to be used for the clean up
|
||||
|
||||
registerCleanupFunction(() => {
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
logins = Services.logins.getAllLogins();
|
||||
Assert.equal(logins.length, 0, "There are no logins after the cleanup");
|
||||
// remove all the values created in this test from the registry
|
||||
|
|
|
@ -83,7 +83,7 @@ const mockGetMonitorData = data => {
|
|||
};
|
||||
|
||||
registerCleanupFunction(function head_cleanup() {
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
|
||||
// Used to replace AboutProtectionsParent.VPNSubStatus and Region.current
|
||||
|
|
|
@ -23,6 +23,7 @@ menu =
|
|||
about-logins-menu-menuitem-import-from-another-browser = Import from Another Browser…
|
||||
about-logins-menu-menuitem-import-from-a-file = Import from a File…
|
||||
about-logins-menu-menuitem-export-logins = Export Logins…
|
||||
about-logins-menu-menuitem-remove-all-logins = Remove All Logins…
|
||||
menu-menuitem-preferences =
|
||||
{ PLATFORM() ->
|
||||
[windows] Options
|
||||
|
@ -160,6 +161,35 @@ about-logins-confirm-remove-dialog-title = Remove this login?
|
|||
confirm-delete-dialog-message = This action cannot be undone.
|
||||
about-logins-confirm-remove-dialog-confirm-button = Remove
|
||||
|
||||
about-logins-confirm-remove-all-dialog-confirm-button = Remove All
|
||||
about-logins-confirm-remove-all-dialog-checkbox-label =
|
||||
{ $count ->
|
||||
[1] Yes, remove this login
|
||||
*[other] Yes, remove these logins
|
||||
}
|
||||
|
||||
about-logins-confirm-remove-all-dialog-title =
|
||||
{ $count ->
|
||||
[one] Remove { $count } login?
|
||||
*[other] Remove all { $count } logins?
|
||||
}
|
||||
about-logins-confirm-remove-all-dialog-message =
|
||||
{ $count ->
|
||||
[1] This will remove the login you’ve saved to { -brand-short-name } and any breach alerts that appear here. You won’t be able to undo this action.
|
||||
*[other] This will remove the logins you’ve saved to { -brand-short-name } and any breach alerts that appear here. You won’t be able to undo this action.
|
||||
}
|
||||
|
||||
about-logins-confirm-remove-all-sync-dialog-title =
|
||||
{ $count ->
|
||||
[one] Remove { $count } login from all devices?
|
||||
*[other] Remove all { $count } logins from all devices?
|
||||
}
|
||||
about-logins-confirm-remove-all-sync-dialog-message=
|
||||
{ $count ->
|
||||
[1] This will remove the login you’ve saved to { -brand-short-name } on all devices synced to your { -fxaccount-brand-name }. This will also remove breach alerts that appear here. You won’t be able to undo this action.
|
||||
*[other] This will remove all logins you’ve saved to { -brand-short-name } on all devices synced to your { -fxaccount-brand-name }. This will also remove breach alerts that appear here. You won’t be able to undo this action.
|
||||
}
|
||||
|
||||
about-logins-confirm-export-dialog-title = Export logins and passwords
|
||||
about-logins-confirm-export-dialog-message = Your passwords will be saved as readable text (e.g., BadP@ssw0rd) so anyone who can open the exported file can view them.
|
||||
about-logins-confirm-export-dialog-confirm-button = Export…
|
||||
|
|
|
@ -14,7 +14,7 @@ function resetPassword() {
|
|||
token.reset();
|
||||
|
||||
try {
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
} catch (e) {}
|
||||
|
||||
let l10n = new Localization(["security/pippki/pippki.ftl"], true);
|
||||
|
|
|
@ -411,7 +411,7 @@ PasswordStore.prototype = {
|
|||
},
|
||||
|
||||
async wipe() {
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -463,8 +463,18 @@ PasswordTracker.prototype = {
|
|||
}
|
||||
break;
|
||||
|
||||
// Bug 1613620: We iterate through the removed logins and track them to ensure
|
||||
// the logins are deleted across synced devices/accounts
|
||||
case "removeAllLogins":
|
||||
this._log.trace(data);
|
||||
subject.QueryInterface(Ci.nsIArrayExtensions);
|
||||
let count = subject.Count();
|
||||
for (let i = 0; i < count; i++) {
|
||||
let currentSubject = subject.GetElementAt(i);
|
||||
let tracked = await this._trackLogin(currentSubject);
|
||||
if (tracked) {
|
||||
this._log.trace(data + ": " + currentSubject.guid);
|
||||
}
|
||||
}
|
||||
this.score += SCORE_INCREMENT_XLARGE;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -106,3 +106,51 @@ add_task(async function test_onWipe() {
|
|||
await tracker.stop();
|
||||
}
|
||||
});
|
||||
|
||||
add_task(async function test_removeAllLogins() {
|
||||
let recordNum = 0;
|
||||
_("Verify that all tracked logins are removed.");
|
||||
|
||||
async function createPassword() {
|
||||
_("RECORD NUM: " + recordNum);
|
||||
let record = {
|
||||
id: "GUID" + recordNum,
|
||||
hostname: "http://foo.bar.com",
|
||||
formSubmitURL: "http://foo.bar.com",
|
||||
username: "john" + recordNum,
|
||||
password: "smith",
|
||||
usernameField: "username",
|
||||
passwordField: "password",
|
||||
};
|
||||
recordNum++;
|
||||
let login = store._nsLoginInfoFromRecord(record);
|
||||
Services.logins.addLogin(login);
|
||||
await tracker.asyncObserver.promiseObserversComplete();
|
||||
}
|
||||
try {
|
||||
_("Tell tracker to start tracking changes");
|
||||
tracker.start();
|
||||
await createPassword();
|
||||
await createPassword();
|
||||
let changes = await tracker.getChangedIDs();
|
||||
do_check_attribute_count(changes, 2);
|
||||
Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE * 2);
|
||||
|
||||
await tracker.clearChangedIDs();
|
||||
changes = await tracker.getChangedIDs();
|
||||
do_check_attribute_count(changes, 0);
|
||||
|
||||
_("Tell sync to remove all logins");
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
await tracker.asyncObserver.promiseObserversComplete();
|
||||
changes = await tracker.getChangedIDs();
|
||||
do_check_attribute_count(changes, 2);
|
||||
Assert.equal(tracker.score, SCORE_INCREMENT_XLARGE * 5);
|
||||
} finally {
|
||||
_("Clean up.");
|
||||
await store.wipe();
|
||||
await tracker.clearChangedIDs();
|
||||
tracker.resetScore();
|
||||
await tracker.stop();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -30,7 +30,7 @@ function run_test() {
|
|||
|
||||
add_task(async function test_verifyLogin() {
|
||||
// This test expects a clean slate -- no saved passphrase.
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
let johnHelper = track_collections_helper();
|
||||
let johnU = johnHelper.with_updated_collection;
|
||||
|
||||
|
|
|
@ -318,7 +318,7 @@ async function test_login_manager_logins_not_cleared_with_uri_contains_domain()
|
|||
await ForgetAboutSite.removeDataFromDomain("mozilla.org");
|
||||
check_login_exists(TEST_HOST, true);
|
||||
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
check_login_exists(TEST_HOST, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -436,10 +436,24 @@ LoginManager.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Remove all stored logins.
|
||||
* Remove all user facing stored logins.
|
||||
*
|
||||
* This will not remove the FxA Sync key, which is stored with the rest of a user's logins.
|
||||
*/
|
||||
removeAllUserFacingLogins() {
|
||||
log.debug("Removing all user facing logins");
|
||||
this._storage.removeAllUserFacingLogins();
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove all logins from data store, including the FxA Sync key.
|
||||
*
|
||||
* NOTE: You probably want `removeAllUserFacingLogins()` instead of this function.
|
||||
* This function will remove the FxA Sync key, which will break syncing of saved user data
|
||||
* e.g. bookmarks, history, open tabs, logins and passwords, add-ons, and options
|
||||
*/
|
||||
removeAllLogins() {
|
||||
log.debug("Removing all logins");
|
||||
log.debug("Removing all logins from local store, including FxA key");
|
||||
this._storage.removeAllLogins();
|
||||
},
|
||||
|
||||
|
|
|
@ -108,7 +108,7 @@ LoginStore.prototype._save = async function() {
|
|||
|
||||
/**
|
||||
* Delete logins backup file if the last saved login was removed using
|
||||
* removeLogin() or if all logins were removed at once using removeAllLogins().
|
||||
* removeLogin() or if all logins were removed at once using removeAllUserFacingLogins().
|
||||
* Note that if the user has a fxa key stored as a login, we just update the
|
||||
* backup to only store the key when the last saved user facing login is removed.
|
||||
*/
|
||||
|
|
|
@ -101,11 +101,22 @@ interface nsILoginManager : nsISupports {
|
|||
void recordPasswordUse(in nsILoginInfo aLogin, in boolean aPrivateContextWithoutExplicitConsent, in AString aLoginType, in boolean aFilled);
|
||||
|
||||
/**
|
||||
* Remove all logins known to login manager.
|
||||
* Remove all stored user facing logins.
|
||||
*
|
||||
* This will remove all the logins that a user can access through about:logins.
|
||||
* This will not remove the FxA Sync key which is stored with the rest of a user's logins
|
||||
* but is not accessible through about:logins
|
||||
*
|
||||
* The browser sanitization feature allows the user to clear any stored
|
||||
* passwords. This interface allows that to be done without getting each
|
||||
* login first (which might require knowing the master password).
|
||||
* login first.
|
||||
*
|
||||
*/
|
||||
void removeAllUserFacingLogins();
|
||||
|
||||
/**
|
||||
* Completely remove all logins, including the user's FxA Sync key.
|
||||
*
|
||||
*/
|
||||
void removeAllLogins();
|
||||
|
||||
|
|
|
@ -106,11 +106,22 @@ interface nsILoginManagerStorage : nsISupports {
|
|||
void recordPasswordUse(in nsILoginInfo aLogin);
|
||||
|
||||
/**
|
||||
* Remove all stored logins.
|
||||
* Remove all stored user facing logins.
|
||||
*
|
||||
* This will remove all the logins that a user can access through about:logins.
|
||||
* This will not remove the FxA Sync key which is stored with the rest of a user's logins
|
||||
* but is not accessible through about:logins
|
||||
*
|
||||
* The browser sanitization feature allows the user to clear any stored
|
||||
* passwords. This interface allows that to be done without getting each
|
||||
* login first (which might require knowing the master password).
|
||||
* login first.
|
||||
*
|
||||
*/
|
||||
void removeAllUserFacingLogins();
|
||||
|
||||
/**
|
||||
* Completely remove all logins, including the user's FxA key.
|
||||
*
|
||||
*/
|
||||
void removeAllLogins();
|
||||
|
||||
|
|
|
@ -35,6 +35,11 @@ XPCOMUtils.defineLazyServiceGetter(
|
|||
"nsIUUIDGenerator"
|
||||
);
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
FXA_PWDMGR_HOST: "resource://gre/modules/FxAccountsCommon.js",
|
||||
FXA_PWDMGR_REALM: "resource://gre/modules/FxAccountsCommon.js",
|
||||
});
|
||||
|
||||
class LoginManagerStorage_json {
|
||||
constructor() {
|
||||
this.__crypto = null; // nsILoginManagerCrypto service
|
||||
|
@ -639,19 +644,50 @@ class LoginManagerStorage_json {
|
|||
}
|
||||
|
||||
/**
|
||||
* Removes all logins from storage.
|
||||
* Removes all logins from local storage, including FxA Sync key.
|
||||
*
|
||||
* NOTE: You probably want removeAllUserFacingLogins instead of this function.
|
||||
*
|
||||
*/
|
||||
removeAllLogins() {
|
||||
this._store.ensureDataReady();
|
||||
|
||||
this.log("Removing all logins");
|
||||
this._store.data.logins = [];
|
||||
this._store.data.potentiallyVulnerablePasswords = [];
|
||||
this.__decryptedPotentiallyVulnerablePasswords = null;
|
||||
this._store.data.dismissedBreachAlertsByLoginGUID = {};
|
||||
this._store.saveSoon();
|
||||
|
||||
LoginHelper.notifyStorageChanged("removeAllLogins", null);
|
||||
LoginHelper.notifyStorageChanged("removeAllLogins", []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all user facing logins from storage. e.g. all logins except the FxA Sync key
|
||||
*
|
||||
* If you need to remove the FxA key, use `removeAllLogins` instead
|
||||
*/
|
||||
removeAllUserFacingLogins() {
|
||||
this._store.ensureDataReady();
|
||||
this.log("Removing all logins");
|
||||
|
||||
let [allLogins, ids] = this._searchLogins({});
|
||||
|
||||
let fxaKey = this._store.data.logins.find(
|
||||
login =>
|
||||
login.hostname == FXA_PWDMGR_HOST && login.httpRealm == FXA_PWDMGR_REALM
|
||||
);
|
||||
if (fxaKey) {
|
||||
this._store.data.logins = [fxaKey];
|
||||
allLogins = allLogins.filter(item => item != fxaKey);
|
||||
} else {
|
||||
this._store.data.logins = [];
|
||||
}
|
||||
|
||||
this._store.data.potentiallyVulnerablePasswords = [];
|
||||
this.__decryptedPotentiallyVulnerablePasswords = null;
|
||||
this._store.data.dismissedBreachAlertsByLoginGUID = {};
|
||||
this._store.saveSoon();
|
||||
|
||||
LoginHelper.notifyStorageChanged("removeAllLogins", allLogins);
|
||||
}
|
||||
|
||||
findLogins(origin, formActionOrigin, httpRealm) {
|
||||
|
|
|
@ -50,7 +50,7 @@ this.LoginTestUtils = {
|
|||
* Erases all the data stored by the Login Manager service.
|
||||
*/
|
||||
clearData() {
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
for (let origin of Services.logins.getAllDisabledHosts()) {
|
||||
Services.logins.setLoginSavingEnabled(origin, true);
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ function observeMasterPasswordDialog(window, result) {
|
|||
}
|
||||
|
||||
add_task(async function setup() {
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
let login = LoginTestUtils.testData.formLogin({
|
||||
origin: "http://example.org",
|
||||
formActionOrigin: "http://example.org",
|
||||
|
|
|
@ -98,6 +98,6 @@ add_task(async function test() {
|
|||
BrowserTestUtils.removeTab(tab);
|
||||
|
||||
// Reset all passwords before next iteration.
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -412,7 +412,7 @@ add_task(async function fill_generated_password_with_matching_logins() {
|
|||
"Generated password shouldn't have changed to match the filled password"
|
||||
);
|
||||
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
LoginTestUtils.resetGeneratedPasswordsCache();
|
||||
});
|
||||
|
||||
|
|
|
@ -83,14 +83,14 @@ async function loginBackupDeleted() {
|
|||
});
|
||||
}
|
||||
|
||||
// 1. Test that logins backup is deleted when Services.logins.removeAllLogins() is called.
|
||||
// 1. Test that logins backup is deleted when Services.logins.removeAllUserFacingLogins() is called.
|
||||
// 2. Test that logins backup is deleted when the last saved login is removed using
|
||||
// Services.logins.removeLogin() when no fxa key is saved.
|
||||
// 3. If a fxa key is stored as a login, test that logins backup is updated to only store
|
||||
// the fxa key when the last user facing login is deleted.
|
||||
add_task(async function test_deleteLoginsBackup_removeAll() {
|
||||
// Remove logins.json and logins-backup.json before starting.
|
||||
info("Testing the removeAllLogins() case");
|
||||
info("Testing the removeAllUserFacingLogins() case");
|
||||
|
||||
await OS.File.remove(loginStorePath, { ignoreAbsent: true });
|
||||
await OS.File.remove(loginBackupPath, { ignoreAbsent: true });
|
||||
|
@ -113,7 +113,7 @@ add_task(async function test_deleteLoginsBackup_removeAll() {
|
|||
|
||||
storageUpdatePromise = TestUtils.topicObserved("password-storage-updated");
|
||||
info("Removing all logins");
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
|
||||
await storageUpdatePromise;
|
||||
info("Writes to storage are complete when removeAllLogins() is called");
|
||||
|
|
|
@ -177,7 +177,7 @@ add_task(async function test_edit_password() {
|
|||
await LoginTestUtils.clearData();
|
||||
await cleanupDoorhanger();
|
||||
await cleanupPasswordNotifications();
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
|
||||
// Create the pre-existing logins when needed.
|
||||
info("Adding any saved logins");
|
||||
|
@ -269,7 +269,7 @@ add_task(async function test_edit_password() {
|
|||
await cleanupDoorhanger();
|
||||
await cleanupPasswordNotifications();
|
||||
await clearMessageCache(browser);
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -178,5 +178,5 @@ async function test_save_change({
|
|||
);
|
||||
|
||||
// Clean up the database before the next test case is executed.
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ const usernameInputSelector = "#form-basic-username";
|
|||
requestLongerTimeout(2);
|
||||
|
||||
async function task_setup() {
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
LoginTestUtils.resetGeneratedPasswordsCache();
|
||||
await cleanupPasswordNotifications();
|
||||
}
|
||||
|
|
|
@ -96,7 +96,7 @@ add_task(async function test_httpsUpgradeCaptureFields_changePW() {
|
|||
is(login.password, "pass2", "Check the password changed");
|
||||
is(login.timesUsed, 2, "Check times used increased");
|
||||
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
|
||||
add_task(
|
||||
|
@ -165,7 +165,7 @@ add_task(
|
|||
"timeLastUsed == timePasswordChanged"
|
||||
);
|
||||
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ async function showChangePasswordDoorhanger(
|
|||
}
|
||||
|
||||
async function setupLogins(...logins) {
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
let savedLogins = {};
|
||||
let timesCreated = new Set();
|
||||
for (let login of logins) {
|
||||
|
|
|
@ -886,7 +886,7 @@ add_task(async function test_recipeCaptureFields_ExistingLogin() {
|
|||
is(login.password, "notifyp1", "Check the password unchanged");
|
||||
is(login.timesUsed, 2, "Check times used incremented");
|
||||
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
|
||||
add_task(async function test_saveUsingEnter() {
|
||||
|
@ -925,7 +925,7 @@ add_task(async function test_saveUsingEnter() {
|
|||
is(login.password, "notifyp1", "Check the password used on the new entry");
|
||||
is(login.timesUsed, 1, "Check times used on new entry");
|
||||
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
}
|
||||
|
||||
await testWithTextboxSelector("#password-notification-password");
|
||||
|
|
|
@ -160,5 +160,5 @@ async function test_save_change(testData) {
|
|||
);
|
||||
|
||||
// Clean up the database before the next test case is executed.
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
}
|
||||
|
|
|
@ -362,5 +362,5 @@ async function test_submit_telemetry(tc) {
|
|||
|
||||
// Clean up the database before the next test case is executed.
|
||||
await cleanupDoorhanger(notif);
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ add_task(async function test_setup() {
|
|||
authPromptModalType = Services.prefs.getIntPref("prompts.modalType.httpAuth");
|
||||
normalWin = await BrowserTestUtils.openNewBrowserWindow({ private: false });
|
||||
privateWin = await BrowserTestUtils.openNewBrowserWindow({ private: true });
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
|
||||
add_task(async function test_normal_popup_notification_1() {
|
||||
|
@ -169,7 +169,7 @@ add_task(async function test_private_popup_notification_2() {
|
|||
);
|
||||
|
||||
// clear existing logins for parity with the previous test
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
await focusWindow(privateWin);
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
|
@ -243,7 +243,7 @@ add_task(async function test_private_popup_notification_no_capture_pref_2b() {
|
|||
Services.prefs.setBoolPref(PRIVATE_BROWSING_CAPTURE_PREF, false);
|
||||
|
||||
// clear existing logins for parity with the previous test
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
|
||||
await focusWindow(privateWin);
|
||||
await BrowserTestUtils.withNewTab(
|
||||
|
@ -289,7 +289,7 @@ add_task(async function test_normal_popup_notification_3() {
|
|||
"match existing username/password: no popup notification should appear"
|
||||
);
|
||||
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
Services.logins.addLogin(login);
|
||||
let allLogins = Services.logins.getAllLogins();
|
||||
// Sanity check the HTTP login exists.
|
||||
|
@ -340,7 +340,7 @@ add_task(async function test_private_popup_notification_3b() {
|
|||
" match existing username/password: no popup notification should appear"
|
||||
);
|
||||
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
Services.logins.addLogin(login);
|
||||
let allLogins = Services.logins.getAllLogins();
|
||||
// Sanity check the HTTP login exists.
|
||||
|
@ -392,7 +392,7 @@ add_task(async function test_normal_new_password_4() {
|
|||
"test 4: run with a login, outside of private mode," +
|
||||
" add a new password: popup notification should appear"
|
||||
);
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
Services.logins.addLogin(login);
|
||||
let allLogins = Services.logins.getAllLogins();
|
||||
// Sanity check the HTTP login exists.
|
||||
|
@ -684,7 +684,7 @@ add_task(async function test_normal_http_basic_auth() {
|
|||
info(
|
||||
"test normal/basic-auth: verify that we get a doorhanger after basic-auth login"
|
||||
);
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
clearHttpAuths();
|
||||
|
||||
await focusWindow(normalWin);
|
||||
|
@ -737,7 +737,7 @@ add_task(async function test_private_http_basic_auth() {
|
|||
info(
|
||||
"test private/basic-auth: verify that we don't get a doorhanger after basic-auth login"
|
||||
);
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
clearHttpAuths();
|
||||
|
||||
const capturePrefValue = Services.prefs.getBoolPref(
|
||||
|
@ -792,7 +792,7 @@ add_task(async function test_private_http_basic_auth_no_capture_pref() {
|
|||
);
|
||||
Services.prefs.setBoolPref(PRIVATE_BROWSING_CAPTURE_PREF, false);
|
||||
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
clearHttpAuths();
|
||||
|
||||
await focusWindow(privateWin);
|
||||
|
|
|
@ -811,7 +811,7 @@ SimpleTest.registerCleanupFunction(() => {
|
|||
);
|
||||
|
||||
// Remove all logins and disabled hosts
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
|
||||
let disabledHosts = Services.logins.getAllDisabledHosts();
|
||||
disabledHosts.forEach(host =>
|
||||
|
|
|
@ -24,7 +24,7 @@ let FILE_PATH = "/tests/toolkit/components/passwordmgr/test/mochitest/slow_image
|
|||
// part of a suite
|
||||
runInParent(function removeAll() {
|
||||
let {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
})
|
||||
|
||||
let readyPromise = registerRunTests();
|
||||
|
|
|
@ -16,7 +16,7 @@ Login Manager test: autofill with autocomplete=new-password fields
|
|||
<script>
|
||||
function initLogins() {
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
|
||||
const {LoginManagerParent} = ChromeUtils.import("resource://gre/modules/LoginManagerParent.jsm");
|
||||
if (LoginManagerParent.getGeneratedPasswordsByPrincipalOrigin()) {
|
||||
|
@ -282,7 +282,7 @@ add_task(async function test_autofillAutocompletePassword_withGeneration() {
|
|||
await promiseNoUnexpectedPopupShown();
|
||||
|
||||
info("Removing all logins to test auto-saving of generated passwords");
|
||||
await LoginManager.removeAllLogins();
|
||||
await LoginManager.removeAllUserFacingLogins();
|
||||
|
||||
while (pword.value) {
|
||||
synthesizeKey("KEY_Backspace");
|
||||
|
@ -445,7 +445,7 @@ add_task(async function test_autofillAutocompletePassword_saveLoginDisabled() {
|
|||
|
||||
add_task(async function test_deleteAndReselectGeneratedPassword() {
|
||||
info("Removing all logins to test auto-saving of generated passwords");
|
||||
await LoginManager.removeAllLogins();
|
||||
await LoginManager.removeAllUserFacingLogins();
|
||||
|
||||
// form should not be filled
|
||||
checkForm(2, "", "");
|
||||
|
|
|
@ -62,7 +62,7 @@ add_task(async function test_two_logins() {
|
|||
|
||||
checkLoginForm(uname, "", pword, "");
|
||||
let removedPromise = promiseStorageChanged(["removeAllLogins"]);
|
||||
await LoginManager.removeAllLogins();
|
||||
await LoginManager.removeAllUserFacingLogins();
|
||||
await removedPromise;
|
||||
});
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ let readyPromise = registerRunTests(1);
|
|||
const { TestUtils } = SpecialPowers.Cu.import("resource://testing-common/TestUtils.jsm");
|
||||
|
||||
async function prepareLogins(logins = []) {
|
||||
await LoginManager.removeAllLogins();
|
||||
await LoginManager.removeAllUserFacingLogins();
|
||||
|
||||
for (let login of logins) {
|
||||
let storageAddPromise = promiseStorageChanged(["addLogin"]);
|
||||
|
|
|
@ -33,7 +33,7 @@ let win = window.open("about:blank");
|
|||
SimpleTest.registerCleanupFunction(() => win.close());
|
||||
|
||||
async function prepareLoginsAndProcessForm(url, logins = []) {
|
||||
await LoginManager.removeAllLogins();
|
||||
await LoginManager.removeAllUserFacingLogins();
|
||||
|
||||
let dates = Date.now();
|
||||
for (let login of logins) {
|
||||
|
|
|
@ -45,7 +45,7 @@ async function checkWindowLoginForm(expectedUsername, expectedPassword) {
|
|||
}
|
||||
|
||||
async function prepareLogins(logins = []) {
|
||||
await LoginManager.removeAllLogins();
|
||||
await LoginManager.removeAllUserFacingLogins();
|
||||
|
||||
let dates = Date.now();
|
||||
for (let login of logins) {
|
||||
|
|
|
@ -38,7 +38,7 @@ async function prepareAndProcessForm(url, login) {
|
|||
}
|
||||
|
||||
async function checkFormsWithLogin(formUrls, login, expectedUsername, expectedPassword) {
|
||||
await LoginManager.removeAllLogins();
|
||||
await LoginManager.removeAllUserFacingLogins();
|
||||
await LoginManager.addLogin(login);
|
||||
|
||||
for (let url of formUrls) {
|
||||
|
|
|
@ -31,7 +31,7 @@ let win = window.open("about:blank");
|
|||
SimpleTest.registerCleanupFunction(() => win.close());
|
||||
|
||||
async function prepareLoginsAndProcessForm(url, logins = []) {
|
||||
await LoginManager.removeAllLogins();
|
||||
await LoginManager.removeAllUserFacingLogins();
|
||||
|
||||
let dates = Date.now();
|
||||
for (let login of logins) {
|
||||
|
|
|
@ -34,7 +34,7 @@ let html = `
|
|||
</form>`;
|
||||
|
||||
async function prepareLogins(logins = []) {
|
||||
await LoginManager.removeAllLogins();
|
||||
await LoginManager.removeAllUserFacingLogins();
|
||||
|
||||
for (let login of logins) {
|
||||
let storageAddPromise = promiseStorageChanged(["addLogin"]);
|
||||
|
|
|
@ -14,20 +14,20 @@ let readyPromise = registerRunTests();
|
|||
|
||||
const DEFAULT_ORIGIN = window.location.origin;
|
||||
|
||||
function removeAllLoginsInParent() {
|
||||
runInParent(function removeAllLogins() {
|
||||
function removeAllUserFacingLoginsInParent() {
|
||||
runInParent(function removeAllUserFacingLogins() {
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
}
|
||||
|
||||
function add2logins() {
|
||||
removeAllLoginsInParent();
|
||||
removeAllUserFacingLoginsInParent();
|
||||
addLoginsInParent([DEFAULT_ORIGIN, DEFAULT_ORIGIN, null, "real••••user", "pass1", "", ""], [DEFAULT_ORIGIN, DEFAULT_ORIGIN, null, "user2", "pass2", "", ""]);
|
||||
}
|
||||
|
||||
function addSingleLogin() {
|
||||
removeAllLoginsInParent();
|
||||
removeAllUserFacingLoginsInParent();
|
||||
addLoginsInParent([DEFAULT_ORIGIN, DEFAULT_ORIGIN, null, "real••••user", "pass1", "", ""])
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ async function setupWithOneLogin(pageUrl) {
|
|||
function resetSavedLogins() {
|
||||
let chromeScript = runInParent(function testTeardown() {
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
chromeScript.destroy();
|
||||
}
|
||||
|
|
|
@ -332,7 +332,7 @@ add_task(async function test_onPasswordEditedOrGenerated_generatedPassword() {
|
|||
LoginManagerParent._browsingContextGlobal.get.restore();
|
||||
restorePrompter();
|
||||
LoginManagerParent.getGeneratedPasswordsByPrincipalOrigin().clear();
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
Services.telemetry.clearEvents();
|
||||
});
|
||||
|
||||
|
@ -418,7 +418,7 @@ add_task(
|
|||
LoginManagerParent._browsingContextGlobal.get.restore();
|
||||
restorePrompter();
|
||||
LoginManagerParent.getGeneratedPasswordsByPrincipalOrigin().clear();
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
Services.telemetry.clearEvents();
|
||||
}
|
||||
);
|
||||
|
@ -613,7 +613,7 @@ add_task(async function test_addUsernameBeforeAutoSaveEdit() {
|
|||
LoginHelper.getBrowserForPrompt.restore();
|
||||
restorePrompter();
|
||||
LoginManagerParent.getGeneratedPasswordsByPrincipalOrigin().clear();
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
Services.telemetry.clearEvents();
|
||||
});
|
||||
|
||||
|
@ -750,7 +750,7 @@ add_task(async function test_editUsernameOfFilledSavedLogin() {
|
|||
LoginHelper.getBrowserForPrompt.restore();
|
||||
restorePrompter();
|
||||
LoginManagerParent.getGeneratedPasswordsByPrincipalOrigin().clear();
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
Services.telemetry.clearEvents();
|
||||
});
|
||||
|
||||
|
@ -785,7 +785,7 @@ add_task(
|
|||
restorePrompter();
|
||||
LoginManagerParent.getGeneratedPasswordsByPrincipalOrigin().clear();
|
||||
Services.logins.setLoginSavingEnabled("https://www.example.com", true);
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -873,7 +873,7 @@ add_task(
|
|||
LoginManagerParent._browsingContextGlobal.get.restore();
|
||||
restorePrompter();
|
||||
LoginManagerParent.getGeneratedPasswordsByPrincipalOrigin().clear();
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
Services.telemetry.clearEvents();
|
||||
}
|
||||
);
|
||||
|
@ -992,7 +992,7 @@ add_task(
|
|||
LoginManagerParent._browsingContextGlobal.get.restore();
|
||||
restorePrompter();
|
||||
LoginManagerParent.getGeneratedPasswordsByPrincipalOrigin().clear();
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
Services.telemetry.clearEvents();
|
||||
}
|
||||
);
|
||||
|
@ -1057,7 +1057,7 @@ add_task(
|
|||
LoginManagerParent._browsingContextGlobal.get.restore();
|
||||
restorePrompter();
|
||||
LoginManagerParent.getGeneratedPasswordsByPrincipalOrigin().clear();
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -1119,6 +1119,6 @@ add_task(
|
|||
LoginManagerParent._browsingContextGlobal.get.restore();
|
||||
restorePrompter();
|
||||
LoginManagerParent.getGeneratedPasswordsByPrincipalOrigin().clear();
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
}
|
||||
);
|
||||
|
|
|
@ -190,6 +190,6 @@ add_task(async function test_searchAndDedupeLogins_acceptDifferentSubdomains() {
|
|||
Assert.ok(actual[i].equals(login), `Check index ${i}`);
|
||||
}
|
||||
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -281,7 +281,7 @@ async function runTestcase({ formOrigin, savedLogins, expectedItems }) {
|
|||
"All items correctly cleared."
|
||||
);
|
||||
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -211,15 +211,15 @@ add_task(function test_removeLogin_nonexisting() {
|
|||
/**
|
||||
* Tests removing all logins at once.
|
||||
*/
|
||||
add_task(function test_removeAllLogins() {
|
||||
add_task(function test_removeAllUserFacingLogins() {
|
||||
for (let loginInfo of TestData.loginList()) {
|
||||
Services.logins.addLogin(loginInfo);
|
||||
}
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
LoginTestUtils.checkLogins([]);
|
||||
|
||||
// The function should also work when there are no logins to delete.
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
|
||||
/**
|
||||
|
@ -460,7 +460,7 @@ add_task(function test_addLogin_badDates() {
|
|||
!!Services.logins.addLogin(defaultsLogin),
|
||||
"Sanity check adding defaults formLogin"
|
||||
);
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
|
||||
// 0 is a valid date in this context - new nsLoginInfo timestamps init to 0
|
||||
for (let pname of ["timeCreated", "timeLastUsed", "timePasswordChanged"]) {
|
||||
|
@ -473,7 +473,7 @@ add_task(function test_addLogin_badDates() {
|
|||
!!Services.logins.addLogin(loginInfo),
|
||||
"Check 0 value for " + pname
|
||||
);
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
}
|
||||
|
||||
// negative dates get clamped to 0 and are ok
|
||||
|
@ -487,7 +487,7 @@ add_task(function test_addLogin_badDates() {
|
|||
!!Services.logins.addLogin(loginInfo),
|
||||
"Check -1 value for " + pname
|
||||
);
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
}
|
||||
|
||||
// out-of-range dates will throw
|
||||
|
@ -544,5 +544,5 @@ add_task(async function test_addLogins_badDates() {
|
|||
let savedLogins = Services.logins.getAllLogins();
|
||||
Assert.equal(savedLogins.length, 1);
|
||||
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
|
|
|
@ -84,7 +84,7 @@ add_task(async function test_logins_decrypt_failure() {
|
|||
Assert.equal(Services.logins.countLogins("", "", ""), logins.length);
|
||||
|
||||
// Removing all logins removes the non-decryptable entries also.
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
Assert.equal(Services.logins.getAllLogins().length, 0);
|
||||
Assert.equal(Services.logins.countLogins("", "", ""), 0);
|
||||
});
|
||||
|
@ -151,7 +151,7 @@ add_task(function test_add_logins_with_decrypt_failure() {
|
|||
Services.logins.addLogin(login);
|
||||
equal(Services.logins.searchLogins(searchProp).length, 1);
|
||||
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
|
||||
// Test the "syncID" metadata works as expected on decryption failure.
|
||||
|
|
|
@ -46,7 +46,7 @@ add_task(async function test_invalid_logins() {
|
|||
0,
|
||||
`Should have no logins in storage: ${JSON.stringify(savedLogins, null, 2)}`
|
||||
);
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
|
||||
add_task(async function test_new_logins() {
|
||||
|
@ -97,7 +97,7 @@ add_task(async function test_new_logins() {
|
|||
2,
|
||||
"There should be 2 logins in total"
|
||||
);
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
|
||||
add_task(async function test_duplicate_logins() {
|
||||
|
@ -135,7 +135,7 @@ add_task(async function test_duplicate_logins() {
|
|||
1,
|
||||
`There should still be 1 login for ${HOST1}`
|
||||
);
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
|
||||
add_task(async function test_different_passwords() {
|
||||
|
@ -208,7 +208,7 @@ add_task(async function test_different_passwords() {
|
|||
"We should NOT have updated the password for this login."
|
||||
);
|
||||
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
|
||||
add_task(async function test_different_usernames_without_guid() {
|
||||
|
@ -247,7 +247,7 @@ add_task(async function test_different_usernames_without_guid() {
|
|||
`There should now be 2 logins for ${HOST1}`
|
||||
);
|
||||
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
|
||||
add_task(async function test_different_usernames_with_guid() {
|
||||
|
@ -289,7 +289,7 @@ add_task(async function test_different_usernames_with_guid() {
|
|||
Assert.equal(storageLogin.username, USER2, "Check username updated");
|
||||
Assert.equal(storageLogin.origin, HOST2, "Check origin updated");
|
||||
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
|
||||
add_task(async function test_different_targets() {
|
||||
|
@ -355,5 +355,5 @@ add_task(async function test_different_targets() {
|
|||
`There should now be 2 logins for ${HOST1}`
|
||||
);
|
||||
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
});
|
||||
|
|
|
@ -37,7 +37,7 @@ async function setupCsv(csvLines) {
|
|||
TTU.getAndClearKeyedHistogram("FX_MIGRATION_LOGINS_QUANTITY");
|
||||
TTU.getAndClearKeyedHistogram("FX_MIGRATION_LOGINS_IMPORT_MS");
|
||||
TTU.getAndClearKeyedHistogram("FX_MIGRATION_LOGINS_JANK_MS");
|
||||
Services.logins.removeAllLogins();
|
||||
Services.logins.removeAllUserFacingLogins();
|
||||
|
||||
let tmpFile = await LoginTestUtils.file.setupCsvFileWithLines(csvLines);
|
||||
return tmpFile.path;
|
||||
|
|
|
@ -35,7 +35,7 @@ let TestObserver = {
|
|||
Assert.ok(expectedData.equals(subject)); // nsILoginInfo.equals()
|
||||
break;
|
||||
case "removeAllLogins":
|
||||
Assert.equal(subject, null);
|
||||
Assert.ok(subject instanceof Ci.nsIArray);
|
||||
break;
|
||||
case "hostSavingEnabled":
|
||||
case "hostSavingDisabled":
|
||||
|
@ -126,6 +126,10 @@ add_task(function test_notifications() {
|
|||
testnum++;
|
||||
testdesc = "removeAllLogins (again)";
|
||||
|
||||
expectedNotification = "addLogin";
|
||||
expectedData = testuser1;
|
||||
Services.logins.addLogin(testuser1);
|
||||
|
||||
expectedNotification = "removeAllLogins";
|
||||
expectedData = null;
|
||||
Services.logins.removeAllLogins();
|
||||
|
|
Загрузка…
Ссылка в новой задаче