chromium/chrome/browser/resources/settings/privacy_page/security_page.ts

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import '/shared/settings/prefs/prefs.js';
import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js';
import 'chrome://resources/cr_elements/cr_link_row/cr_link_row.js';
import 'chrome://resources/cr_elements/cr_shared_style.css.js';
import './collapse_radio_button.js';
import '../controls/settings_radio_group.js';
import '../controls/settings_toggle_button.js';
import '../privacy_page/secure_dns.js';
import '../icons.html.js';
import '../settings_shared.css.js';
import '../simple_confirmation_dialog.js';

import {PrefsMixin} from '/shared/settings/prefs/prefs_mixin.js';
import {CrSettingsPrefs} from '/shared/settings/prefs/prefs_types.js';
import type {PrivacyPageBrowserProxy} from '/shared/settings/privacy_page/privacy_page_browser_proxy.js';
import {PrivacyPageBrowserProxyImpl} from '/shared/settings/privacy_page/privacy_page_browser_proxy.js';
import {HelpBubbleMixin} from 'chrome://resources/cr_components/help_bubble/help_bubble_mixin.js';
import {I18nMixin} from 'chrome://resources/cr_elements/i18n_mixin.js';
import {assert} from 'chrome://resources/js/assert.js';
import {EventTracker} from 'chrome://resources/js/event_tracker.js';
import {focusWithoutInk} from 'chrome://resources/js/focus_without_ink.js';
import {OpenWindowProxyImpl} from 'chrome://resources/js/open_window_proxy.js';
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';

import type {SettingsRadioGroupElement} from '../controls/settings_radio_group.js';
import type {SettingsToggleButtonElement} from '../controls/settings_toggle_button.js';
import type {FocusConfig} from '../focus_config.js';
import {HatsBrowserProxyImpl, SecurityPageInteraction} from '../hats_browser_proxy.js';
import {loadTimeData} from '../i18n_setup.js';
import type {MetricsBrowserProxy} from '../metrics_browser_proxy.js';
import {MetricsBrowserProxyImpl, PrivacyElementInteractions, SafeBrowsingInteractions} from '../metrics_browser_proxy.js';
import {routes} from '../route.js';
import type {Route} from '../router.js';
import {RouteObserverMixin, Router} from '../router.js';

import type {SettingsCollapseRadioButtonElement} from './collapse_radio_button.js';
import {getTemplate} from './security_page.html.js';

/**
 * Enumeration of all safe browsing modes. Must be kept in sync with the enum
 * of the same name located in:
 * chrome/browser/safe_browsing/generated_safe_browsing_pref.h
 */
export enum SafeBrowsingSetting {
  ENHANCED = 0,
  STANDARD = 1,
  DISABLED = 2,
}

/**
 * Enumeration of all HTTPS-First Mode setting states. Must be kept in sync with
 * the enum of the same name located in:
 * chrome/browser/ssl/https_first_mode_settings_tracker.h
 */
export enum HttpsFirstModeSetting {
  DISABLED = 0,
  // DEPRECATED: A separate Incognito setting never shipped.
  // ENABLED_INCOGNITO = 1,
  ENABLED_FULL = 2,
  ENABLED_BALANCED = 3,
}

export interface SettingsSecurityPageElement {
  $: {
    passwordsLeakToggle: SettingsToggleButtonElement,
    safeBrowsingDisabled: SettingsCollapseRadioButtonElement,
    safeBrowsingEnhanced: SettingsCollapseRadioButtonElement,
    safeBrowsingRadioGroup: SettingsRadioGroupElement,
    safeBrowsingReportingToggle: SettingsToggleButtonElement,
    safeBrowsingStandard: SettingsCollapseRadioButtonElement,
  };
}

const SettingsSecurityPageElementBase =
    HelpBubbleMixin(RouteObserverMixin(I18nMixin(PrefsMixin(PolymerElement))));

