Commit 912f342c authored by Monica Basta's avatar Monica Basta Committed by Commit Bot

[SyncSetup]: Change encryption UI in the sync setup settings page.

As part of Friendly settings, we are changing the encryption UI to be an
expandable button. The menu is expanded by default in case of encryption
with custom passphrase.

Screenshots:
http://screen/TjYzvt1Mm1Z
http://screen/GuBbKarc59a
http://screen/8sWerk9f6zQ

Bug: 1046410
Change-Id: Ie106c4f50a50538f4514178440df0fcd32127f1d
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2025349
Commit-Queue: Monica Basta <msalama@chromium.org>
Reviewed-by: default avatarDemetrios Papadopoulos <dpapad@chromium.org>
Cr-Commit-Position: refs/heads/master@{#738988}
parent 84d080b2
......@@ -801,6 +801,12 @@
type="chrome_html"
preprocess="true" />
<!-- TODO(jamescook): Remove when SplitSettingsSync is the default. -->
<structure name="IDR_OS_SETTINGS_SYNC_ENCRYPTION_OPTIONS_JS"
file="people_page/sync_encryption_options.js"
type="chrome_html" />
<structure name="IDR_OS_SETTINGS_SYNC_ENCRYPTION_OPTIONS_HTML"
file="people_page/sync_encryption_options.html"
type="chrome_html" />
<structure name="IDR_OS_SETTINGS_SYNC_PAGE_JS"
file="people_page/sync_page.js"
type="chrome_html"
......
......@@ -12,6 +12,7 @@ js_type_check("closure_compile") {
":sync_account_control",
":sync_browser_proxy",
":sync_controls",
":sync_encryption_options",
":sync_page",
]
......@@ -98,6 +99,7 @@ js_library("sync_page") {
deps = [
":sync_account_control",
":sync_browser_proxy",
":sync_encryption_options",
"..:page_visibility",
"..:router",
"../settings_page:settings_animated_pages",
......@@ -146,6 +148,16 @@ js_library("sync_account_control") {
]
}
js_library("sync_encryption_options") {
deps = [
":sync_browser_proxy",
"//ui/webui/resources/cr_elements/cr_input",
"//ui/webui/resources/cr_elements/cr_radio_group",
"//ui/webui/resources/js:assert",
"//ui/webui/resources/js:i18n_behavior",
]
}
# TODO(crbug.com/1026426): Fix and enable.
#js_type_check("closure_compile_module") {
# is_polymer3 = true
......
<link rel="import" href="chrome://resources/html/polymer.html">
<link rel="import" href="chrome://resources/html/i18n_behavior.html">
<link rel="import" href="chrome://resources/html/assert.html">
<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
<link rel="import" href="chrome://resources/cr_elements/cr_radio_button/cr_radio_button.html">
<link rel="import" href="chrome://resources/cr_elements/cr_radio_group/cr_radio_group.html">
<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
<link rel="import" href="sync_browser_proxy.html">
<link rel="import" href="../settings_shared_css.html">
<link rel="import" href="../settings_vars_css.html">
<dom-module id="settings-sync-encryption-options">
<template>
<style include="cr-shared-style settings-shared">
#create-password-box {
margin-bottom: 1em;
/* In order to line up with the encryption radio box text. */
margin-inline-start: var(--cr-section-indent-width);
}
#create-password-box .list-item {
margin-bottom: var(--cr-form-field-bottom-spacing);
}
cr-input {
--cr-input-width: var(--settings-input-max-width);
}
.passphrase-reset-icon {
margin-inline-end: 8px;
}
</style>
<template is="dom-if" if="[[!syncPrefs.passphraseRequired]]">
<div id="encryptionRadioGroupContainer" class="list-frame">
<cr-radio-group
id="encryptionRadioGroup"
selected="[[selectedEncryptionRadio_(syncPrefs)]]"
on-selected-changed="onEncryptionRadioSelectionChanged_"
disabled$="[[disableEncryptionOptions_]]">
<cr-radio-button name="encrypt-with-google" class="list-item"
aria-label="$i18n{encryptWithGoogleCredentialsLabel}">
$i18n{encryptWithGoogleCredentialsLabel}
</cr-radio-button>
<cr-radio-button name="encrypt-with-passphrase"
class="list-item">
<span hidden="[[!syncPrefs.fullEncryptionBody]]">
[[syncPrefs.fullEncryptionBody]]
</span>
<span on-click="onLearnMoreClick_"
hidden="[[syncPrefs.fullEncryptionBody]]">
$i18nRaw{encryptWithSyncPassphraseLabel}
</span>
</cr-radio-button>
</cr-radio-group>
</div>
</template>
<template is="dom-if" if="[[creatingNewPassphrase_]]" restamp>
<div class="list-frame">
<div id="create-password-box">
<div class="list-item">
<span>$i18nRaw{passphraseExplanationText}</span>
</div>
<cr-input id="passphraseInput" type="password"
value="{{passphrase_}}"
placeholder="$i18n{passphrasePlaceholder}"
error-message="$i18n{emptyPassphraseError}"
on-keypress="onNewPassphraseInputKeypress_">
</cr-input>
<cr-input id="passphraseConfirmationInput" type="password"
value="{{confirmation_}}"
placeholder="$i18n{passphraseConfirmationPlaceholder}"
error-message="$i18n{mismatchedPassphraseError}"
on-keypress="onNewPassphraseInputKeypress_">
</cr-input>
<cr-button id="saveNewPassphrase"
on-click="onSaveNewPassphraseClick_" class="action-button"
disabled="[[!isSaveNewPassphraseEnabled_(
passphrase_, confirmation_)]]">
$i18n{save}
</cr-button>
</div>
</div>
</template>
</template>
<script src="sync_encryption_options.js"></script>
</dom-module>
// 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.
(function() {
/**
* Names of the radio buttons which allow the user to choose their encryption
* mechanism.
* @enum {string}
*/
const RadioButtonNames = {
ENCRYPT_WITH_GOOGLE: 'encrypt-with-google',
ENCRYPT_WITH_PASSPHRASE: 'encrypt-with-passphrase',
};
Polymer({
is: 'settings-sync-encryption-options',
properties: {
/**
* @type {settings.SyncPrefs}
*/
syncPrefs: {
type: Object,
notify: true,
},
/** @type {settings.SyncStatus} */
syncStatus: Object,
/**
* Whether the "create passphrase" inputs should be shown. These inputs
* give the user the opportunity to use a custom passphrase instead of
* authenticating with their Google credentials.
* @private
*/
creatingNewPassphrase_: {
type: Boolean,
value: false,
},
/**
* The passphrase input field value.
* @private
*/
passphrase_: {
type: String,
value: '',
},
/**
* The passphrase confirmation input field value.
* @private
*/
confirmation_: {
type: String,
value: '',
},
/** @private */
disableEncryptionOptions_: {
type: Boolean,
computed: 'computeDisableEncryptionOptions_(' +
'syncPrefs, syncStatus)',
observer: 'disableEncryptionOptionsChanged_',
},
},
/**
* Whether we should disable the radio buttons that allow choosing the
* encryption options for Sync.
* We disable the buttons if:
* (a) full data encryption is enabled, or,
* (b) full data encryption is not allowed (so far, only applies to
* supervised accounts), or,
* (c) current encryption keys are missing, or,
* (d) the user is a supervised account.
* @return {boolean}
* @private
*/
computeDisableEncryptionOptions_() {
return !!(
(this.syncPrefs &&
(this.syncPrefs.encryptAllData ||
!this.syncPrefs.encryptAllDataAllowed ||
this.syncPrefs.trustedVaultKeysRequired)) ||
(this.syncStatus && this.syncStatus.supervisedUser));
},
/** @private */
disableEncryptionOptionsChanged_() {
if (this.disableEncryptionOptions_) {
this.creatingNewPassphrase_ = false;
}
},
/**
* @param {string} passphrase The passphrase input field value
* @param {string} confirmation The passphrase confirmation input field value.
* @return {boolean} Whether the passphrase save button should be enabled.
* @private
*/
isSaveNewPassphraseEnabled_(passphrase, confirmation) {
return passphrase !== '' && confirmation !== '';
},
/**
* @param {!KeyboardEvent} e
* @private
*/
onNewPassphraseInputKeypress_(e) {
if (e.type == 'keypress' && e.key != 'Enter') {
return;
}
this.saveNewPassphrase_();
},
/** @private */
onSaveNewPassphraseClick_() {
this.saveNewPassphrase_();
},
/**
* Sends the newly created custom sync passphrase to the browser.
* @private
*/
saveNewPassphrase_() {
assert(this.creatingNewPassphrase_);
// Might happen within the transient time between the request to
// |setSyncEncryption| and receiving the response.
if (this.syncPrefs.encryptAllData) {
return;
}
// If a new password has been entered but it is invalid, do not send the
// sync state to the API.
if (!this.validateCreatedPassphrases_()) {
return;
}
this.syncPrefs.encryptAllData = true;
this.syncPrefs.setNewPassphrase = true;
this.syncPrefs.passphrase = this.passphrase_;
settings.SyncBrowserProxyImpl.getInstance()
.setSyncEncryption(this.syncPrefs)
.then(pageStatus => {
this.fire('passphrase-changed', pageStatus);
});
},
/**
* Called when the encryption
* @param {!CustomEvent<{value: string}>} event
* @private
*/
onEncryptionRadioSelectionChanged_(event) {
this.creatingNewPassphrase_ =
event.detail.value == RadioButtonNames.ENCRYPT_WITH_PASSPHRASE;
},
/**
* Computed binding returning the selected encryption radio button.
* @private
*/
selectedEncryptionRadio_() {
return this.syncPrefs.encryptAllData || this.creatingNewPassphrase_ ?
RadioButtonNames.ENCRYPT_WITH_PASSPHRASE :
RadioButtonNames.ENCRYPT_WITH_GOOGLE;
},
/**
* Checks the supplied passphrases to ensure that they are not empty and that
* they match each other. Additionally, displays error UI if they are invalid.
* @return {boolean} Whether the check was successful (i.e., that the
* passphrases were valid).
* @private
*/
validateCreatedPassphrases_() {
const emptyPassphrase = !this.passphrase_;
const mismatchedPassphrase = this.passphrase_ != this.confirmation_;
this.$$('#passphraseInput').invalid = emptyPassphrase;
this.$$('#passphraseConfirmationInput').invalid =
!emptyPassphrase && mismatchedPassphrase;
return !emptyPassphrase && !mismatchedPassphrase;
},
/**
* @param {!Event} event
* @private
*/
onLearnMoreClick_(event) {
if (event.target.tagName == 'A') {
// Stop the propagation of events, so that clicking on links inside
// checkboxes or radio buttons won't change the value.
event.stopPropagation();
}
},
});
})();
......@@ -7,13 +7,15 @@
<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
<link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
<link rel="import" href="chrome://resources/cr_elements/cr_radio_button/cr_radio_button.html">
<link rel="import" href="chrome://resources/cr_elements/cr_radio_group/cr_radio_group.html">
<link rel="import" href="chrome://resources/cr_elements/icons.html">
<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
<link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html">
<link rel="import" href="sync_account_control.html">
<link rel="import" href="sync_encryption_options.html">
<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
<link rel="import" href="sync_browser_proxy.html">
<link rel="import" href="../privacy_page/personalization_options.html">
......@@ -232,73 +234,56 @@
<cr-icon-button class="icon-external"></cr-icon-button>
</a>
<div id="encryptionDescription"
hidden="[[syncPrefs.passphraseRequired]]"
class$="single-column settings-box-text
[[getPassphraseHintLines_(syncPrefs.encryptAllData)]]
list-item">
$i18n{encryptionOptionsTitle}
<div class="secondary">
$i18n{syncDataEncryptedText}
<div hidden="[[!syncPrefs.encryptAllData]]">
<iron-icon icon="cr:info-outline"
class="passphrase-reset-icon">
</iron-icon>
$i18nRaw{passphraseResetHintEncryption}
<template is="dom-if" if="[[!syncSetupFriendlySettings_]]">
<div id="encryptionDescription"
hidden="[[syncPrefs.passphraseRequired]]"
class$="single-column settings-box-text
[[getPassphraseHintLines_(syncPrefs.encryptAllData)]]
list-item">
$i18n{encryptionOptionsTitle}
<div class="secondary">
$i18n{syncDataEncryptedText}
<div hidden="[[!syncPrefs.encryptAllData]]">
<iron-icon icon="cr:info-outline"
class="passphrase-reset-icon">
</iron-icon>
$i18nRaw{passphraseResetHintEncryption}
</div>
</div>
</div>
</div>
<div id="encryptionRadioGroupContainer" class="list-frame"
hidden="[[syncPrefs.passphraseRequired]]">
<cr-radio-group
id="encryptionRadioGroup"
selected="[[selectedEncryptionRadio_(syncPrefs)]]"
on-selected-changed="onEncryptionRadioSelectionChanged_"
disabled$="[[disableEncryptionOptions_]]">
<cr-radio-button name="encrypt-with-google" class="list-item"
aria-label="$i18n{encryptWithGoogleCredentialsLabel}"
disabled$="[[disableEncryptionOptions_]]">
$i18n{encryptWithGoogleCredentialsLabel}
</cr-radio-button>
<cr-radio-button name="encrypt-with-passphrase" class="list-item"
disabled$="[[disableEncryptionOptions_]]">
<span hidden="[[!syncPrefs.fullEncryptionBody]]">
[[syncPrefs.fullEncryptionBody]]
</span>
<span on-click="onLearnMoreTap_"
hidden="[[syncPrefs.fullEncryptionBody]]">
$i18nRaw{encryptWithSyncPassphraseLabel}
</span>
</cr-radio-button>
</cr-radio-group>
</div>
<settings-sync-encryption-options
sync-status="[[syncStatus]]" sync-prefs="{{syncPrefs}}"
on-passphrase-changed="onPassphraseChanged_">
</settings-sync-encryption-options>
</template>
<template is="dom-if" if="[[creatingNewPassphrase_]]">
<div class="list-frame">
<div id="create-password-box"
on-keypress="onSaveNewPassphraseTap_">
<div class="list-item">
<span>$i18nRaw{passphraseExplanationText}</span>
<template is="dom-if" if="[[syncSetupFriendlySettings_]]">
<cr-expand-button id="encryptionDescription"
hidden="[[syncPrefs.passphraseRequired]]"
expanded="{{encryptionExpanded_}}"
class$="list-item
[[getPassphraseHintLines_(syncPrefs.encryptAllData)]]">
$i18n{encryptionOptionsTitle}
<div class="secondary">
$i18n{syncDataEncryptedText}
<div on-click="onResetSyncClick_"
hidden="[[!syncPrefs.encryptAllData]]">
<iron-icon icon="cr:info-outline"
class="passphrase-reset-icon">
</iron-icon>
$i18nRaw{passphraseResetHintEncryption}
</div>
<cr-input id="passphraseInput" type="password"
value="{{passphrase_}}"
placeholder="$i18n{passphrasePlaceholder}"
error-message="$i18n{emptyPassphraseError}">
</cr-input>
<cr-input id="passphraseConfirmationInput" type="password"
value="{{confirmation_}}"
placeholder="$i18n{passphraseConfirmationPlaceholder}"
error-message="$i18n{mismatchedPassphraseError}">
</cr-input>
<cr-button id="saveNewPassphrase"
on-click="onSaveNewPassphraseTap_" class="action-button"
disabled="[[!isSaveNewPassphraseEnabled_(passphrase_,
confirmation_)]]">
$i18n{save}
</cr-button>
</div>
</div>
</cr-expand-button>
<iron-collapse id="encryptionCollapse"
opened="[[encryptionExpanded_]]">
<settings-sync-encryption-options
sync-status="[[syncStatus]]" sync-prefs="{{syncPrefs}}"
on-passphrase-changed="onPassphraseChanged_">
</settings-sync-encryption-options>
</iron-collapse>
</template>
</div>
......
......@@ -4,16 +4,6 @@
(function() {
/**
* Names of the radio buttons which allow the user to choose their encryption
* mechanism.
* @enum {string}
*/
const RadioButtonNames = {
ENCRYPT_WITH_GOOGLE: 'encrypt-with-google',
ENCRYPT_WITH_PASSPHRASE: 'encrypt-with-passphrase',
};
/**
* All possible states for the sWAA bit.
* @enum {string}
......@@ -85,33 +75,11 @@ Polymer({
type: Object,
},
/**
* Whether the "create passphrase" inputs should be shown. These inputs
* give the user the opportunity to use a custom passphrase instead of
* authenticating with their Google credentials.
* @private
*/
creatingNewPassphrase_: {
/** @private */
encryptionExpanded_: {
type: Boolean,
value: false,
},
/**
* The passphrase input field value.
* @private
*/
passphrase_: {
type: String,
value: '',
},
/**
* The passphrase confirmation input field value.
* @private
*/
confirmation_: {
type: String,
value: '',
computed: 'computeEncryptionExpanded_(syncPrefs.encryptAllData)',
},
/**
......@@ -153,12 +121,6 @@ Polymer({
value: false,
},
disableEncryptionOptions_: {
type: Boolean,
computed: 'computeDisableEncryptionOptions_(' +
'syncPrefs, syncStatus)',
},
/**
* If sync page friendly settings is enabled.
* @private
......@@ -592,15 +554,6 @@ Polymer({
this.syncPrefs = syncPrefs;
this.pageStatus_ = settings.PageStatus.CONFIGURE;
// Hide the new passphrase box if (a) full data encryption is enabled,
// (b) encrypting all data is not allowed (so far, only applies to
// supervised accounts), or (c) the user is a supervised account.
if (this.syncPrefs.encryptAllData ||
!this.syncPrefs.encryptAllDataAllowed ||
(this.syncStatus && this.syncStatus.supervisedUser)) {
this.creatingNewPassphrase_ = false;
}
if (this.sWAA_ === sWAAState.FAILED) {
this.fetchSWAA_();
}
......@@ -612,43 +565,24 @@ Polymer({
},
/**
* @param {string} passphrase The passphrase input field value
* @param {string} confirmation The passphrase confirmation input field value.
* @return {boolean} Whether the passphrase save button should be enabled.
* Whether the encryption dropdown should be expanded by default.
* @return {boolean}
* @private
*/
isSaveNewPassphraseEnabled_(passphrase, confirmation) {
return passphrase !== '' && confirmation !== '';
computeEncryptionExpanded_() {
return !!this.syncPrefs && this.syncPrefs.encryptAllData;
},
/**
* Sends the newly created custom sync passphrase to the browser.
* @param {!Event} event
* @private
* @param {!Event} e
*/
onSaveNewPassphraseTap_(e) {
assert(this.creatingNewPassphrase_);
// Ignore events on irrelevant elements or with irrelevant keys.
if (e.target.tagName != 'CR-BUTTON' && e.target.tagName != 'CR-INPUT') {
return;
}
if (e.type == 'keypress' && e.key != 'Enter') {
return;
}
// If a new password has been entered but it is invalid, do not send the
// sync state to the API.
if (!this.validateCreatedPassphrases_()) {
return;
onResetSyncClick_(event) {
if (event.target.tagName == 'A') {
// Stop the propagation of events as the |cr-expand-button|
// prevents the default which will prevent the navigation to the link.
event.stopPropagation();
}
this.syncPrefs.encryptAllData = true;
this.syncPrefs.setNewPassphrase = true;
this.syncPrefs.passphrase = this.passphrase_;
this.browserProxy_.setSyncEncryption(this.syncPrefs)
.then(this.handlePageStatusChanged_.bind(this));
},
/**
......@@ -661,8 +595,6 @@ Polymer({
return;
}
assert(!this.creatingNewPassphrase_);
this.syncPrefs.setNewPassphrase = false;
this.syncPrefs.passphrase = this.existingPassphrase_;
......@@ -672,6 +604,15 @@ Polymer({
.then(this.handlePageStatusChanged_.bind(this));
},
/**
* @private
* @param {!CustomEvent<!settings.PageStatus>} e
*/
onPassphraseChanged_(e) {
this.handlePageStatusChanged_(
/** @type {!settings.PageStatus} */ (e.detail));
},
/**
* Called when the page status updates.
* @param {!settings.PageStatus} pageStatus
......@@ -705,44 +646,6 @@ Polymer({
assertNotReached();
},
/**
* Called when the encryption
* @param {!Event} event
* @private
*/
onEncryptionRadioSelectionChanged_(event) {
this.creatingNewPassphrase_ =
event.detail.value == RadioButtonNames.ENCRYPT_WITH_PASSPHRASE;
},
/**
* Computed binding returning the selected encryption radio button.
* @private
*/
selectedEncryptionRadio_() {
return this.syncPrefs.encryptAllData || this.creatingNewPassphrase_ ?
RadioButtonNames.ENCRYPT_WITH_PASSPHRASE :
RadioButtonNames.ENCRYPT_WITH_GOOGLE;
},
/**
* Checks the supplied passphrases to ensure that they are not empty and that
* they match each other. Additionally, displays error UI if they are invalid.
* @return {boolean} Whether the check was successful (i.e., that the
* passphrases were valid).
* @private
*/
validateCreatedPassphrases_() {
const emptyPassphrase = !this.passphrase_;
const mismatchedPassphrase = this.passphrase_ != this.confirmation_;
this.$$('#passphraseInput').invalid = emptyPassphrase;
this.$$('#passphraseConfirmationInput').invalid =
!emptyPassphrase && mismatchedPassphrase;
return !emptyPassphrase && !mismatchedPassphrase;
},
/**
* @param {!Event} event
* @private
......@@ -787,27 +690,6 @@ Polymer({
return this.syncPrefs !== undefined && !!this.syncPrefs.passphraseRequired;
},
/**
* Whether we should disable the radio buttons that allow choosing the
* encryption options for Sync.
* We disable the buttons if:
* (a) full data encryption is enabled, or,
* (b) full data encryption is not allowed (so far, only applies to
* supervised accounts), or,
* (c) current encryption keys are missing, or,
* (d) the user is a supervised account.
* @return {boolean}
* @private
*/
computeDisableEncryptionOptions_() {
return !!(
(this.syncPrefs &&
(this.syncPrefs.encryptAllData ||
!this.syncPrefs.encryptAllDataAllowed ||
this.syncPrefs.trustedVaultKeysRequired)) ||
(this.syncStatus && this.syncStatus.supervisedUser));
},
/** @private */
onSyncAdvancedTap_() {
const router = settings.Router.getInstance();
......
......@@ -1039,6 +1039,12 @@
file="people_page/sync_controls.html"
type="chrome_html"
preprocess="true" />
<structure name="IDR_SETTINGS_SYNC_ENCRYPTION_OPTIONS_JS"
file="people_page/sync_encryption_options.js"
type="chrome_html" />
<structure name="IDR_SETTINGS_SYNC_ENCRYPTION_OPTIONS_HTML"
file="people_page/sync_encryption_options.html"
type="chrome_html" />
<structure name="IDR_SETTINGS_SYNC_PAGE_JS"
file="people_page/sync_page.js"
type="chrome_html"
......
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