[CrOS Bluetooth] Sanitize Bluetooth device names
This CL updates getDeviceName for in bluetooth_utils.ts and marks it as unsafe. This is because we allow users to enter any string as the device name. We make sure to use loadTimeData.getStringF when displaying the device name in HTML so the HTML is not rendered. Fixed: b/298724102 Test: Deployed to DUT, added test and ran CQ Change-Id: Icddf7ad76fff13bcf4511f118a6500b0009e275f Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5238635 Commit-Queue: Theo Johnson-kanu <tjohnsonkanu@google.com> Reviewed-by: Chad Duffin <chadduffin@chromium.org> Cr-Commit-Position: refs/heads/main@{#1257566}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
e027c63ebf
commit
473d45cf37
ash/webui/common/resources/bluetooth
chrome
browser
resources
ash
settings
os_bluetooth_page
os_bluetooth_change_device_name_dialog.tsos_bluetooth_device_detail_subpage.htmlos_bluetooth_device_detail_subpage.tsos_bluetooth_forget_device_dialog.tsos_bluetooth_summary.tsos_paired_bluetooth_list_item.htmlos_paired_bluetooth_list_item.tsos_saved_devices_list_item.htmlos_saved_devices_list_item.ts
os_settings_menu
test
data
webui
settings
@ -7,16 +7,20 @@ import {BluetoothDeviceProperties, PairedBluetoothDeviceProperties} from 'chrome
|
||||
|
||||
import {BatteryType} from './bluetooth_types.js';
|
||||
|
||||
export function getDeviceName(device: PairedBluetoothDeviceProperties | null): string {
|
||||
if (!device) {
|
||||
|
||||
/**
|
||||
* WARNING: The returned string may contain malicious HTML and should not be
|
||||
* used for Polymer bindings in CSS code. For additional information see
|
||||
* b/298724102.
|
||||
*/
|
||||
export function getDeviceNameUnsafe(device: PairedBluetoothDeviceProperties|
|
||||
null): string {
|
||||
if (!device || (!device.nickname && !device.deviceProperties?.publicName)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (device.nickname) {
|
||||
return device.nickname;
|
||||
}
|
||||
|
||||
return mojoString16ToString(device.deviceProperties.publicName);
|
||||
return device.nickname ||
|
||||
mojoString16ToString(device.deviceProperties.publicName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
15
chrome/browser/resources/ash/settings/os_bluetooth_page/os_bluetooth_change_device_name_dialog.ts
15
chrome/browser/resources/ash/settings/os_bluetooth_page/os_bluetooth_change_device_name_dialog.ts
@ -11,7 +11,7 @@ import '../settings_shared.css.js';
|
||||
import 'chrome://resources/ash/common/cr_elements/cr_input/cr_input.js';
|
||||
import 'chrome://resources/ash/common/cr_elements/cr_dialog/cr_dialog.js';
|
||||
|
||||
import {getDeviceName} from 'chrome://resources/ash/common/bluetooth/bluetooth_utils.js';
|
||||
import {getDeviceNameUnsafe} from 'chrome://resources/ash/common/bluetooth/bluetooth_utils.js';
|
||||
import {getBluetoothConfig} from 'chrome://resources/ash/common/bluetooth/cros_bluetooth_config.js';
|
||||
import {CrDialogElement} from 'chrome://resources/ash/common/cr_elements/cr_dialog/cr_dialog.js';
|
||||
import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js';
|
||||
@ -52,6 +52,11 @@ export class SettingsBluetoothChangeDeviceNameDialogElement extends
|
||||
value: MAX_INPUT_LENGTH,
|
||||
},
|
||||
|
||||
/**
|
||||
* WARNING: This string may contain malicious HTML and should not be used
|
||||
* for Polymer bindings in CSS code. For additional information see
|
||||
* b/298724102.
|
||||
*/
|
||||
deviceName_: {
|
||||
type: String,
|
||||
value: '',
|
||||
@ -71,7 +76,7 @@ export class SettingsBluetoothChangeDeviceNameDialogElement extends
|
||||
private isInputInvalid_: boolean;
|
||||
|
||||
private onDeviceChanged_(): void {
|
||||
this.deviceName_ = getDeviceName(this.device);
|
||||
this.deviceName_ = getDeviceNameUnsafe(this.device);
|
||||
}
|
||||
|
||||
private onCancelClick_(): void {
|
||||
@ -118,7 +123,7 @@ export class SettingsBluetoothChangeDeviceNameDialogElement extends
|
||||
}
|
||||
|
||||
private isDoneDisabled_(): boolean {
|
||||
if (this.deviceName_ === getDeviceName(this.device)) {
|
||||
if (this.deviceName_ === getDeviceNameUnsafe(this.device)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -128,6 +133,10 @@ export class SettingsBluetoothChangeDeviceNameDialogElement extends
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
getNameForTest(): string|null {
|
||||
return getDeviceNameUnsafe(this.device);
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
|
@ -104,7 +104,7 @@
|
||||
aria-hidden="true">
|
||||
$i18n{bluetoothDeviceDetailName}
|
||||
<div class="secondary" id="bluetoothDeviceNameLabel">
|
||||
[[getDeviceName_(device_.*)]]
|
||||
[[getDeviceNameUnsafe_(device_.*)]]
|
||||
</div>
|
||||
</div>
|
||||
<cr-button id="changeNameBtn"
|
||||
|
@ -17,7 +17,7 @@ import 'chrome://resources/ash/common/bluetooth/bluetooth_device_battery_info.js
|
||||
|
||||
import {BluetoothUiSurface, recordBluetoothUiSurfaceMetrics} from 'chrome://resources/ash/common/bluetooth/bluetooth_metrics_utils.js';
|
||||
import {BatteryType} from 'chrome://resources/ash/common/bluetooth/bluetooth_types.js';
|
||||
import {getBatteryPercentage, getDeviceName, hasAnyDetailedBatteryInfo, hasDefaultImage, hasTrueWirelessImages} from 'chrome://resources/ash/common/bluetooth/bluetooth_utils.js';
|
||||
import {getBatteryPercentage, getDeviceNameUnsafe, hasAnyDetailedBatteryInfo, hasDefaultImage, hasTrueWirelessImages} from 'chrome://resources/ash/common/bluetooth/bluetooth_utils.js';
|
||||
import {getBluetoothConfig} from 'chrome://resources/ash/common/bluetooth/cros_bluetooth_config.js';
|
||||
import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js';
|
||||
import {WebUiListenerMixin} from 'chrome://resources/ash/common/cr_elements/web_ui_listener_mixin.js';
|
||||
@ -211,11 +211,8 @@ export class SettingsBluetoothDeviceDetailSubpageElement extends
|
||||
this.i18n('bluetoothDeviceDetailDisconnected');
|
||||
}
|
||||
|
||||
private getDeviceName_(): string {
|
||||
if (!this.device_) {
|
||||
return '';
|
||||
}
|
||||
return getDeviceName(this.device_);
|
||||
private getDeviceNameUnsafe_(): string {
|
||||
return getDeviceNameUnsafe(this.device_);
|
||||
}
|
||||
|
||||
private shouldShowConnectDisconnectBtn_(): boolean {
|
||||
@ -235,7 +232,7 @@ export class SettingsBluetoothDeviceDetailSubpageElement extends
|
||||
return;
|
||||
}
|
||||
(this.parentNode as OsSettingsSubpageElement).pageTitle =
|
||||
getDeviceName(this.device_);
|
||||
getDeviceNameUnsafe(this.device_);
|
||||
|
||||
// Special case a where user is still on detail page and has
|
||||
// tried to connect to device but failed. The current |pageState_|
|
||||
@ -299,9 +296,9 @@ export class SettingsBluetoothDeviceDetailSubpageElement extends
|
||||
return '';
|
||||
}
|
||||
|
||||
return this.i18n(
|
||||
return loadTimeData.getStringF(
|
||||
'bluetoothDeviceDetailChangeDeviceNameBtnA11yLabel',
|
||||
this.getDeviceName_());
|
||||
getDeviceNameUnsafe(this.device_));
|
||||
}
|
||||
|
||||
private getMultipleBatteryInfoA11yLabel_(): string {
|
||||
@ -363,20 +360,22 @@ export class SettingsBluetoothDeviceDetailSubpageElement extends
|
||||
|
||||
switch (this.pageState_) {
|
||||
case PageState.CONNECTING:
|
||||
return this.i18n(
|
||||
'bluetoothDeviceDetailConnectingA11yLabel', this.getDeviceName_());
|
||||
return loadTimeData.getStringF(
|
||||
'bluetoothDeviceDetailConnectingA11yLabel',
|
||||
getDeviceNameUnsafe(this.device_));
|
||||
case PageState.CONNECTED:
|
||||
return this.i18n(
|
||||
'bluetoothDeviceDetailConnectedA11yLabel', this.getDeviceName_());
|
||||
return loadTimeData.getStringF(
|
||||
'bluetoothDeviceDetailConnectedA11yLabel',
|
||||
getDeviceNameUnsafe(this.device_));
|
||||
case PageState.CONNECTION_FAILED:
|
||||
return this.i18n(
|
||||
return loadTimeData.getStringF(
|
||||
'bluetoothDeviceDetailConnectionFailureA11yLabel',
|
||||
this.getDeviceName_());
|
||||
getDeviceNameUnsafe(this.device_));
|
||||
case PageState.DISCONNECTED:
|
||||
case PageState.DISCONNECTING:
|
||||
return this.i18n(
|
||||
return loadTimeData.getStringF(
|
||||
'bluetoothDeviceDetailDisconnectedA11yLabel',
|
||||
this.getDeviceName_());
|
||||
getDeviceNameUnsafe(this.device_));
|
||||
default:
|
||||
assertNotReached();
|
||||
}
|
||||
@ -525,8 +524,9 @@ export class SettingsBluetoothDeviceDetailSubpageElement extends
|
||||
}
|
||||
|
||||
private getForgetA11yLabel_(): string {
|
||||
return this.i18n(
|
||||
'bluetoothDeviceDetailForgetA11yLabel', this.getDeviceName_());
|
||||
return loadTimeData.getStringF(
|
||||
'bluetoothDeviceDetailForgetA11yLabel',
|
||||
getDeviceNameUnsafe(this.device_));
|
||||
}
|
||||
|
||||
private onForgetButtonClicked_(): void {
|
||||
|
@ -10,7 +10,7 @@ import '../settings_shared.css.js';
|
||||
import 'chrome://resources/ash/common/cr_elements/cr_input/cr_input.js';
|
||||
import 'chrome://resources/ash/common/cr_elements/cr_dialog/cr_dialog.js';
|
||||
|
||||
import {getDeviceName} from 'chrome://resources/ash/common/bluetooth/bluetooth_utils.js';
|
||||
import {getDeviceNameUnsafe} from 'chrome://resources/ash/common/bluetooth/bluetooth_utils.js';
|
||||
import {CrDialogElement} from 'chrome://resources/ash/common/cr_elements/cr_dialog/cr_dialog.js';
|
||||
import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js';
|
||||
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
|
||||
@ -45,15 +45,11 @@ class SettingsBluetoothForgetDeviceDialogElement extends
|
||||
private device_: PairedBluetoothDeviceProperties;
|
||||
|
||||
private getForgetDeviceDialogBodyText_(): string {
|
||||
return this.i18n(
|
||||
'bluetoothDevicesDialogLabel', this.getDeviceName_(),
|
||||
return loadTimeData.getStringF(
|
||||
'bluetoothDevicesDialogLabel', getDeviceNameUnsafe(this.device_),
|
||||
loadTimeData.getString('primaryUserEmail'));
|
||||
}
|
||||
|
||||
private getDeviceName_(): string {
|
||||
return getDeviceName(this.device_);
|
||||
}
|
||||
|
||||
private onForgetClick_(event: Event): void {
|
||||
const fireEvent = new CustomEvent(
|
||||
'forget-bluetooth-device', {bubbles: true, composed: true});
|
||||
|
@ -12,7 +12,7 @@ import '../settings_shared.css.js';
|
||||
import 'chrome://resources/ash/common/cr_elements/cr_icon_button/cr_icon_button.js';
|
||||
import 'chrome://resources/ash/common/cr_elements/icons.html.js';
|
||||
|
||||
import {getDeviceName} from 'chrome://resources/ash/common/bluetooth/bluetooth_utils.js';
|
||||
import {getDeviceNameUnsafe} from 'chrome://resources/ash/common/bluetooth/bluetooth_utils.js';
|
||||
import {getBluetoothConfig} from 'chrome://resources/ash/common/bluetooth/cros_bluetooth_config.js';
|
||||
import {getInstance as getAnnouncerInstance} from 'chrome://resources/ash/common/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js';
|
||||
import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js';
|
||||
@ -175,31 +175,32 @@ export class SettingsBluetoothSummaryElement extends
|
||||
}
|
||||
|
||||
const isA11yLabel = labelType === LabelType.A11Y;
|
||||
const firstConnectedDeviceName = getDeviceName(connectedDevices[0]);
|
||||
const firstConnectedDeviceName = getDeviceNameUnsafe(connectedDevices[0]);
|
||||
|
||||
if (connectedDevices.length === 1) {
|
||||
return isA11yLabel ? this.i18n(
|
||||
return isA11yLabel ? loadTimeData.getStringF(
|
||||
'bluetoothSummaryPageConnectedA11yOneDevice',
|
||||
firstConnectedDeviceName) :
|
||||
firstConnectedDeviceName;
|
||||
}
|
||||
|
||||
if (connectedDevices.length === 2) {
|
||||
const secondConnectedDeviceName = getDeviceName(connectedDevices[1]);
|
||||
const secondConnectedDeviceName =
|
||||
getDeviceNameUnsafe(connectedDevices[1]);
|
||||
return isA11yLabel ?
|
||||
this.i18n(
|
||||
loadTimeData.getStringF(
|
||||
'bluetoothSummaryPageConnectedA11yTwoDevices',
|
||||
firstConnectedDeviceName, secondConnectedDeviceName) :
|
||||
this.i18n(
|
||||
loadTimeData.getStringF(
|
||||
'bluetoothSummaryPageTwoDevicesDescription',
|
||||
firstConnectedDeviceName, secondConnectedDeviceName);
|
||||
}
|
||||
|
||||
return isA11yLabel ?
|
||||
this.i18n(
|
||||
loadTimeData.getStringF(
|
||||
'bluetoothSummaryPageConnectedA11yTwoOrMoreDevices',
|
||||
firstConnectedDeviceName, connectedDevices.length - 1) :
|
||||
this.i18n(
|
||||
loadTimeData.getStringF(
|
||||
'bluetoothSummaryPageTwoOrMoreDevicesDescription',
|
||||
firstConnectedDeviceName, connectedDevices.length - 1);
|
||||
}
|
||||
|
@ -14,7 +14,7 @@
|
||||
on-click="onSelected_">
|
||||
<bluetooth-icon device="[[device.deviceProperties]]"></bluetooth-icon>
|
||||
<div class="middle" aria-hidden="true">
|
||||
<div id="deviceName">[[getDeviceName_(device)]]</div>
|
||||
<div id="deviceName">[[getDeviceNameUnsafe_(device)]]</div>
|
||||
<template is="dom-if"
|
||||
if="[[shouldShowBatteryInfo_(device)]]" restamp>
|
||||
<bluetooth-device-battery-info
|
||||
|
@ -16,10 +16,11 @@ import 'chrome://resources/ash/common/bluetooth/bluetooth_icon.js';
|
||||
import 'chrome://resources/ash/common/bluetooth/bluetooth_device_battery_info.js';
|
||||
|
||||
import {BatteryType} from 'chrome://resources/ash/common/bluetooth/bluetooth_types.js';
|
||||
import {getBatteryPercentage, getDeviceName, hasAnyDetailedBatteryInfo} from 'chrome://resources/ash/common/bluetooth/bluetooth_utils.js';
|
||||
import {getBatteryPercentage, getDeviceNameUnsafe, hasAnyDetailedBatteryInfo} from 'chrome://resources/ash/common/bluetooth/bluetooth_utils.js';
|
||||
import {FocusRowMixin} from 'chrome://resources/ash/common/cr_elements/focus_row_mixin.js';
|
||||
import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js';
|
||||
import {assert, assertNotReached} from 'chrome://resources/js/assert.js';
|
||||
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
|
||||
import {DeviceConnectionState, DeviceType, PairedBluetoothDeviceProperties} from 'chrome://resources/mojo/chromeos/ash/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom-webui.js';
|
||||
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
|
||||
|
||||
@ -101,8 +102,9 @@ export class SettingsPairedBluetoothListItemElement extends
|
||||
Router.getInstance().navigateTo(routes.BLUETOOTH_DEVICE_DETAIL, params);
|
||||
}
|
||||
|
||||
private getDeviceName_(device: PairedBluetoothDeviceProperties): string {
|
||||
return getDeviceName(device);
|
||||
private getDeviceNameUnsafe_(device: PairedBluetoothDeviceProperties):
|
||||
string {
|
||||
return getDeviceNameUnsafe(device);
|
||||
}
|
||||
|
||||
private shouldShowBatteryInfo_(device: PairedBluetoothDeviceProperties):
|
||||
@ -159,9 +161,9 @@ export class SettingsPairedBluetoothListItemElement extends
|
||||
private getAriaLabel_(device: PairedBluetoothDeviceProperties): string {
|
||||
// Start with the base information of the device name and location within
|
||||
// the list of devices with the same connection state.
|
||||
let a11yLabel = this.i18n(
|
||||
let a11yLabel = loadTimeData.getStringF(
|
||||
'bluetoothA11yDeviceName', this.itemIndex + 1, this.listSize,
|
||||
this.getDeviceName_(device));
|
||||
this.getDeviceNameUnsafe_(device));
|
||||
|
||||
// Include the connection status.
|
||||
a11yLabel +=
|
||||
|
@ -28,7 +28,7 @@
|
||||
</template>
|
||||
</div>
|
||||
<div class="middle" aria-hidden="true">
|
||||
<div id="deviceName">[[getDeviceName_(device)]]</div>
|
||||
<div id="deviceName">[[getDeviceNameUnsafe_(device)]]</div>
|
||||
</div>
|
||||
<div>
|
||||
<cr-icon-button class="icon-more-vert"
|
||||
|
@ -16,8 +16,8 @@ import 'chrome://resources/ash/common/cr_elements/cr_action_menu/cr_action_menu.
|
||||
import {FastPairSavedDevicesUiEvent, recordSavedDevicesUiEventMetrics} from 'chrome://resources/ash/common/bluetooth/bluetooth_metrics_utils.js';
|
||||
import {CrActionMenuElement} from 'chrome://resources/ash/common/cr_elements/cr_action_menu/cr_action_menu.js';
|
||||
import {FocusRowMixin} from 'chrome://resources/ash/common/cr_elements/focus_row_mixin.js';
|
||||
import {I18nMixin} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js';
|
||||
import {WebUiListenerMixin} from 'chrome://resources/ash/common/cr_elements/web_ui_listener_mixin.js';
|
||||
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
|
||||
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
|
||||
|
||||
import {getTemplate} from './os_saved_devices_list_item.html.js';
|
||||
@ -30,7 +30,7 @@ interface SettingsSavedDevicesListItemElement {
|
||||
}
|
||||
|
||||
const SettingsSavedDevicesListItemElementBase =
|
||||
FocusRowMixin(WebUiListenerMixin(I18nMixin(PolymerElement)));
|
||||
FocusRowMixin(WebUiListenerMixin(PolymerElement));
|
||||
|
||||
class SettingsSavedDevicesListItemElement extends
|
||||
SettingsSavedDevicesListItemElementBase {
|
||||
@ -69,7 +69,7 @@ class SettingsSavedDevicesListItemElement extends
|
||||
listSize: number;
|
||||
private shouldShowRemoveSavedDeviceDialog_: boolean;
|
||||
|
||||
private getDeviceName_(device: FastPairSavedDevice): string {
|
||||
private getDeviceNameUnsafe_(device: FastPairSavedDevice): string {
|
||||
return device.name;
|
||||
}
|
||||
|
||||
@ -95,15 +95,16 @@ class SettingsSavedDevicesListItemElement extends
|
||||
}
|
||||
|
||||
private getAriaLabel_(device: FastPairSavedDevice): string {
|
||||
const deviceName = this.getDeviceName_(device);
|
||||
return this.i18n(
|
||||
const deviceName = this.getDeviceNameUnsafe_(device);
|
||||
return loadTimeData.getStringF(
|
||||
'savedDeviceItemA11yLabel', this.itemIndex + 1, this.listSize,
|
||||
deviceName);
|
||||
}
|
||||
|
||||
private getSubpageButtonA11yLabel_(device: FastPairSavedDevice): string {
|
||||
const deviceName = this.getDeviceName_(device);
|
||||
return this.i18n('savedDeviceItemButtonA11yLabel', deviceName);
|
||||
const deviceName = this.getDeviceNameUnsafe_(device);
|
||||
return loadTimeData.getStringF(
|
||||
'savedDeviceItemButtonA11yLabel', deviceName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,13 +15,13 @@ import '../settings_shared.css.js';
|
||||
import '../os_settings_icons.html.js';
|
||||
import './menu_item.js';
|
||||
|
||||
import {getDeviceName} from 'chrome://resources/ash/common/bluetooth/bluetooth_utils.js';
|
||||
import {getDeviceNameUnsafe} from 'chrome://resources/ash/common/bluetooth/bluetooth_utils.js';
|
||||
import {getBluetoothConfig} from 'chrome://resources/ash/common/bluetooth/cros_bluetooth_config.js';
|
||||
import {I18nMixin, I18nMixinInterface} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js';
|
||||
import {WebUiListenerMixin, WebUiListenerMixinInterface} from 'chrome://resources/ash/common/cr_elements/web_ui_listener_mixin.js';
|
||||
import {MojoInterfaceProviderImpl} from 'chrome://resources/ash/common/network/mojo_interface_provider.js';
|
||||
import {NetworkListenerBehavior, NetworkListenerBehaviorInterface} from 'chrome://resources/ash/common/network/network_listener_behavior.js';
|
||||
import {OncMojo} from 'chrome://resources/ash/common/network/onc_mojo.js';
|
||||
import {I18nMixin, I18nMixinInterface} from 'chrome://resources/ash/common/cr_elements/i18n_mixin.js';
|
||||
import {WebUiListenerMixin, WebUiListenerMixinInterface} from 'chrome://resources/ash/common/cr_elements/web_ui_listener_mixin.js';
|
||||
import {BluetoothSystemProperties, BluetoothSystemState, DeviceConnectionState, PairedBluetoothDeviceProperties, SystemPropertiesObserverReceiver as BluetoothPropertiesObserverReceiver} from 'chrome://resources/mojo/chromeos/ash/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom-webui.js';
|
||||
import {CrosNetworkConfigInterface, FilterType, NO_LIMIT} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/cros_network_config.mojom-webui.js';
|
||||
import {NetworkType} from 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-webui.js';
|
||||
@ -664,7 +664,7 @@ export class OsSettingsMenuElement extends OsSettingsMenuElementBase {
|
||||
|
||||
if (connectedDevices.length === 1) {
|
||||
const device = castExists(connectedDevices[0]);
|
||||
this.bluetoothMenuItemDescription_ = getDeviceName(device);
|
||||
this.bluetoothMenuItemDescription_ = getDeviceNameUnsafe(device);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ import 'chrome://os-settings/lazy_load.js';
|
||||
|
||||
import {SettingsBluetoothChangeDeviceNameDialogElement} from 'chrome://os-settings/lazy_load.js';
|
||||
import {CrInputElement} from 'chrome://os-settings/os_settings.js';
|
||||
import {getDeviceName} from 'chrome://resources/ash/common/bluetooth/bluetooth_utils.js';
|
||||
import {getDeviceNameUnsafe} from 'chrome://resources/ash/common/bluetooth/bluetooth_utils.js';
|
||||
import {setBluetoothConfigForTesting} from 'chrome://resources/ash/common/bluetooth/cros_bluetooth_config.js';
|
||||
import {DeviceConnectionState} from 'chrome://resources/mojo/chromeos/ash/services/bluetooth_config/public/mojom/cros_bluetooth_config.mojom-webui.js';
|
||||
import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
|
||||
@ -18,6 +18,7 @@ suite('<os-settings-bluetooth-change-device-name-dialog>', () => {
|
||||
let bluetoothDeviceChangeNameDialog:
|
||||
SettingsBluetoothChangeDeviceNameDialogElement;
|
||||
let bluetoothConfig: FakeBluetoothConfig;
|
||||
const deviceId = '12//345&6789';
|
||||
|
||||
setup(() => {
|
||||
bluetoothConfig = new FakeBluetoothConfig();
|
||||
@ -61,7 +62,7 @@ suite('<os-settings-bluetooth-change-device-name-dialog>', () => {
|
||||
|
||||
test('Input is sanitized', async () => {
|
||||
const device1 = createDefaultBluetoothDevice(
|
||||
/*id=*/ '12//345&6789',
|
||||
/*id=*/ deviceId,
|
||||
/*publicName=*/ 'BeatsX',
|
||||
/*connectionState=*/
|
||||
DeviceConnectionState.kConnected,
|
||||
@ -109,8 +110,10 @@ suite('<os-settings-bluetooth-change-device-name-dialog>', () => {
|
||||
});
|
||||
|
||||
test('Device name is changed', async () => {
|
||||
const id = '12//345&6789';
|
||||
const nickname = 'Nickname';
|
||||
const initialNickname = 'device1';
|
||||
const newNickname = 'nickname';
|
||||
const htmlNickname = '<a>html</a>';
|
||||
|
||||
const getDoneBtn = () => {
|
||||
const doneButton = bluetoothDeviceChangeNameDialog.shadowRoot!
|
||||
.querySelector<HTMLButtonElement>('#done');
|
||||
@ -119,11 +122,11 @@ suite('<os-settings-bluetooth-change-device-name-dialog>', () => {
|
||||
};
|
||||
|
||||
const device = createDefaultBluetoothDevice(
|
||||
id,
|
||||
deviceId,
|
||||
/*publicName=*/ 'BeatsX',
|
||||
/*connectionState=*/
|
||||
DeviceConnectionState.kConnected,
|
||||
/*opt_nickname=*/ 'device1');
|
||||
/*opt_nickname=*/ initialNickname);
|
||||
|
||||
bluetoothDeviceChangeNameDialog.set('device', {...device});
|
||||
bluetoothConfig.appendToPairedDeviceList([device]);
|
||||
@ -132,18 +135,27 @@ suite('<os-settings-bluetooth-change-device-name-dialog>', () => {
|
||||
const input = bluetoothDeviceChangeNameDialog.shadowRoot!
|
||||
.querySelector<CrInputElement>('#changeNameInput');
|
||||
assertTrue(!!input);
|
||||
assertEquals('device1', input.value);
|
||||
assertEquals(initialNickname, input.value);
|
||||
assertTrue(getDoneBtn().disabled);
|
||||
|
||||
input.value = nickname;
|
||||
input.value = newNickname;
|
||||
await flushTasks();
|
||||
assertFalse(getDoneBtn().disabled);
|
||||
|
||||
getDoneBtn().click();
|
||||
await flushTasks();
|
||||
assertEquals(
|
||||
newNickname,
|
||||
getDeviceNameUnsafe(bluetoothConfig.getPairedDeviceById(deviceId)));
|
||||
|
||||
const newName = getDeviceName(bluetoothConfig.getPairedDeviceById(id));
|
||||
input.value = htmlNickname;
|
||||
await flushTasks();
|
||||
assertFalse(getDoneBtn().disabled);
|
||||
|
||||
assertEquals(nickname, newName);
|
||||
getDoneBtn().click();
|
||||
await flushTasks();
|
||||
assertEquals(
|
||||
htmlNickname,
|
||||
getDeviceNameUnsafe(bluetoothConfig.getPairedDeviceById(deviceId)));
|
||||
});
|
||||
});
|
||||
|
@ -195,6 +195,32 @@ suite('<os-settings-paired-bluetooth-list-item>', () => {
|
||||
getItemA11yLabel());
|
||||
});
|
||||
|
||||
test('Device name is set correctly', async () => {
|
||||
const getDeviceName = () => {
|
||||
const deviceName =
|
||||
pairedBluetoothListItem.shadowRoot!.querySelector<HTMLElement>(
|
||||
'#deviceName');
|
||||
assertTrue(!!deviceName);
|
||||
return deviceName;
|
||||
};
|
||||
|
||||
const publicName = 'BeatsX';
|
||||
const nameWithHtml = '<a>testname</a>';
|
||||
const device = createDefaultBluetoothDevice(
|
||||
/*id=*/ '123456789', /*publicName=*/ publicName,
|
||||
/*connectionState=*/
|
||||
DeviceConnectionState.kConnected);
|
||||
pairedBluetoothListItem.set('device', device);
|
||||
await flushTasks();
|
||||
assertEquals(publicName, getDeviceName().innerText);
|
||||
|
||||
device.nickname = nameWithHtml;
|
||||
pairedBluetoothListItem.set('device', {...device});
|
||||
await flushTasks();
|
||||
assertTrue(!!getDeviceName());
|
||||
assertEquals(nameWithHtml, getDeviceName().innerText);
|
||||
});
|
||||
|
||||
test('Battery percentage out of bounds', async () => {
|
||||
const device = createDefaultBluetoothDevice(
|
||||
/*id=*/ '123456789', /*publicName=*/ 'BeatsX',
|
||||
|
@ -177,4 +177,23 @@ suite('<os-settings-saved-devices-list>', () => {
|
||||
assertTrue(isVisible(
|
||||
getListItems()[1]!.shadowRoot!.querySelector('#deviceImage')));
|
||||
});
|
||||
|
||||
test('Device names are set properly', async () => {
|
||||
const getDeviceName = () => {
|
||||
return getListItems()[0]!.shadowRoot!
|
||||
.querySelector<HTMLElement>('#deviceName')!.innerText;
|
||||
};
|
||||
const deviceName = 'deviceName';
|
||||
const device = {name: deviceName, imageUrl: 'fakeUrl', accountKey: '1'};
|
||||
|
||||
savedDevicesList.set('devices', [device]);
|
||||
await flushTasks();
|
||||
assertEquals(deviceName, getDeviceName());
|
||||
|
||||
const nameWithHtml = '<a>test</a>';
|
||||
device.name = nameWithHtml;
|
||||
savedDevicesList.set('devices', [{...device}]);
|
||||
await flushTasks();
|
||||
assertEquals(nameWithHtml, getDeviceName());
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user