export class SettingsSecurityPageElement extends
    SettingsSecurityPageElementBase {
  static get is() {
    return 'settings-security-page';
  }

  static get template() {
    return getTemplate();
  }

  static get properties() {
    return {
      /**
       * Preferences state.
       */
      prefs: {
        type: Object,
        notify: true,
      },

      // <if expr="chrome_root_store_cert_management_ui">
      /**
       * Whether we should show the new cert management UI.
       */
      enableCertManagementUIV2_: {
        type: Boolean,
        readOnly: true,
        value: function() {
          return loadTimeData.getBoolean('enableCertManagementUIV2');
        },
      },
      // </if>

      /**
       * Whether the secure DNS setting should be displayed.
       */
      showSecureDnsSetting_: {
        type: Boolean,
        readOnly: true,
        value: function() {
          return loadTimeData.getBoolean('showSecureDnsSetting');
        },
      },

      // <if expr="is_chromeos">
      /**
       * Whether a link to secure DNS OS setting should be displayed.
       */
      showSecureDnsSettingLink_: {
        type: Boolean,
        readOnly: true,
        value: function() {
          return loadTimeData.getBoolean('showSecureDnsSettingLink');
        },
      },
      // </if>

      /**
       * Valid safe browsing states.
       */
      safeBrowsingSettingEnum_: {
        type: Object,
        value: SafeBrowsingSetting,
      },

      /**
       * Valid HTTPS-First Mode states.
       */
      httpsFirstModeSettingEnum_: {
        type: Object,
        value: HttpsFirstModeSetting,
      },

      /**
       * Setting for HTTPS-First Mode when the toggle is off.
       */
      httpsFirstModeUncheckedValues_: {
        type: Array,
        value: () => [HttpsFirstModeSetting.DISABLED],
      },

      enableHttpsFirstModeNewSettings_: {
        type: Boolean,
        readOnly: true,
        value() {
          return loadTimeData.getBoolean('enableHttpsFirstModeNewSettings');
        },
      },

      enableSecurityKeysSubpage_: {
        type: Boolean,
        readOnly: true,
        value() {
          return loadTimeData.getBoolean('enableSecurityKeysSubpage');
        },
      },

      // <if expr="is_win">
      enableSecurityKeysPhonesSubpage_: {
        type: Boolean,
        readOnly: true,
        value() {
          // The phones subpage is linked from the security keys subpage, if
          // it exists. Thus the phones subpage is only linked from this page
          // if the security keys subpage is disabled.
          return !loadTimeData.getBoolean('enableSecurityKeysSubpage');
        },
      },
      // </if>

      focusConfig: {
        type: Object,
        observer: 'focusConfigChanged_',
      },

      enableHashPrefixRealTimeLookups_: {
        type: Boolean,
        value() {
          return loadTimeData.getBoolean('enableHashPrefixRealTimeLookups');
        },
      },

      hideExtendedReportingRadioButton_: {
        type: Boolean,
        value() {
          return loadTimeData.getBoolean(
                     'extendedReportingRemovePrefDependency') &&
              loadTimeData.getBoolean('hashPrefixRealTimeLookupsSamplePing');
        },
      },

      showDisableSafebrowsingDialog_: Boolean,

      /**
       * A timestamp that records the last time the user visited this page or
       * returned to it.
       */
      lastFocusTime_: Number,

      /** The total amount of time a user spent on the page in focus. */
      totalTimeInFocus_: {
        type: Number,
        value: 0,
      },

      /** Latest user interaction type on the security page. */
      lastInteraction_: {
        type: SecurityPageInteraction,
        value: SecurityPageInteraction.NO_INTERACTION,
      },

      /** Safe browsing state when the page opened. */
      safeBrowsingStateOnOpen_: SafeBrowsingSetting,

      /** Whether the user is currently on the security page or not. */
      isRouteSecurity_: {
        type: Boolean,
        value: true,
      },
    };
  }
  // <if expr="chrome_root_store_cert_management_ui">
  private enableCertManagementUIV2_: boolean;
  // </if>
  private showSecureDnsSetting_: boolean;

  // <if expr="is_chromeos">
  private showSecureDnsSettingLink_: boolean;
  // </if>

  private enableSecurityKeysSubpage_: boolean;
  focusConfig: FocusConfig;
  private showDisableSafebrowsingDialog_: boolean;
  private enableHashPrefixRealTimeLookups_: boolean;
  private enableHttpsFirstModeNewSettings_: boolean;
  private lastFocusTime_: number|undefined;
  private totalTimeInFocus_: number;
  private lastInteraction_: SecurityPageInteraction;
  private safeBrowsingStateOnOpen_: SafeBrowsingSetting;
  private isRouteSecurity_: boolean;
  private eventTracker_: EventTracker = new EventTracker();
  private hideExtendedReportingRadioButton_: boolean;

  private browserProxy_: PrivacyPageBrowserProxy =
      PrivacyPageBrowserProxyImpl.getInstance();
  private metricsBrowserProxy_: MetricsBrowserProxy =
      MetricsBrowserProxyImpl.getInstance();

  private focusConfigChanged_(_newConfig: FocusConfig, oldConfig: FocusConfig) {
    assert(!oldConfig);
    // TODO(crbug.com/40928765): fix this for new cert management UI.
    // <if expr="use_nss_certs">
    if (routes.CERTIFICATES) {
      this.focusConfig.set(routes.CERTIFICATES.path, () => {
        const toFocus = this.shadowRoot!.querySelector<HTMLElement>(
            '#manageCertificatesLinkRow');
        assert(toFocus);
        focusWithoutInk(toFocus);
      });
    }
    // </if>

    if (routes.SECURITY_KEYS) {
      this.focusConfig.set(routes.SECURITY_KEYS.path, () => {
        const toFocus = this.shadowRoot!.querySelector<HTMLElement>(
            '#security-keys-subpage-trigger');
        assert(toFocus);
        focusWithoutInk(toFocus);
      });
    }

    if (routes.SITE_SETTINGS_JAVASCRIPT_JIT) {
      this.focusConfig.set(routes.SITE_SETTINGS_JAVASCRIPT_JIT.path, () => {
        const toFocus =
            this.shadowRoot!.querySelector<HTMLElement>('#v8-setting-link');
        assert(toFocus);
        focusWithoutInk(toFocus);
      });
    }
  }

  override ready() {
    super.ready();

    CrSettingsPrefs.initialized.then(() => {
      // Expand initial pref value manually because automatic
      // expanding is disabled.
      const prefValue = this.getPref('generated.safe_browsing').value;
      if (prefValue === SafeBrowsingSetting.ENHANCED) {
        this.$.safeBrowsingEnhanced.expanded = true;
      } else if (prefValue === SafeBrowsingSetting.STANDARD) {
        this.$.safeBrowsingStandard.expanded = true;
      }

      this.safeBrowsingStateOnOpen_ = prefValue;

      // The HTTPS-First Mode generated pref should never be set to
      // ENABLED_BALANCED if the feature flag is not enabled.
      if (!loadTimeData.getBoolean('enableHttpsFirstModeNewSettings')) {
        assert(
            this.getPref('generated.https_first_mode_enabled').value !==
            HttpsFirstModeSetting.ENABLED_BALANCED);
      }
    });

    this.registerHelpBubble(
        'kEnhancedProtectionSettingElementId',
        this.$.safeBrowsingEnhanced.getBubbleAnchor(), {anchorPaddingTop: 10});

    // Initialize the last focus time on page load.
    this.lastFocusTime_ = HatsBrowserProxyImpl.getInstance().now();
  }

  /**
   * RouteObserverMixin
   */
  override currentRouteChanged(route: Route) {
    if (route !== routes.SECURITY) {
      // If the user navigates to other settings page from security page, call
      // onBeforeUnload_ method to check if the security page survey should be
      // shown.
      this.onBeforeUnload_();
      this.isRouteSecurity_ = false;
      this.eventTracker_.removeAll();
      return;
    }
    this.metricsBrowserProxy_.recordSafeBrowsingInteractionHistogram(
        SafeBrowsingInteractions.SAFE_BROWSING_SHOWED);
    const queryParams = Router.getInstance().getQueryParameters();
    const section = queryParams.get('q');
    if (section === 'enhanced') {
      this.$.safeBrowsingEnhanced.expanded = false;
      this.$.safeBrowsingStandard.expanded = false;
    }

    this.eventTracker_.add(window, 'focus', this.onFocus_.bind(this));
    this.eventTracker_.add(window, 'blur', this.onBlur_.bind(this));
    this.eventTracker_.add(
        window, 'beforeunload', this.onBeforeUnload_.bind(this));

    // When the route changes back to the security page, reset the values.
    this.isRouteSecurity_ = true;
    this.lastInteraction_ = SecurityPageInteraction.NO_INTERACTION;
    this.totalTimeInFocus_ = 0;
    this.lastFocusTime_ = HatsBrowserProxyImpl.getInstance().now();
  }

  /** Call this function when the user switches to another tab. */
  private onBlur_() {
    // If the user is not on the security page, we will not calculate the time
    // values.
    if (!this.isRouteSecurity_) {
      return;
    }
    // Calculates the amount of time a user spent on a page for the current
    // session, from the point when they opened/returned to the page until
    // they left.
    const timeSinceLastFocus = HatsBrowserProxyImpl.getInstance().now() -
        (this.lastFocusTime_ as number);

    this.totalTimeInFocus_ += timeSinceLastFocus;
    // Set the lastFocusTime_ variable to undefined. This indicates that the
    // totalTimeInFocus_ variable is up to date.
    this.lastFocusTime_ = undefined;
  }

  /** Call this function when the user returns to it from other tabs. */
  private onFocus_() {
    // Updates the timestamp.
    this.lastFocusTime_ = HatsBrowserProxyImpl.getInstance().now();
  }

  /**
   * Trigger the securityPageHatsRequest api to potentially start the survey.
   */
  private onBeforeUnload_() {
    // If the user is not on other settings page, we do not send survey.
    if (!this.isRouteSecurity_) {
      return;
    }
    // If the lastFocusTime_ variable is not undefined, add the time between the
    // lastFocusTime_ and the current time to the totalTimeInFocus_ variable
    // because the user unloads the page before they un-focus on the page.
    if (this.lastFocusTime_ !== undefined) {
      this.totalTimeInFocus_ +=
          HatsBrowserProxyImpl.getInstance().now() - this.lastFocusTime_;
    }
    HatsBrowserProxyImpl.getInstance().securityPageHatsRequest(
        this.lastInteraction_, this.safeBrowsingStateOnOpen_,
        this.totalTimeInFocus_);
  }

  /**
   * Updates the buttons' expanded status by propagating previous click
   * events
   */
  private updateCollapsedButtons_() {
    this.$.safeBrowsingEnhanced.updateCollapsed();
    this.$.safeBrowsingStandard.updateCollapsed();
  }

  /**
   * Possibly displays the Safe Browsing disable dialog based on the users
   * selection.
   */
  private onSafeBrowsingRadioChange_() {
    const selected =
        Number.parseInt(this.$.safeBrowsingRadioGroup.selected || '', 10);
    const prefValue = this.getPref('generated.safe_browsing').value;
    if (prefValue !== selected) {
      this.recordInteractionHistogramOnRadioChange_(selected);
      this.recordActionOnRadioChange_(selected);
      this.interactedWithPage_(selected);
    }
    if (selected === SafeBrowsingSetting.DISABLED) {
      this.showDisableSafebrowsingDialog_ = true;
    } else {
      this.updateCollapsedButtons_();
      this.$.safeBrowsingRadioGroup.sendPrefChange();
    }
  }

  private interactedWithPage_(securityPageInteraction:
                                  SecurityPageInteraction) {
    this.lastInteraction_ = securityPageInteraction;
  }

  private getDisabledExtendedSafeBrowsing_(): boolean {
    return this.getPref('generated.safe_browsing').value !==
        SafeBrowsingSetting.STANDARD;
  }


  private getSafeBrowsingStandardSubLabel_(): string {
    return this.i18n(
        this.enableHashPrefixRealTimeLookups_ ?
            'safeBrowsingStandardDescProxy' :
            'safeBrowsingStandardDesc');
  }

  private getPasswordsLeakToggleSubLabel_(): string {
    let subLabel = this.i18n('passwordsLeakDetectionGeneralDescription');
    // If the backing password leak detection preference is enabled, but the
    // generated preference is off and user control is disabled, then additional
    // text explaining that the feature will be enabled if the user signs in is
    // added.
    if (this.prefs !== undefined) {
      const generatedPref = this.getPref('generated.password_leak_detection');
      if (this.getPref('profile.password_manager_leak_detection').value &&
          !generatedPref.value && generatedPref.userControlDisabled) {
        subLabel +=
            ' ' +  // Whitespace is a valid sentence separator w.r.t. i18n.
            this.i18n('passwordsLeakDetectionSignedOutEnabledDescription');
      }
    }
    return subLabel;
  }

  // Conversion helper for binding Integer pref values as String values.
  // For ControlledRadioButton elements, the name attribute must be of String
  // type in order to correctly match for the PrefControlMixin.
  private getName_(value: number): string {
    return value.toString();
  }

  private getHttpsFirstModeSubLabel_(): string {
    // If the backing HTTPS-Only Mode preference is enabled, but the
    // generated preference has its user control disabled, then additional
    // text explaining that the feature is locked down for Advanced Protection
    // users is added.
    const generatedPref = this.getPref('generated.https_first_mode_enabled');
    if (this.enableHttpsFirstModeNewSettings_) {
      return this.i18n(
          generatedPref.userControlDisabled ?
              'httpsFirstModeDescriptionAdvancedProtection' :
              'httpsFirstModeSectionDescription');
    } else {
      return this.i18n(
          generatedPref.userControlDisabled ?
              'httpsOnlyModeDescriptionAdvancedProtection' :
              'httpsOnlyModeDescription');
    }
  }

  private isHttpsFirstModeExpanded_(value: number): boolean {
    // If the pref is not user-modifiable, we should only show the main toggle.
    // (Note: this is not the case when the setting is policy-managed -- the
    // radio group should be expanded and labeled with the enterprise
    // indicator.)
    const generatedPref = this.getPref('generated.https_first_mode_enabled');
    if (generatedPref.userControlDisabled) {
      return false;
    }
    return value !== HttpsFirstModeSetting.DISABLED;
  }

  private onManageCertificatesClick_() {
    // <if expr="use_nss_certs">
    Router.getInstance().navigateTo(routes.CERTIFICATES);
    // </if>
    // <if expr="is_win or is_macosx">
    this.browserProxy_.showManageSslCertificates();
    // </if>
    this.metricsBrowserProxy_.recordSettingsPageHistogram(
        PrivacyElementInteractions.MANAGE_CERTIFICATES);
  }

  private onNewManageCertificatesClick_() {
    this.metricsBrowserProxy_.recordSettingsPageHistogram(
        PrivacyElementInteractions.MANAGE_CERTIFICATES);
    OpenWindowProxyImpl.getInstance().openUrl(
        loadTimeData.getString('certManagementV2URL'));
  }

  private onChromeCertificatesClick_() {
    OpenWindowProxyImpl.getInstance().openUrl(
        loadTimeData.getString('chromeRootStoreHelpCenterURL'));
  }

  private onAdvancedProtectionProgramLinkClick_() {
    window.open(loadTimeData.getString('advancedProtectionURL'));
  }

  private onV8SettingsClick_() {
    Router.getInstance().navigateTo(routes.SITE_SETTINGS_JAVASCRIPT_JIT);
  }

  private onSecurityKeysClick_() {
    Router.getInstance().navigateTo(routes.SECURITY_KEYS);
  }

  // <if expr="is_win">
  private onManagePhonesClick_() {
    Router.getInstance().navigateTo(routes.SECURITY_KEYS_PHONES);
  }
  // </if>

  private onEnhancedProtectionLearnMoreClick_(e: Event) {
    OpenWindowProxyImpl.getInstance().openUrl(
        loadTimeData.getString('enhancedProtectionHelpCenterURL'));
    e.preventDefault();
  }

  private onSafeBrowsingExtendedReportingChange_() {
    this.metricsBrowserProxy_.recordSettingsPageHistogram(
        PrivacyElementInteractions.IMPROVE_SECURITY);
  }

  /**
   * Handles the closure of the disable safebrowsing dialog, reselects the
   * appropriate radio button if the user cancels the dialog, and puts focus on
   * the disable safebrowsing button.
   */
  private onDisableSafebrowsingDialogClose_() {
    const dialog =
        this.shadowRoot!.querySelector('settings-simple-confirmation-dialog');
    assert(dialog);
    const confirmed = dialog.wasConfirmed();
    this.recordInteractionHistogramOnSafeBrowsingDialogClose_(confirmed);
    this.recordActionOnSafeBrowsingDialogClose_(confirmed);
    // Check if the dialog was confirmed before closing it.
    if (confirmed) {
      this.$.safeBrowsingRadioGroup.sendPrefChange();
      this.updateCollapsedButtons_();
    } else {
      this.$.safeBrowsingRadioGroup.resetToPrefValue();
    }

    this.showDisableSafebrowsingDialog_ = false;

    // Set focus back to the no protection button regardless of user interaction
    // with the dialog, as it was the entry point to the dialog.
    focusWithoutInk(this.$.safeBrowsingDisabled);
  }

  private onEnhancedProtectionExpandButtonClicked_() {
    this.recordInteractionHistogramOnExpandButtonClicked_(
        SafeBrowsingSetting.ENHANCED);
    this.recordActionOnExpandButtonClicked_(SafeBrowsingSetting.ENHANCED);
    this.interactedWithPage_(
        SecurityPageInteraction.EXPAND_BUTTON_ENHANCED_CLICK);
  }

  private onStandardProtectionExpandButtonClicked_() {
    this.recordInteractionHistogramOnExpandButtonClicked_(
        SafeBrowsingSetting.STANDARD);
    this.recordActionOnExpandButtonClicked_(SafeBrowsingSetting.STANDARD);
    this.interactedWithPage_(
        SecurityPageInteraction.EXPAND_BUTTON_STANDARD_CLICK);
  }

  // <if expr="is_chromeos">
  private onOpenChromeOsSecureDnsSettingsClicked_() {
    const path =
        loadTimeData.getString('chromeOSPrivacyAndSecuritySectionPath');
    OpenWindowProxyImpl.getInstance().openUrl(`chrome://os-settings/${path}`);
  }
  // </if>

  private recordInteractionHistogramOnRadioChange_(safeBrowsingSetting:
                                                       SafeBrowsingSetting) {
    let action;
    if (safeBrowsingSetting === SafeBrowsingSetting.ENHANCED) {
      action =
          SafeBrowsingInteractions.SAFE_BROWSING_ENHANCED_PROTECTION_CLICKED;
    } else if (safeBrowsingSetting === SafeBrowsingSetting.STANDARD) {
      action =
          SafeBrowsingInteractions.SAFE_BROWSING_STANDARD_PROTECTION_CLICKED;
    } else {
      action =
          SafeBrowsingInteractions.SAFE_BROWSING_DISABLE_SAFE_BROWSING_CLICKED;
    }
    this.metricsBrowserProxy_.recordSafeBrowsingInteractionHistogram(action);
  }

  private recordInteractionHistogramOnExpandButtonClicked_(
      safeBrowsingSetting: SafeBrowsingSetting) {
    this.metricsBrowserProxy_.recordSafeBrowsingInteractionHistogram(
        safeBrowsingSetting === SafeBrowsingSetting.ENHANCED ?
            SafeBrowsingInteractions
                .SAFE_BROWSING_ENHANCED_PROTECTION_EXPAND_ARROW_CLICKED :
            SafeBrowsingInteractions
                .SAFE_BROWSING_STANDARD_PROTECTION_EXPAND_ARROW_CLICKED);
  }

  private recordInteractionHistogramOnSafeBrowsingDialogClose_(confirmed:
                                                                   boolean) {
    this.metricsBrowserProxy_.recordSafeBrowsingInteractionHistogram(
        confirmed ? SafeBrowsingInteractions
                        .SAFE_BROWSING_DISABLE_SAFE_BROWSING_DIALOG_CONFIRMED :
                    SafeBrowsingInteractions
                        .SAFE_BROWSING_DISABLE_SAFE_BROWSING_DIALOG_DENIED);
  }

  private recordActionOnRadioChange_(safeBrowsingSetting: SafeBrowsingSetting) {
    let actionName;
    if (safeBrowsingSetting === SafeBrowsingSetting.ENHANCED) {
      actionName = 'SafeBrowsing.Settings.EnhancedProtectionClicked';
    } else if (safeBrowsingSetting === SafeBrowsingSetting.STANDARD) {
      actionName = 'SafeBrowsing.Settings.StandardProtectionClicked';
    } else {
      actionName = 'SafeBrowsing.Settings.DisableSafeBrowsingClicked';
    }
    this.metricsBrowserProxy_.recordAction(actionName);
  }

  private recordActionOnExpandButtonClicked_(safeBrowsingSetting:
                                                 SafeBrowsingSetting) {
    this.metricsBrowserProxy_.recordAction(
        safeBrowsingSetting === SafeBrowsingSetting.ENHANCED ?
            'SafeBrowsing.Settings.EnhancedProtectionExpandArrowClicked' :
            'SafeBrowsing.Settings.StandardProtectionExpandArrowClicked');
  }

  private recordActionOnSafeBrowsingDialogClose_(confirmed: boolean) {
    this.metricsBrowserProxy_.recordAction(
        confirmed ? 'SafeBrowsing.Settings.DisableSafeBrowsingDialogConfirmed' :
                    'SafeBrowsing.Settings.DisableSafeBrowsingDialogDenied');
  }
}

declare global {
  interface HTMLElementTagNameMap {
    'settings-security-page': SettingsSecurityPageElement;
  }
}

customElements.define(
    SettingsSecurityPageElement.is, SettingsSecurityPageElement);