blob: ef407f4d08c849a57f5210f51a921237819525c5 [file] [log] [blame]
// Copyright 2015 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
* 'site-details-permission' handles showing the state of one permission, such
* as Geolocation, for a given origin.
*/
import 'chrome://resources/cr_elements/md_select_css.m.js';
import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
import '../settings_shared_css.m.js';
import '../settings_vars_css.m.js';
import {assert, assertNotReached} from 'chrome://resources/js/assert.m.js';
import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
import {WebUIListenerBehavior} from 'chrome://resources/js/web_ui_listener_behavior.m.js';
import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
import {loadTimeData} from '../i18n_setup.js';
import {routes} from '../route.js';
import {ContentSetting, ContentSettingsTypes, SiteSettingSource} from './constants.js';
import {SiteSettingsBehavior} from './site_settings_behavior.js';
import {RawSiteException} from './site_settings_prefs_browser_proxy.js';
Polymer({
is: 'site-details-permission',
_template: html`{__html_template__}`,
behaviors: [I18nBehavior, SiteSettingsBehavior, WebUIListenerBehavior],
properties: {
/**
* If this is a sound content setting, then this controls whether it
* should use "Automatic" instead of "Allow" as the default setting
* allow label.
*/
useAutomaticLabel: {type: Boolean, value: false},
/**
* The site that this widget is showing details for.
* @type {RawSiteException}
*/
site: Object,
/**
* The default setting for this permission category.
* @type {ContentSetting}
* @private
*/
defaultSetting_: String,
label: String,
icon: String,
},
observers: ['siteChanged_(site)'],
/** @override */
attached() {
this.addWebUIListener(
'contentSettingCategoryChanged',
this.onDefaultSettingChanged_.bind(this));
},
shouldHideCategory_(category) {
return !this.getCategoryList().includes(category);
},
/**
* Updates the drop-down value after |site| has changed.
* @param {!RawSiteException} site The site to display.
* @private
*/
siteChanged_(site) {
if (site.source == SiteSettingSource.DEFAULT) {
this.defaultSetting_ = site.setting;
this.$.permission.value = ContentSetting.DEFAULT;
} else {
// The default setting is unknown, so consult the C++ backend for it.
this.updateDefaultPermission_(site);
this.$.permission.value = site.setting;
}
if (this.isNonDefaultAsk_(site.setting, site.source)) {
assert(
this.$.permission.value == ContentSetting.ASK,
'\'Ask\' should only show up when it\'s currently selected.');
}
},
/**
* Updates the default permission setting for this permission category.
* @param {!RawSiteException} site The site to display.
* @private
*/
updateDefaultPermission_(site) {
this.browserProxy.getDefaultValueForContentType(this.category)
.then((defaultValue) => {
this.defaultSetting_ = defaultValue.setting;
});
},
/**
* Handles the category permission changing for this origin.
* @param {!ContentSettingsTypes} category The permission category
* that has changed default permission.
* @private
*/
onDefaultSettingChanged_(category) {
if (category == this.category) {
this.updateDefaultPermission_(this.site);
}
},
/**
* Handles the category permission changing for this origin.
* @private
*/
onPermissionSelectionChange_() {
this.browserProxy.setOriginPermissions(
this.site.origin, [this.category], this.$.permission.value);
},
/**
* Returns if we should use the custom labels for the sound type.
* @param {!ContentSettingsTypes} category The permission type.
* @return {boolean}
* @private
*/
useCustomSoundLabels_(category) {
return category == ContentSettingsTypes.SOUND &&
loadTimeData.getBoolean('enableAutoplayWhitelistContentSetting');
},
/**
* Updates the string used for this permission category's default setting.
* @param {!ContentSetting} defaultSetting Value of the default
* setting for this permission category.
* @param {!ContentSettingsTypes} category The permission type.
* @param {boolean} useAutomaticLabel Whether to use the automatic label
* if the default setting value is allow.
* @return {string}
* @private
*/
defaultSettingString_(defaultSetting, category, useAutomaticLabel) {
if (defaultSetting == undefined || category == undefined ||
useAutomaticLabel == undefined) {
return '';
}
if (defaultSetting == ContentSetting.ASK ||
defaultSetting == ContentSetting.IMPORTANT_CONTENT) {
return this.i18n('siteSettingsActionAskDefault');
} else if (defaultSetting == ContentSetting.ALLOW) {
if (this.useCustomSoundLabels_(category) && useAutomaticLabel) {
return this.i18n('siteSettingsActionAutomaticDefault');
}
return this.i18n('siteSettingsActionAllowDefault');
} else if (defaultSetting == ContentSetting.BLOCK) {
if (this.useCustomSoundLabels_(category)) {
return this.i18n('siteSettingsActionMuteDefault');
}
return this.i18n('siteSettingsActionBlockDefault');
}
assertNotReached(
`No string for ${this.category}'s default of ${defaultSetting}`);
},
/**
* Updates the string used for this permission category's block setting.
* @param {!ContentSettingsTypes} category The permission type.
* @param {string} blockString 'Block' label.
* @param {string} muteString 'Mute' label.
* @return {string}
* @private
*/
blockSettingString_(category, blockString, muteString) {
if (this.useCustomSoundLabels_(category)) {
return muteString;
}
return blockString;
},
/**
* Returns true if there's a string to display that provides more information
* about this permission's setting. Currently, this only gets called when
* |this.site| is updated.
* @param {!SiteSettingSource} source The source of the permission.
* @param {!ContentSettingsTypes} category The permission type.
* @param {!ContentSetting} setting The permission setting.
* @return {boolean} Whether the permission will have a source string to
* display.
* @private
*/
hasPermissionInfoString_(source, category, setting) {
// This method assumes that an empty string will be returned for categories
// that have no permission info string.
return this.permissionInfoString_(
source, category, setting,
// Set all permission info string arguments as null. This is OK
// because there is no need to know what the information string
// will be, just whether there is one or not.
null, null, null, null, null, null, null, null, null, null, null,
null) != '';
},
/**
* Checks if there's a additional information to display, and returns the
* class name to apply to permissions if so.
* @param {!SiteSettingSource} source The source of the permission.
* @param {!ContentSettingsTypes} category The permission type.
* @param {!ContentSetting} setting The permission setting.
* @return {string} CSS class applied when there is an additional description
* string.
* @private
*/
permissionInfoStringClass_(source, category, setting) {
return this.hasPermissionInfoString_(source, category, setting) ?
'two-line' :
'';
},
/**
* Returns true if this permission can be controlled by the user.
* @param {!SiteSettingSource} source The source of the permission.
* @return {boolean}
* @private
*/
isPermissionUserControlled_(source) {
return !(
source == SiteSettingSource.DRM_DISABLED ||
source == SiteSettingSource.POLICY ||
source == SiteSettingSource.EXTENSION ||
source == SiteSettingSource.KILL_SWITCH ||
source == SiteSettingSource.INSECURE_ORIGIN);
},
/**
* Returns true if the 'allow' option should be shown.
* @param {!ContentSettingsTypes} category The permission type.
* @return {boolean}
* @private
*/
showAllowedSetting_(category) {
return !(
category == ContentSettingsTypes.SERIAL_PORTS ||
category == ContentSettingsTypes.USB_DEVICES ||
category == ContentSettingsTypes.BLUETOOTH_SCANNING ||
category == ContentSettingsTypes.NATIVE_FILE_SYSTEM_WRITE ||
category == ContentSettingsTypes.HID_DEVICES ||
category == ContentSettingsTypes.BLUETOOTH_DEVICES);
},
/**
* Returns true if the 'ask' option should be shown.
* @param {!ContentSettingsTypes} category The permission type.
* @param {!ContentSetting} setting The setting of the permission.
* @param {!SiteSettingSource} source The source of the permission.
* @return {boolean}
* @private
*/
showAskSetting_(category, setting, source) {
// For chooser-based permissions 'ask' takes the place of 'allow'.
if (category == ContentSettingsTypes.SERIAL_PORTS ||
category == ContentSettingsTypes.USB_DEVICES ||
category == ContentSettingsTypes.HID_DEVICES ||
category == ContentSettingsTypes.BLUETOOTH_DEVICES) {
return true;
}
// For Bluetooth scanning permission and Native File System write permission
// 'ask' takes the place of 'allow'.
if (category == ContentSettingsTypes.BLUETOOTH_SCANNING ||
category == ContentSettingsTypes.NATIVE_FILE_SYSTEM_WRITE) {
return true;
}
return this.isNonDefaultAsk_(setting, source);
},
/**
* Returns true if the permission is set to a non-default 'ask'. Currently,
* this only gets called when |this.site| is updated.
* @param {!ContentSetting} setting The setting of the permission.
* @param {!SiteSettingSource} source The source of the permission.
* @private
*/
isNonDefaultAsk_(setting, source) {
if (setting != ContentSetting.ASK || source == SiteSettingSource.DEFAULT) {
return false;
}
assert(
source == SiteSettingSource.EXTENSION ||
source == SiteSettingSource.POLICY ||
source == SiteSettingSource.PREFERENCE,
'Only extensions, enterprise policy or preferences can change ' +
'the setting to ASK.');
return true;
},
/**
* Updates the information string for the current permission.
* Currently, this only gets called when |this.site| is updated.
* @param {!SiteSettingSource} source The source of the permission.
* @param {!ContentSettingsTypes} category The permission type.
* @param {!ContentSetting} setting The permission setting.
* @param {?string} adsBlacklistString The string to show if the site is
* blacklisted for showing bad ads.
* @param {?string} adsBlockString The string to show if ads are blocked, but
* the site is not blacklisted.
* @param {?string} embargoString
* @param {?string} insecureOriginString
* @param {?string} killSwitchString
* @param {?string} extensionAllowString
* @param {?string} extensionBlockString
* @param {?string} extensionAskString
* @param {?string} policyAllowString
* @param {?string} policyBlockString
* @param {?string} policyAskString
* @param {?string} drmDisabledString
* @return {?string} The permission information string to display in the HTML.
* @private
*/
permissionInfoString_(
source, category, setting, adsBlacklistString, adsBlockString,
embargoString, insecureOriginString, killSwitchString,
extensionAllowString, extensionBlockString, extensionAskString,
policyAllowString, policyBlockString, policyAskString,
drmDisabledString) {
if (source == undefined || category == undefined || setting == undefined) {
return null;
}
/** @type {Object<!ContentSetting, ?string>} */
const extensionStrings = {};
extensionStrings[ContentSetting.ALLOW] = extensionAllowString;
extensionStrings[ContentSetting.BLOCK] = extensionBlockString;
extensionStrings[ContentSetting.ASK] = extensionAskString;
/** @type {Object<!ContentSetting, ?string>} */
const policyStrings = {};
policyStrings[ContentSetting.ALLOW] = policyAllowString;
policyStrings[ContentSetting.BLOCK] = policyBlockString;
policyStrings[ContentSetting.ASK] = policyAskString;
if (source == SiteSettingSource.ADS_FILTER_BLACKLIST) {
assert(
ContentSettingsTypes.ADS == category,
'The ads filter blacklist only applies to Ads.');
return adsBlacklistString;
} else if (
category == ContentSettingsTypes.ADS &&
setting == ContentSetting.BLOCK) {
return adsBlockString;
} else if (source == SiteSettingSource.DRM_DISABLED) {
assert(
ContentSetting.BLOCK == setting,
'If DRM is disabled, Protected Content must be blocked.');
assert(
ContentSettingsTypes.PROTECTED_CONTENT == category,
'The DRM disabled source only applies to Protected Content.');
if (!drmDisabledString) {
return null;
}
return loadTimeData.sanitizeInnerHtml(loadTimeData.substituteString(
drmDisabledString,
routes.SITE_SETTINGS_PROTECTED_CONTENT.getAbsolutePath()));
} else if (source == SiteSettingSource.EMBARGO) {
assert(
ContentSetting.BLOCK == setting,
'Embargo is only used to block permissions.');
return embargoString;
} else if (source == SiteSettingSource.EXTENSION) {
return extensionStrings[setting];
} else if (source == SiteSettingSource.INSECURE_ORIGIN) {
assert(
ContentSetting.BLOCK == setting,
'Permissions can only be blocked due to insecure origins.');
return insecureOriginString;
} else if (source == SiteSettingSource.KILL_SWITCH) {
assert(
ContentSetting.BLOCK == setting,
'The permissions kill switch can only be used to block permissions.');
return killSwitchString;
} else if (source == SiteSettingSource.POLICY) {
return policyStrings[setting];
} else if (
source == SiteSettingSource.DEFAULT ||
source == SiteSettingSource.PREFERENCE) {
return '';
}
assertNotReached(`No string for ${category} setting source '${source}'`);
},
});