Commit 2a439018 authored by Viktor Semeniuk's avatar Viktor Semeniuk Committed by Commit Bot

[Passwords] UI for password check


This change adds basic UI for password check page. Change includes
number of compromised credentials, last refresh time, and button to run
password check manually.

Bug: 1047726
Change-Id: If7a9f7ad2c35ccd070e090514d38d313a22d6d6b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2068602Reviewed-by: default avatarMarc Treib <treib@chromium.org>
Reviewed-by: default avatarJan Wilken Dörrie <jdoerrie@chromium.org>
Commit-Queue: Viktor Semeniuk <vsemeniuk@google.com>
Cr-Commit-Position: refs/heads/master@{#744616}
parent 4369629b
...@@ -448,9 +448,18 @@ ...@@ -448,9 +448,18 @@
<message name="IDS_SETTINGS_CHECK_PASSWORDS" desc="Name for the check passwords subsection and settings entry used to perform a password bulk check."> <message name="IDS_SETTINGS_CHECK_PASSWORDS" desc="Name for the check passwords subsection and settings entry used to perform a password bulk check.">
Check passwords Check passwords
</message> </message>
<message name="IDS_SETTINGS_CHECKED_PASSWORDS" desc="Title above amount of found compromised passwords after password bulk check.">
Checked passwords
</message>
<message name="IDS_SETTINGS_CHECK_PASSWORDS_DESCRIPTION" desc="Explanation of the passwords bulk check feature found within the password settings."> <message name="IDS_SETTINGS_CHECK_PASSWORDS_DESCRIPTION" desc="Explanation of the passwords bulk check feature found within the password settings.">
Keep your passwords safe from data breaches and other security issues Keep your passwords safe from data breaches and other security issues
</message> </message>
<message name="IDS_SETTINGS_LEAKED_PASSWORDS_COUNT" desc="Number of compromised passwords found during bulk check.">
<ph name="COUNT">$1<ex>5</ex></ph> compromised passwords
</message>
<message name="IDS_SETTINGS_CHECK_PASSWORDS_AGAIN" desc="Button to start bulk password check manually in passwords check section.">
Check again
</message>
<message name="IDS_SETTINGS_PASSWORDS_SAVE_PASSWORDS_TOGGLE_LABEL" desc="Label for a toggle that allows users to be prompted if they want to save their passwords when logging into webpages."> <message name="IDS_SETTINGS_PASSWORDS_SAVE_PASSWORDS_TOGGLE_LABEL" desc="Label for a toggle that allows users to be prompted if they want to save their passwords when logging into webpages.">
Offer to save passwords Offer to save passwords
</message> </message>
......
956520bbbe69fb947a771b72de567f1bac2ac5c4
\ No newline at end of file
956520bbbe69fb947a771b72de567f1bac2ac5c4
\ No newline at end of file
956520bbbe69fb947a771b72de567f1bac2ac5c4
\ No newline at end of file
...@@ -52,10 +52,9 @@ ...@@ -52,10 +52,9 @@
</template> </template>
<template is="dom-if" route-path="/passwords/check"> <template is="dom-if" route-path="/passwords/check">
<settings-subpage <settings-subpage
associated-control="[[$$('#passwordManagerButton')]]"
page-title="$i18n{checkPasswords}" page-title="$i18n{checkPasswords}"
learn-more-url="$i18n{passwordCheckLearnMoreURL}"> learn-more-url="$i18n{passwordCheckLearnMoreURL}">
<password-check></password-check> <settings-password-check></settings-password-check>
</settings-subpage> </settings-subpage>
</template> </template>
<template is="dom-if" route-path="/payments"> <template is="dom-if" route-path="/payments">
......
<link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/html/polymer.html">
<dom-module id="password-check"> <link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
<link rel="import" href="../i18n_setup.html">
<link rel="import" href="../settings_shared_css.html">
<link rel="import" href="chrome://resources/cr_elements/icons.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<dom-module id="settings-password-check">
<template> <template>
<style include="settings-shared">
#leak-passwords-icon {
--iron-icon-fill-color: var(--google-red-600);
padding-inline-end: 20px;
}
</style>
<div class="settings-box first two-line" id="leakCheckHeader">
<!--TODO(https://crbug.com/1047726) add background to icon-->
<iron-icon id="leak-passwords-icon" icon="cr:warning"></iron-icon>
<div class="start settings-box-text">
<div>
$i18n{checkedPasswords}
<span class="secondary inline" id="lastCompletedCheck">
&bull; [[getLastCompletedCheck_(passwordLeakCount_)]]
</span>
</div>
<div class="secondary" id="passwordLeakCount"
name="[[passwordLeakCount_]]">
[[getLeakedPasswordsCount_(passwordLeakCount_)]]
</div>
</div>
<cr-button id="controlPasswordCheckButton"
on-click="onPasswordCheckButtonClick_">
$i18n{checkPasswordsAgain}
</cr-button>
</div>
<div class="settings-box"></div>
</template> </template>
<script src="password_check.js"></script> <script src="password_check.js"></script>
</dom-module> </dom-module>
...@@ -4,4 +4,52 @@ ...@@ -4,4 +4,52 @@
Polymer({ Polymer({
is: 'settings-password-check', is: 'settings-password-check',
behaviors: [I18nBehavior],
properties: {
/** @private */
passwordLeakCount_: {
type: Number,
value: 0,
},
/** @private */
lastCompletedCheck_: Date,
},
/**
* @type {PasswordManagerProxy}
* @private
*/
passwordManager_: null,
/** @override */
attached() {
// It's just a placeholder at the moment.
this.passwordLeakCount_ = 5;
// Set the manager. These can be overridden by tests.
this.passwordManager_ = PasswordManagerImpl.getInstance();
},
/**
* Start/Stop bulk password check.
* @private
*/
onPasswordCheckButtonClick_() {
// TODO(https://crbug.com/1047726): By click on this button user should be
// able to 'Cancel' current check.
this.passwordManager_.startBulkPasswordCheck();
},
getLeakedPasswordsCount_() {
return this.i18n('checkPasswordLeakCount', this.passwordLeakCount_);
},
getLastCompletedCheck_() {
// TODO(https://crbug.com/1047726): use lastCompletedCheck_ to return proper
// passed time from the last password check.
return '5 min ago';
},
}); });
...@@ -148,6 +148,11 @@ class PasswordManagerProxy { ...@@ -148,6 +148,11 @@ class PasswordManagerProxy {
* @return {!Promise<(boolean)>} A promise that resolves to the opt-in state. * @return {!Promise<(boolean)>} A promise that resolves to the opt-in state.
*/ */
isOptedInForAccountStorage() {} isOptedInForAccountStorage() {}
/**
* Requests the start of the bulk password check.
*/
startBulkPasswordCheck() {}
} }
/** @typedef {chrome.passwordsPrivate.PasswordUiEntry} */ /** @typedef {chrome.passwordsPrivate.PasswordUiEntry} */
...@@ -289,6 +294,9 @@ class PasswordManagerImpl { ...@@ -289,6 +294,9 @@ class PasswordManagerImpl {
chrome.passwordsPrivate.isOptedInForAccountStorage(resolve); chrome.passwordsPrivate.isOptedInForAccountStorage(resolve);
}); });
} }
/** @override */
startBulkPasswordCheck() {}
} }
cr.addSingletonGetter(PasswordManagerImpl); cr.addSingletonGetter(PasswordManagerImpl);
...@@ -738,7 +738,10 @@ void AddAutofillStrings(content::WebUIDataSource* html_source, ...@@ -738,7 +738,10 @@ void AddAutofillStrings(content::WebUIDataSource* html_source,
{"autofillPageTitle", IDS_SETTINGS_AUTOFILL}, {"autofillPageTitle", IDS_SETTINGS_AUTOFILL},
{"passwords", IDS_SETTINGS_PASSWORDS}, {"passwords", IDS_SETTINGS_PASSWORDS},
{"checkPasswords", IDS_SETTINGS_CHECK_PASSWORDS}, {"checkPasswords", IDS_SETTINGS_CHECK_PASSWORDS},
{"checkedPasswords", IDS_SETTINGS_CHECKED_PASSWORDS},
{"checkPasswordsDescription", IDS_SETTINGS_CHECK_PASSWORDS_DESCRIPTION}, {"checkPasswordsDescription", IDS_SETTINGS_CHECK_PASSWORDS_DESCRIPTION},
{"checkPasswordLeakCount", IDS_SETTINGS_LEAKED_PASSWORDS_COUNT},
{"checkPasswordsAgain", IDS_SETTINGS_CHECK_PASSWORDS_AGAIN},
{"creditCards", IDS_AUTOFILL_PAYMENT_METHODS}, {"creditCards", IDS_AUTOFILL_PAYMENT_METHODS},
{"noCreditCardsFound", IDS_SETTINGS_PAYMENT_METHODS_NONE}, {"noCreditCardsFound", IDS_SETTINGS_PAYMENT_METHODS_NONE},
{"googlePayments", IDS_SETTINGS_GOOGLE_PAYMENTS}, {"googlePayments", IDS_SETTINGS_GOOGLE_PAYMENTS},
......
...@@ -341,6 +341,33 @@ TEST_F('CrSettingsPasswordsSectionTest', 'All', function() { ...@@ -341,6 +341,33 @@ TEST_F('CrSettingsPasswordsSectionTest', 'All', function() {
mocha.run(); mocha.run();
}); });
/**
* Test fixture for
* chrome/browser/resources/settings/autofill_page/passwords_check.html.
* @constructor
* @extends {CrSettingsBrowserTest}
*/
function CrSettingsPasswordsCheckTest() {}
CrSettingsPasswordsCheckTest.prototype = {
__proto__: CrSettingsBrowserTest.prototype,
/** @override */
browsePreload: 'chrome://settings/autofill_page/passwords_check.html',
/** @override */
extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
'password_check_test.js',
'../test_browser_proxy.js',
'passwords_and_autofill_fake_data.js',
'test_password_manager_proxy.js',
]),
};
TEST_F('CrSettingsPasswordsCheckTest', 'All', function() {
mocha.run();
});
GEN('#if defined(OS_CHROMEOS)'); GEN('#if defined(OS_CHROMEOS)');
/** /**
* Test fixture for CrOS specific behavior in * Test fixture for CrOS specific behavior in
......
// 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 Runs the Polymer Check Password tests. */
cr.define('settings_passwords_check', function() {
function createCheckPasswordSection() {
// Create a passwords-section to use for testing.
const passwordsSection =
this.document.createElement('settings-password-check');
this.document.body.appendChild(passwordsSection);
Polymer.dom.flush();
return passwordsSection;
}
suite('PasswordsCheckSection', function() {
/** @type {TestPasswordManagerProxy} */
let passwordManager = null;
suiteSetup(function() {
loadTimeData.overrideValues({enablePasswordCheck: true});
});
setup(function() {
PolymerTest.clearBody();
// Override the PasswordManagerImpl for testing.
passwordManager = new TestPasswordManagerProxy();
PasswordManagerImpl.instance_ = passwordManager;
});
// Test verifies that clicking 'Check again' make proper function call to
// password manager
test('testCheckAgainButton', function() {
const checkSection = createCheckPasswordSection();
checkSection.$.controlPasswordCheckButton.click();
return passwordManager.whenCalled('startBulkPasswordCheck');
});
});
});
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
*/ */
class TestPasswordManagerProxy extends TestBrowserProxy { class TestPasswordManagerProxy extends TestBrowserProxy {
constructor() { constructor() {
super(['requestPlaintextPassword']); super(['requestPlaintextPassword', 'startBulkPasswordCheck']);
this.actual_ = new PasswordManagerExpectations(); this.actual_ = new PasswordManagerExpectations();
...@@ -138,4 +138,9 @@ class TestPasswordManagerProxy extends TestBrowserProxy { ...@@ -138,4 +138,9 @@ class TestPasswordManagerProxy extends TestBrowserProxy {
expected.listening.accountStorageOptInState, expected.listening.accountStorageOptInState,
actual.listening.accountStorageOptInState); actual.listening.accountStorageOptInState);
} }
/** @override */
startBulkPasswordCheck() {
this.methodCalled('startBulkPasswordCheck');
}
} }
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