Commit 0a88f283 authored by Viktor Semeniuk's avatar Viktor Semeniuk Committed by Commit Bot

[Passwords] Reminder in autofill section

This change adds reminder about compromised credentials found during
password check to the autofill page. Also, this change implements
PasswordCheckBehavior to reduce code duplication in password_check
passwords_section and autofill_page files.

Mock: https://docs.google.com/presentation/d/1yWuZO-fjXhdRp64nWRbnHEyzpFd1KOMS3u1_1XMdGuA/edit#slide=id.g7c9229dfe2_9_1

Bug: 1047726
Change-Id: I48e3e2b999d4f521f5018fb3ca0b0376d66eefa6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2120417Reviewed-by: default avatarJan Wilken Dörrie <jdoerrie@chromium.org>
Reviewed-by: default avatardpapad <dpapad@chromium.org>
Commit-Queue: Viktor Semeniuk <vsemeniuk@google.com>
Cr-Commit-Position: refs/heads/master@{#755341}
parent 7c20ada6
......@@ -16,6 +16,7 @@ js_type_check("closure_compile") {
":credit_card_edit_dialog",
":credit_card_list_entry",
":password_check",
":password_check_behavior",
":password_check_edit_dialog",
":password_check_list_item",
":password_edit_dialog",
......@@ -33,6 +34,7 @@ js_type_check("closure_compile") {
js_library("autofill_page") {
deps = [
":autofill_section",
":password_check_behavior",
":passwords_section",
":payments_section",
"..:open_window_proxy",
......@@ -52,6 +54,7 @@ js_library("autofill_page") {
js_library("autofill_section") {
deps = [
":address_edit_dialog",
":password_check_behavior",
"//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu",
"//ui/webui/resources/js:assert",
"//ui/webui/resources/js:load_time_data",
......@@ -97,6 +100,7 @@ js_library("credit_card_list_entry") {
js_library("password_check") {
deps = [
":password_check_behavior",
":password_manager_proxy",
"..:plural_string_proxy",
"../prefs:prefs_behavior",
......@@ -105,6 +109,14 @@ js_library("password_check") {
]
}
js_library("password_check_behavior") {
deps = [
":password_manager_proxy",
"..:plural_string_proxy",
]
externs_list = [ "$externs_path/passwords_private.js" ]
}
js_library("password_check_edit_dialog") {
deps = [
":password_manager_proxy",
......@@ -203,6 +215,7 @@ js_type_check("closure_compile_module") {
":credit_card_edit_dialog.m",
":credit_card_list_entry.m",
":password_check.m",
":password_check_behavior.m",
":password_check_edit_dialog.m",
":password_check_list_item.m",
":password_edit_dialog.m",
......@@ -234,6 +247,7 @@ js_library("address_edit_dialog.m") {
js_library("autofill_page.m") {
sources = [ "$root_gen_dir/chrome/browser/resources/settings/autofill_page/autofill_page.m.js" ]
deps = [
":password_check_behavior.m",
"..:open_window_proxy.m",
"..:route.m",
"..:router.m",
......@@ -293,6 +307,7 @@ js_library("credit_card_list_entry.m") {
js_library("password_check.m") {
sources = [ "$root_gen_dir/chrome/browser/resources/settings/autofill_page/password_check.m.js" ]
deps = [
":password_check_behavior.m",
":password_manager_proxy.m",
"..:plural_string_proxy.m",
"../prefs:prefs_behavior.m",
......@@ -303,6 +318,16 @@ js_library("password_check.m") {
extra_deps = [ ":password_check_module" ]
}
js_library("password_check_behavior.m") {
sources = [ "$root_gen_dir/chrome/browser/resources/settings/autofill_page/password_check_behavior.m.js" ]
deps = [
":password_manager_proxy.m",
"..:plural_string_proxy.m",
]
externs_list = [ "$externs_path/passwords_private.js" ]
extra_deps = [ ":modulize" ]
}
js_library("password_check_edit_dialog.m") {
sources = [ "$root_gen_dir/chrome/browser/resources/settings/autofill_page/password_check_edit_dialog.m.js" ]
deps = [
......@@ -653,6 +678,7 @@ polymer_modulizer("upi_id_list_entry") {
js_modulizer("modulize") {
input_files = [
"blocking_request_manager.js",
"password_check_behavior.js",
"password_manager_proxy.js",
"show_password_behavior.js",
]
......
......@@ -12,6 +12,7 @@
<link rel="import" href="../settings_page/settings_animated_pages.html">
<link rel="import" href="../settings_page/settings_subpage.html">
<link rel="import" href="../settings_shared_css.html">
<link rel="import" href="./password_check_behavior.html">
<link rel="import" href="./password_manager_proxy.html">
<dom-module id="settings-autofill-page">
......@@ -20,16 +21,30 @@
cr-link-row {
--cr-icon-button-margin-start: 20px;
}
cr-link-row:not([hidden]) + cr-link-row {
border-top: var(--cr-separator-line);
}
#passwordManagerSubLabel {
color: var(--google-red-600);
}
@media (prefers-color-scheme: dark) {
#passwordManagerSubLabel {
color: var(--google-red-refresh-300);
}
}
</style>
<settings-animated-pages id="pages" section="autofill"
focus-config="[[focusConfig_]]">
<div route-path="default">
<cr-link-row id="passwordManagerButton" start-icon="settings20:vpn-key"
label="$i18n{passwords}" on-click="onPasswordsClick_"
role-description="$i18n{subpageArrowRoleDescription}"></cr-link-row>
role-description="$i18n{subpageArrowRoleDescription}">
<span id="passwordManagerSubLabel" slot="sub-label">
[[passwordManagerSubLabel_]]</span>
</cr-link-row>
<cr-link-row id="paymentManagerButton"
start-icon="settings20:credit-card" label="$i18n{creditCards}"
on-click="onPaymentsClick_"
......
......@@ -10,7 +10,10 @@
Polymer({
is: 'settings-autofill-page',
behaviors: [PrefsBehavior],
behaviors: [
PrefsBehavior,
PasswordCheckBehavior,
],
properties: {
/** @private Filter applied to passwords and password exceptions. */
......@@ -34,6 +37,12 @@ Polymer({
return map;
},
},
/** @private */
passwordManagerSubLabel_: {
type: String,
computed: 'computePasswordManagerSubLabel_(compromisedPasswordsCount)',
}
},
/**
......@@ -65,4 +74,18 @@ Polymer({
loadTimeData.getString('googlePasswordManagerUrl')) :
settings.Router.getInstance().navigateTo(settings.routes.PASSWORDS);
},
/**
* @return {string} The sub-title message indicating the result of password
* check.
* @private
*/
computePasswordManagerSubLabel_() {
if (!loadTimeData.getBoolean('enablePasswordCheck')) {
return '';
}
return this.leakedPasswords.length > 0 ? this.compromisedPasswordsCount :
'';
},
});
......@@ -18,6 +18,7 @@
<link rel="import" href="../router.html">
<link rel="import" href="../prefs/prefs.html">
<link rel="import" href="../prefs/prefs_behavior.html">
<link rel="import" href="password_check_behavior.html">
<link rel="import" href="password_check_edit_dialog.html">
<link rel="import" href="password_check_list_item.html">
<link rel="import" href="password_manager_proxy.html">
......@@ -67,25 +68,25 @@
</style>
<!-- The banner is visible if no compromised password was found (yet). -->
<template is="dom-if" if="[[shouldShowBanner_(status_, leakedPasswords)]]">
<template is="dom-if" if="[[shouldShowBanner_(status, leakedPasswords)]]">
<picture>
<source srcset="[[bannerImageSrc_(1, status_)]]"
<source srcset="[[bannerImageSrc_(1, status)]]"
media="(prefers-color-scheme: dark)">
<img id="bannerImage" src="[[bannerImageSrc_(0, status_)]]" alt="">
<img id="bannerImage" src="[[bannerImageSrc_(0, status)]]" alt="">
</picture>
</template>
<!-- The header showing progress or result of the check-->
<div class="settings-box first two-line" id="leakCheckHeader">
<!-- If the password check concluded, show only a status Icon. -->
<template is="dom-if" if="[[!isCheckInProgress_(status_)]]">
<iron-icon class$="[[getStatusIconClass_(status_, leakedPasswords)]]"
icon="[[getStatusIcon_(status_, leakedPasswords)]]">
<template is="dom-if" if="[[!isCheckInProgress_(status)]]">
<iron-icon class$="[[getStatusIconClass_(status, leakedPasswords)]]"
icon="[[getStatusIcon_(status, leakedPasswords)]]">
</iron-icon>
</template>
<!-- Show a loader instead of an icon if passwords are still checked. -->
<template is="dom-if"if="[[isCheckInProgress_(status_)]]">
<template is="dom-if"if="[[isCheckInProgress_(status)]]">
<paper-spinner-lite id="progressSpinner" active>
</paper-spinner-lite>
</template>
......@@ -94,20 +95,20 @@
<div id="titleRow">
<span id="title" inner-h-t-m-l="[[title_]]"></span>
<span class="secondary inline" id="lastCompletedCheck"
hidden$="[[!showsTimestamp_(status_)]]">
&bull; [[status_.elapsedTimeSinceLastCheck]]
hidden$="[[!showsTimestamp_(status)]]">
&bull; [[status.elapsedTimeSinceLastCheck]]
</span>
</div>
<div class="secondary" id="subtitle"
hidden$="[[!showsPasswordsCount_(status_, leakedPasswords)]]">
[[compromisedPasswordsCount_]]
hidden$="[[!showsPasswordsCount_(status, leakedPasswords)]]">
[[compromisedPasswordsCount]]
</div>
</div>
<cr-button id="controlPasswordCheckButton"
on-click="onPasswordCheckButtonClick_"
class$="[[getButtonTypeClass_(status_)]]"
class$="[[getButtonTypeClass_(status)]]"
hidden$="[[isButtonHidden_]]">
[[getButtonText_(status_)]]
[[getButtonText_(status)]]
</cr-button>
</div>
<div id="noCompromisedCredentials"
......
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="../plural_string_proxy.html">
<script src="password_check_behavior.js"></script>
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// #import {PasswordManagerImpl, PasswordManagerProxy} from './password_manager_proxy.m.js';
// #import {PluralStringProxyImpl} from '../plural_string_proxy.m.js';
// #import {assert} from 'chrome://resources/js/assert.m.js';
/**
* This behavior bundles functionality required to get compromised credentials
* and status of password check.
* It is used by <settings-password-check> <passwords-section> and
* <settings-autofill-page>.
*
* @polymerBehavior
*/
/* #export */ const PasswordCheckBehavior = {
properties: {
/**
* The number of compromised passwords as a formatted string.
*/
compromisedPasswordsCount: String,
/**
* An array of leaked passwords to display.
* @type {!Array<!PasswordManagerProxy.CompromisedCredential>}
*/
leakedPasswords: {
type: Array,
value: () => [],
},
/**
* The status indicates progress and affects banner, title and icon.
* @type {!PasswordManagerProxy.PasswordCheckStatus}
*/
status: {
type: Object,
value: () => ({state: chrome.passwordsPrivate.PasswordCheckState.IDLE}),
},
},
/**
* @private {?function(!PasswordManagerProxy.CompromisedCredentials):void}
*/
leakedCredentialsListener_: null,
/**
* @private {?function(!PasswordManagerProxy.PasswordCheckStatus):void}
*/
statusChangedListener_: null,
/** @type {?PasswordManagerProxy} */
passwordManager: null,
/** @override */
attached() {
this.statusChangedListener_ = status => this.status = status;
this.leakedCredentialsListener_ = compromisedCredentials => {
this.updateCompromisedPasswordList(compromisedCredentials);
settings.PluralStringProxyImpl.getInstance()
.getPluralString('compromisedPasswords', this.leakedPasswords.length)
.then(count => {
this.compromisedPasswordsCount = count;
});
};
this.passwordManager = PasswordManagerImpl.getInstance();
this.passwordManager.getPasswordCheckStatus().then(
this.statusChangedListener_);
this.passwordManager.getCompromisedCredentials().then(
this.leakedCredentialsListener_);
this.passwordManager.addPasswordCheckStatusListener(
this.statusChangedListener_);
this.passwordManager.addCompromisedCredentialsListener(
this.leakedCredentialsListener_);
},
/** @override */
detached() {
this.passwordManager.removeCompromisedCredentialsListener(
assert(this.statusChangedListener_));
this.statusChangedListener_ = null;
this.passwordManager.removeCompromisedCredentialsListener(
assert(this.leakedCredentialsListener_));
this.leakedCredentialsListener_ = null;
},
/**
* Function to update compromised credentials in a proper way. New entities
* should appear in the bottom.
* @param {!Array<!PasswordManagerProxy.CompromisedCredential>} newList
* @private
*/
updateCompromisedPasswordList(newList) {
const oldList = this.leakedPasswords.slice();
const map = new Map(newList.map(item => ([item.id, item])));
const resultList = [];
for (const item of oldList) {
// If element is present in newList
if (map.has(item.id)) {
// Replace old version with new
resultList.push(map.get(item.id));
map.delete(item.id);
}
}
const addedResults = Array.from(map.values());
addedResults.sort((lhs, rhs) => {
// Phished passwords are always shown above leaked passwords.
if (lhs.compromiseType !== rhs.compromiseType) {
return lhs.compromiseType ===
chrome.passwordsPrivate.CompromiseType.PHISHED ?
-1 :
1;
}
return rhs.compromiseTime - lhs.compromiseTime;
});
resultList.push(...addedResults);
this.leakedPasswords = resultList;
},
};
......@@ -27,6 +27,7 @@
<link rel="import" href="../router.html">
<link rel="import" href="../settings_shared_css.html">
<link rel="import" href="../site_favicon.html">
<link rel="import" href="password_check_behavior.html">
<link rel="import" href="password_edit_dialog.html">
<link rel="import" href="password_list_item.html">
<link rel="import" href="password_manager_proxy.html">
......@@ -150,7 +151,7 @@
</div>
<div class="secondary" id="checkPasswordLeakCount"
hidden$="[[!hasLeakedCredentials_]]">
[[compromisedPasswordsCount_]]
[[compromisedPasswordsCount]]
</div>
<div class="secondary" id="checkPasswordLeakDescription"
hidden$="[[hasLeakedCredentials_]]">
......
......@@ -37,6 +37,7 @@ Polymer({
I18nBehavior,
WebUIListenerBehavior,
ListPropertyUpdateBehavior,
PasswordCheckBehavior,
Polymer.IronA11yKeysBehavior,
settings.GlobalScrollTargetBehavior,
PrefsBehavior,
......@@ -103,7 +104,7 @@ Polymer({
/** @private */
hasNeverCheckedPasswords_: {
type: Boolean,
value: false,
computed: 'computeHasNeverCheckedPasswords_(status)',
},
/** @private */
......@@ -122,15 +123,9 @@ Polymer({
/** @private */
hasLeakedCredentials_: {
type: Boolean,
value: false,
computed: 'computeHasLeakedCredentials_(leakedPasswords)',
},
/**
* The number of compromised passwords as a formatted string.
* @private
*/
compromisedPasswordsCount_: String,
/** @private */
hidePasswordsLink_: {
type: Boolean,
......@@ -216,10 +211,7 @@ Polymer({
*/
activeDialogAnchorStack_: [],
/**
* @type {PasswordManagerProxy}
* @private
*/
/** @private {?PasswordManagerProxy} */
passwordManager_: null,
/**
......@@ -240,18 +232,6 @@ Polymer({
*/
setPasswordExceptionsListener_: null,
/**
* @type {?function(!PasswordManagerProxy.CompromisedCredentials):void}
* @private
*/
setLeakedCredentialsListener_: null,
/**
* @type {?function(!PasswordManagerProxy.PasswordCheckStatus):void}
* @private
*/
statusChangedListener_: null,
/** @override */
attached() {
// Create listener functions.
......@@ -272,29 +252,10 @@ Polymer({
this.passwordExceptions = list;
};
// TODO(https://crbug.com/1047726) Remove code duplication with
// password_check.js
const setLeakedCredentialsListener = credentials => {
this.hasLeakedCredentials_ = credentials.length > 0;
settings.PluralStringProxyImpl.getInstance()
.getPluralString('compromisedPasswords', credentials.length)
.then(compromisedPasswordCount => {
this.compromisedPasswordsCount_ = compromisedPasswordCount;
});
};
// TODO(https://crbug.com/1047726) Remove code duplication with
// password_check.js
const statusChangeListener = status => {
this.hasNeverCheckedPasswords_ = !status.elapsedTimeSinceLastCheck;
};
this.setIsOptedInForAccountStorageListener_ =
setIsOptedInForAccountStorageListener;
this.setSavedPasswordsListener_ = setSavedPasswordsListener;
this.setPasswordExceptionsListener_ = setPasswordExceptionsListener;
this.setLeakedCredentialsListener_ = setLeakedCredentialsListener;
this.statusChangedListener_ = statusChangeListener;
// Set the manager. These can be overridden by tests.
this.passwordManager_ = PasswordManagerImpl.getInstance();
......@@ -317,10 +278,6 @@ Polymer({
setIsOptedInForAccountStorageListener);
this.passwordManager_.getSavedPasswordList(setSavedPasswordsListener);
this.passwordManager_.getExceptionList(setPasswordExceptionsListener);
this.passwordManager_.getCompromisedCredentials().then(
this.setLeakedCredentialsListener_);
this.passwordManager_.getPasswordCheckStatus().then(
this.statusChangedListener_);
// Listen for changes.
this.passwordManager_.addAccountStorageOptInStateListener(
......@@ -329,10 +286,6 @@ Polymer({
setSavedPasswordsListener);
this.passwordManager_.addExceptionListChangedListener(
setPasswordExceptionsListener);
this.passwordManager_.addCompromisedCredentialsListener(
this.setLeakedCredentialsListener_);
this.passwordManager_.addPasswordCheckStatusListener(
this.statusChangedListener_);
this.notifySplices('savedPasswords', []);
......@@ -354,25 +307,11 @@ Polymer({
/** @override */
detached() {
this.passwordManager_.removeSavedPasswordListChangedListener(
/**
* @type {function(!Array<PasswordManagerProxy.PasswordUiEntry>):void}
*/
(this.setSavedPasswordsListener_));
assert(this.setSavedPasswordsListener_));
this.passwordManager_.removeExceptionListChangedListener(
/**
* @type {function(!Array<PasswordManagerProxy.ExceptionEntry>):void}
*/
(this.setPasswordExceptionsListener_));
assert(this.setPasswordExceptionsListener_));
this.passwordManager_.removeAccountStorageOptInStateListener(
/**
* @type {function(boolean):void}
*/
(this.setIsOptedInForAccountStorageListener_));
this.passwordManager_.removeCompromisedCredentialsListener(
assert(this.setLeakedCredentialsListener_));
this.passwordManager_.removePasswordCheckStatusListener(
assert(this.statusChangedListener_));
assert(this.setIsOptedInForAccountStorageListener_));
if (cr.toastManager.getToastManager().isToastOpen) {
cr.toastManager.getToastManager().hide();
......@@ -658,5 +597,21 @@ Polymer({
// TODO(crbug.com/1049141): Add the proper icons once we know them.
return item.fromAccountStore ? 'cr:sync' : 'cr:computer';
},
/**
* @private
* @return {boolean}
*/
computeHasLeakedCredentials_() {
return this.leakedPasswords.length > 0;
},
/**
* @private
* @return {boolean}
*/
computeHasNeverCheckedPasswords_() {
return !this.status.elapsedTimeSinceLastCheck;
},
});
})();
......@@ -121,6 +121,7 @@ settings_namespace_rewrites = [
settings_auto_imports = [
"chrome/browser/resources/settings/autofill_page/blocking_request_manager.html|BlockingRequestManager",
"chrome/browser/resources/settings/autofill_page/credit_card_list_entry.html|CreditCardEntry",
"chrome/browser/resources/settings/autofill_page/password_check_behavior.html|PasswordCheckBehavior",
"chrome/browser/resources/settings/autofill_page/show_password_behavior.html|ShowPasswordBehavior",
"chrome/browser/resources/settings/controls/pref_control_behavior.html|PrefControlBehavior",
"chrome/browser/resources/settings/controls/settings_boolean_control_behavior.html|SettingsBooleanControlBehavior",
......
......@@ -54,6 +54,7 @@ export {PageStatus, StatusAction, SyncBrowserProxyImpl} from './people_page/sync
export {ProfileInfoBrowserProxyImpl} from './people_page/profile_info_browser_proxy.m.js';
export {pageVisibility} from './page_visibility.m.js';
export {PasswordManagerProxy, PasswordManagerImpl} from './autofill_page/password_manager_proxy.m.js';
export {PluralStringProxyImpl} from './plural_string_proxy.m.js';
export {prefToString, stringToPrefValue} from './prefs/pref_util.m.js';
export {ResetBrowserProxyImpl} from './reset_page/reset_browser_proxy.m.js';
export {routes} from './route.m.js';
......
......@@ -661,6 +661,12 @@
<structure name="IDR_SETTINGS_PASSWORD_CHECK_JS"
file="autofill_page/password_check.js"
type="chrome_html" />
<structure name="IDR_SETTINGS_PASSWORD_CHECK_BEHAVIOR_HTML"
file="autofill_page/password_check_behavior.html"
type="chrome_html" />
<structure name="IDR_SETTINGS_PASSWORD_CHECK_BEHAVIOR_JS"
file="autofill_page/password_check_behavior.js"
type="chrome_html" />
<structure name="IDR_SETTINGS_PASSWORD_CHECK_EDIT_DIALOG_HTML"
file="autofill_page/password_check_edit_dialog.html"
type="chrome_html" />
......
......@@ -98,6 +98,10 @@
file="${root_gen_dir}/chrome/browser/resources/settings/autofill_page/password_check.m.js"
use_base_dir="false"
type="BINDATA" />
<include name="IDR_SETTINGS_AUTOFILL_PAGE_PASSWORD_CHECK_BEHAVIOR_M_JS"
file="${root_gen_dir}/chrome/browser/resources/settings/autofill_page/password_check_behavior.m.js"
use_base_dir="false"
type="BINDATA" />
<include name="IDR_SETTINGS_AUTOFILL_PAGE_PASSWORD_CHECK_EDIT_DIALOG_M_JS"
file="${root_gen_dir}/chrome/browser/resources/settings/autofill_page/password_check_edit_dialog.m.js"
use_base_dir="false"
......
......@@ -293,6 +293,7 @@ js2gtest("browser_tests_js_webui") {
"$root_gen_dir/chrome/test/data/webui/settings/test_lifetime_browser_proxy.m.js",
"$root_gen_dir/chrome/test/data/webui/settings/test_open_window_proxy.m.js",
"$root_gen_dir/chrome/test/data/webui/settings/test_password_manager_proxy.m.js",
"$root_gen_dir/chrome/test/data/webui/settings/test_plural_string_proxy.m.js",
"$root_gen_dir/chrome/test/data/webui/settings/test_privacy_page_browser_proxy.m.js",
"$root_gen_dir/chrome/test/data/webui/settings/test_profile_info_browser_proxy.m.js",
"$root_gen_dir/chrome/test/data/webui/settings/test_reset_browser_proxy.m.js",
......
......@@ -91,6 +91,7 @@ js_modulizer("modulize") {
"test_metrics_browser_proxy.js",
"test_open_window_proxy.js",
"test_password_manager_proxy.js",
"test_plural_string_proxy.js",
"test_privacy_page_browser_proxy.js",
"test_profile_info_browser_proxy.js",
"test_reset_browser_proxy.js",
......
......@@ -3,12 +3,14 @@
// found in the LICENSE file.
// clang-format off
// #import {CrSettingsPrefs, OpenWindowProxyImpl, PasswordManagerImpl, Router, routes} from 'chrome://settings/settings.js';
// #import {CrSettingsPrefs, OpenWindowProxyImpl, PasswordManagerImpl, PluralStringProxyImpl, Router, routes} from 'chrome://settings/settings.js';
// #import {AutofillManagerImpl, PaymentsManagerImpl} from 'chrome://settings/lazy_load.js';
// #import {createAddressEntry, createCreditCardEntry, createExceptionEntry, createPasswordEntry, AutofillManagerExpectations, PasswordManagerExpectations, PaymentsManagerExpectations, TestAutofillManager, TestPaymentsManager} from 'chrome://test/settings/passwords_and_autofill_fake_data.m.js';
// #import {FakeSettingsPrivate} from 'chrome://test/settings/fake_settings_private.m.js';
// #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
// #import {makeCompromisedCredential} from 'chrome://test/settings/passwords_and_autofill_fake_data.m.js';
// #import {TestPasswordManagerProxy} from 'chrome://test/settings/test_password_manager_proxy.m.js';
// #import {TestPluralStringProxy} from 'chrome://test/settings/test_plural_string_proxy.m.js';
// #import {TestOpenWindowProxy} from 'chrome://test/settings/test_open_window_proxy.m.js';
// clang-format on
......@@ -282,33 +284,46 @@ suite('PasswordsAndForms', function() {
});
});
function createAutofillPageSection() {
// Create a passwords-section to use for testing.
const autofillPage = document.createElement('settings-autofill-page');
autofillPage.prefs = {
profile: {
password_manager_leak_detection: {},
},
};
PolymerTest.clearBody();
document.body.appendChild(autofillPage);
Polymer.dom.flush();
return autofillPage;
}
suite('PasswordsUITest', function() {
/** @type {SettingsAutofillPageElement} */
let autofillPage = null;
/** @type {settings.OpenWindowProxy} */
let openWindowProxy = null;
let passwordManager;
let pluaralString;
suiteSetup(function() {
// Forces navigation to Google Password Manager to be off by default.
loadTimeData.overrideValues({
navigateToGooglePasswordManager: false,
enablePasswordCheck: true,
});
});
setup(function() {
openWindowProxy = new TestOpenWindowProxy();
settings.OpenWindowProxyImpl.instance_ = openWindowProxy;
// Override the PasswordManagerImpl for testing.
passwordManager = new TestPasswordManagerProxy();
PasswordManagerImpl.instance_ = passwordManager;
pluaralString = new TestPluralStringProxy();
settings.PluralStringProxyImpl.instance_ = pluaralString;
PolymerTest.clearBody();
autofillPage = document.createElement('settings-autofill-page');
autofillPage.prefs = {
profile: {
password_manager_leak_detection: {},
},
};
document.body.appendChild(autofillPage);
Polymer.dom.flush();
autofillPage = createAutofillPageSection();
});
teardown(function() {
......@@ -343,4 +358,29 @@ suite('PasswordsUITest', function() {
assertEquals(googlePasswordManagerUrl, url);
});
});
test('Compromised Credential', async function() {
// Check if sublabel is empty
assertEquals(
'',
autofillPage.$$('#passwordManagerSubLabel').innerText.trim());
// Simulate one compromised password
const leakedPasswords = [
autofill_test_util.makeCompromisedCredential(
'google.com', 'jdoerrie', 'LEAKED'),
];
passwordManager.data.leakedCredentials = leakedPasswords;
// create autofill page with leaked credentials
autofillPage = createAutofillPageSection();
await passwordManager.whenCalled('getCompromisedCredentials');
await pluaralString.whenCalled('getPluralString');
// With compromised credentials sublabel should have text
assertNotEquals(
'',
autofillPage.$$('#passwordManagerSubLabel').innerText.trim());
});
});
......@@ -275,6 +275,7 @@ CrSettingsAutofillPageTest.prototype = {
'passwords_and_autofill_fake_data.js',
'test_open_window_proxy.js',
'test_password_manager_proxy.js',
'test_plural_string_proxy.js',
'autofill_page_test.js',
]),
};
......
......@@ -496,7 +496,7 @@ cr.define('settings_passwords_check', function() {
const checkPasswordSection = createCheckPasswordSection();
await passwordManager.whenCalled('getPasswordCheckStatus');
Polymer.dom.flush();
expectEquals(PasswordCheckState.IDLE, checkPasswordSection.status_.state);
expectEquals(PasswordCheckState.IDLE, checkPasswordSection.status.state);
});
// Tests that the spinner is replaced with a checkmark on successful runs.
......@@ -941,7 +941,7 @@ cr.define('settings_passwords_check', function() {
'two.com', 'test3', 'LEAKED', 2, 0),
];
const checkPasswordSection = createCheckPasswordSection();
checkPasswordSection.updateList_(leakedPasswords);
checkPasswordSection.updateCompromisedPasswordList(leakedPasswords);
Polymer.dom.flush();
validateLeakedPasswordsList(checkPasswordSection, leakedPasswords);
......@@ -952,7 +952,8 @@ cr.define('settings_passwords_check', function() {
'four.com', 'test1', 'LEAKED', 4, 5));
leakedPasswords.push(autofill_test_util.makeCompromisedCredential(
'five.com', 'test0', 'LEAKED', 5, 4));
checkPasswordSection.updateList_(shuffleArray(leakedPasswords));
checkPasswordSection.updateCompromisedPasswordList(
shuffleArray(leakedPasswords));
Polymer.dom.flush();
validateLeakedPasswordsList(checkPasswordSection, leakedPasswords);
});
......@@ -970,7 +971,7 @@ cr.define('settings_passwords_check', function() {
'four.com', 'test2', 'LEAKED', 3, 2),
];
const checkPasswordSection = createCheckPasswordSection();
checkPasswordSection.updateList_(leakedPasswords);
checkPasswordSection.updateCompromisedPasswordList(leakedPasswords);
Polymer.dom.flush();
validateLeakedPasswordsList(checkPasswordSection, leakedPasswords);
......@@ -979,7 +980,8 @@ cr.define('settings_passwords_check', function() {
leakedPasswords.push(autofill_test_util.makeCompromisedCredential(
'five.com', 'test2', 'LEAKED', 4, 3));
checkPasswordSection.updateList_(shuffleArray(leakedPasswords));
checkPasswordSection.updateCompromisedPasswordList(
shuffleArray(leakedPasswords));
Polymer.dom.flush();
validateLeakedPasswordsList(checkPasswordSection, leakedPasswords);
});
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/** @fileoverview Test implementation of PluralStringProxy. */
// clang-format off
// #import {TestBrowserProxy} from 'chrome://test/test_browser_proxy.m.js';
// clang-format on
/**
* Test implementation
* @implements {PluralStringProxy}
* @constructor
*/
/* #export */ class TestPluralStringProxy extends TestBrowserProxy {
constructor() {
super([
'getPluralString',
]);
}
/** override */
getPluralString(messageName, itemCount) {
this.methodCalled('getPluralString', {messageName, itemCount});
return Promise.resolve('some text');
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment