blob: b83f70d42c1466c969902238b6ab1bebe61ef531 [file] [log] [blame]
// 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
* 'settings-cookies-page' is the settings page containing cookies
* settings.
*/
import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js';
import 'chrome://resources/cr_elements/cr_link_row/cr_link_row.js';
import 'chrome://resources/cr_elements/cr_radio_group/cr_radio_group.m.js';
import '../controls/settings_toggle_button.js';
import '../icons.js';
import '../prefs/prefs.js';
import '../settings_shared_css.js';
import '../site_settings/site_list.js';
import './collapse_radio_button.js';
import './do_not_track_toggle.js';
import {assert} from 'chrome://resources/js/assert.m.js';
import {focusWithoutInk} from 'chrome://resources/js/cr/ui/focus_without_ink.m.js';
import {WebUIListenerBehavior, WebUIListenerBehaviorInterface} from 'chrome://resources/js/web_ui_listener_behavior.m.js';
import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {loadTimeData} from '../i18n_setup.js';
import {MetricsBrowserProxy, MetricsBrowserProxyImpl, PrivacyElementInteractions} from '../metrics_browser_proxy.js';
import {PrefsBehavior, PrefsBehaviorInterface} from '../prefs/prefs_behavior.js';
import {routes} from '../route.js';
import {Route, RouteObserverMixin, RouteObserverMixinInterface, Router} from '../router.js';
import {ContentSetting, ContentSettingsTypes} from '../site_settings/constants.js';
/**
* The primary cookie setting associated with each radio button. Must be kept in
* sync with the C++ enum of the same name in
* chrome/browser/content_settings/generated_cookie_prefs.h
* @enum {number}
*/
const CookiePrimarySetting = {
ALLOW_ALL: 0,
BLOCK_THIRD_PARTY_INCOGNITO: 1,
BLOCK_THIRD_PARTY: 2,
BLOCK_ALL: 3,
};
/**
* Must be kept in sync with the C++ enum of the same name (see
* chrome/browser/net/prediction_options.h).
* @enum {number}
*/
const NetworkPredictionOptions = {
ALWAYS: 0,
WIFI_ONLY: 1,
NEVER: 2,
DEFAULT: 1,
};
/**
* @constructor
* @extends {PolymerElement}
* @implements {PrefsBehaviorInterface}
* @implements {RouteObserverMixinInterface}
* @implements {WebUIListenerBehaviorInterface}
*/
const SettingsCookiesPageElementBase = mixinBehaviors(
[PrefsBehavior, WebUIListenerBehavior], RouteObserverMixin(PolymerElement));
/** @polymer */
export class SettingsCookiesPageElement extends SettingsCookiesPageElementBase {
static get is() {
return 'settings-cookies-page';
}
static get template() {
return html`{__html_template__}`;
}
static get properties() {
return {
/**
* Preferences state.
*/
prefs: {
type: Object,
notify: true,
},
/**
* Current search term.
*/
searchTerm: {
type: String,
notify: true,
value: '',
},
/**
* Primary cookie control states for use in bindings.
* @private
*/
cookiePrimarySettingEnum_: {
type: Object,
value: CookiePrimarySetting,
},
/** @private */
enableContentSettingsRedesign_: {
type: Boolean,
value() {
return loadTimeData.getBoolean('enableContentSettingsRedesign');
}
},
/**
* Used for HTML bindings. This is defined as a property rather than
* within the ready callback, because the value needs to be available
* before local DOM initialization - otherwise, the toggle has unexpected
* behavior.
* @private {!NetworkPredictionOptions}
*/
networkPredictionUncheckedValue_: {
type: Number,
value: NetworkPredictionOptions.NEVER,
},
/** @private */
contentSetting_: {
type: Object,
value: ContentSetting,
},
/**
* @private {!ContentSettingsTypes}
*/
cookiesContentSettingType_: {
type: String,
value: ContentSettingsTypes.COOKIES,
},
/** @private */
exceptionListsReadOnly_: {
type: Boolean,
value: false,
},
/** @private {!chrome.settingsPrivate.PrefObject} */
blockAllPref_: {
type: Object,
value() {
return /** @type {chrome.settingsPrivate.PrefObject} */ ({});
},
},
/** @type {!Map<string, (string|Function)>} */
focusConfig: {
type: Object,
observer: 'focusConfigChanged_',
},
};
}
static get observers() {
return [`onGeneratedPrefsUpdated_(prefs.generated.cookie_session_only,
prefs.generated.cookie_primary_setting)`];
}
constructor() {
super();
/** @type {!MetricsBrowserProxy} */
this.metricsBrowserProxy_ = MetricsBrowserProxyImpl.getInstance();
}
/*
* @param {!Map<string, string>} newConfig
* @param {?Map<string, string>} oldConfig
* @private
*/
focusConfigChanged_(newConfig, oldConfig) {
assert(!oldConfig);
assert(routes.SITE_SETTINGS_SITE_DATA);
this.focusConfig.set(routes.SITE_SETTINGS_SITE_DATA.path, () => {
focusWithoutInk(
assert(this.shadowRoot.querySelector('#site-data-trigger')));
});
}
/** @override */
currentRouteChanged(route) {
if (route !== routes.COOKIES) {
this.$.toast.hide();
}
}
/** @private */
onSiteDataClick_() {
Router.getInstance().navigateTo(routes.SITE_SETTINGS_SITE_DATA);
}
/** @private */
onGeneratedPrefsUpdated_() {
const sessionOnlyPref = this.getPref('generated.cookie_session_only');
// If the clear on exit toggle is managed this implies a content setting
// policy is present and the exception lists should be disabled.
this.exceptionListsReadOnly_ = sessionOnlyPref.enforcement ===
chrome.settingsPrivate.Enforcement.ENFORCED;
// It is not currently possible to represent multiple management sources
// for a single a preference. In all management scenarios, the blockAll
// setting shares the same controlledBy as the cookie_session_only pref.
// To support this, the controlledBy fields for the |cookie_primary_setting|
// pref provided to the blockAll control are overwritten with values from
// the session_only preference.
this.set(
'blockAllPref_',
Object.assign(this.getPref('generated.cookie_primary_setting'), {
controlledBy: sessionOnlyPref.controlledBy,
controlledByName: sessionOnlyPref.controlledByName
}));
}
/**
* Record interaction metrics for the primary cookie radio setting.
* @private
*/
onCookiePrimarySettingChanged_() {
const selection = Number(this.$.primarySettingGroup.selected);
if (selection === CookiePrimarySetting.ALLOW_ALL) {
this.metricsBrowserProxy_.recordSettingsPageHistogram(
PrivacyElementInteractions.COOKIES_ALL);
} else if (selection === CookiePrimarySetting.BLOCK_THIRD_PARTY_INCOGNITO) {
this.metricsBrowserProxy_.recordSettingsPageHistogram(
PrivacyElementInteractions.COOKIES_INCOGNITO);
} else if (selection === CookiePrimarySetting.BLOCK_THIRD_PARTY) {
this.metricsBrowserProxy_.recordSettingsPageHistogram(
PrivacyElementInteractions.COOKIES_THIRD);
} else { // CookiePrimarySetting.BLOCK_ALL
this.metricsBrowserProxy_.recordSettingsPageHistogram(
PrivacyElementInteractions.COOKIES_BLOCK);
}
// If this change resulted in the user now blocking 3P cookies where they
// previously were not, and privacy sandbox APIs are enabled, the privacy
// sandbox toast should be shown.
const currentCookieSetting =
this.getPref('generated.cookie_primary_setting').value;
if (loadTimeData.getBoolean('privacySandboxSettingsEnabled') &&
this.getPref('privacy_sandbox.apis_enabled').value &&
(currentCookieSetting === CookiePrimarySetting.ALLOW_ALL ||
currentCookieSetting ===
CookiePrimarySetting.BLOCK_THIRD_PARTY_INCOGNITO) &&
(selection === CookiePrimarySetting.BLOCK_THIRD_PARTY ||
selection === CookiePrimarySetting.BLOCK_ALL)) {
this.$.toast.show();
this.metricsBrowserProxy_.recordAction(
'Settings.PrivacySandbox.Block3PCookies');
} else if (
selection === CookiePrimarySetting.ALLOW_ALL ||
selection === CookiePrimarySetting.BLOCK_THIRD_PARTY_INCOGNITO) {
this.$.toast.hide();
}
this.$.primarySettingGroup.sendPrefChange();
}
/** @private */
onClearOnExitChange_() {
this.metricsBrowserProxy_.recordSettingsPageHistogram(
PrivacyElementInteractions.COOKIES_SESSION);
}
/**
* Records changes made to the network prediction setting for logging, the
* logic of actually changing the setting is taken care of by the
* net.network_prediction_options pref.
* @private
*/
onNetworkPredictionChange_() {
this.metricsBrowserProxy_.recordSettingsPageHistogram(
PrivacyElementInteractions.NETWORK_PREDICTION);
}
/** @private */
onPrivacySandboxClick_() {
this.metricsBrowserProxy_.recordAction(
'Settings.PrivacySandbox.OpenedFromCookiesPageToast');
this.$.toast.hide();
// TODO(crbug/1159942): Replace this with an ordinary OpenWindowProxy call.
this.shadowRoot.getElementById('privacySandboxLink').click();
}
}
customElements.define(
SettingsCookiesPageElement.is, SettingsCookiesPageElement);