Skip to content

Commit

Permalink
[Security Page] HaTS integration to potentially trigger a survey afte…
Browse files Browse the repository at this point in the history
…r a delay

This CL integrates the HaTS service into the chrome://settings/security
page. When users interact with the security page, a survey may be triggered with a delay.
- Adds new enums in hats_browser_proxy and hats_handler
- Adds new function entries in hats_handler and related files
- Creates new feature flag to control the experiment
- Adds logic to report specific data (user actions, safe browsing
  settings, etc.) and launch survey
- Delay is set to 15s and it’s configurable through Finch

Bug: 1495838
Change-Id: Ibbe99522598e61f12c24bb3f101796a3a400338b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4955836
Reviewed-by: Side YILMAZ <sideyilmaz@chromium.org>
Reviewed-by: Rebekah Potter <rbpotter@chromium.org>
Reviewed-by: Martin Šrámek <msramek@chromium.org>
Commit-Queue: Zack Han <zackhan@chromium.org>
Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com>
Cr-Commit-Position: refs/heads/main@{#1216315}
  • Loading branch information
Zack Han authored and Chromium LUCI CQ committed Oct 27, 2023
1 parent e00a3ae commit 8fff28e
Show file tree
Hide file tree
Showing 13 changed files with 355 additions and 3 deletions.
50 changes: 50 additions & 0 deletions chrome/browser/resources/settings/hats_browser_proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,69 @@ export enum TrustSafetyInteraction {
OPENED_AD_MEASUREMENT_SUBPAGE = 9,
}

/**
* All interactions from the security settings page which may result in a HaTS
* survey. Must be kept in sync with the enum of the same name located in:
* chrome/browser/ui/webui/settings/hats_handler.h
*/
export enum SecurityPageInteraction {
RADIO_BUTTON_ENHANCED_CLICK = 0,
RADIO_BUTTON_STANDARD_CLICK = 1,
RADIO_BUTTON_DISABLE_CLICK = 2,
EXPAND_BUTTON_ENHANCED_CLICK = 3,
EXPAND_BUTTON_STANDARD_CLICK = 4,
NO_INTERACTION = 5,
}

/**
* 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,
}

/**
* All interactions from the security settings page which may result in a HaTS
* survey.
*
* Must be kept in sync with the enum of the same name in hats_handler.h.
*/
export interface HatsBrowserProxy {
/**
* Inform HaTS that the user performed a Trust & Safety interaction.
* @param interaction The type of interaction performed by the user.
*/
trustSafetyInteractionOccurred(interaction: TrustSafetyInteraction): void;

/**
* Inform HaTS that the user performed an interaction on security page.
* @param securityPageInteraction The type of interaction performed on the
* security page.
* @param safeBrowsingSetting The type of safe browsing settings the user is
* on prior to the interaction.
*/
securityPageInteractionOccurred(
securityPageInteraction: SecurityPageInteraction,
safeBrowsingSetting: SafeBrowsingSetting): void;
}

export class HatsBrowserProxyImpl implements HatsBrowserProxy {
trustSafetyInteractionOccurred(interaction: TrustSafetyInteraction) {
chrome.send('trustSafetyInteractionOccurred', [interaction]);
}

securityPageInteractionOccurred(
securityPageInteraction: SecurityPageInteraction,
safeBrowsingSetting: SafeBrowsingSetting) {
chrome.send(
'securityPageInteractionOccurred',
[securityPageInteraction, safeBrowsingSetting]);
}

static getInstance(): HatsBrowserProxy {
return instance || (instance = new HatsBrowserProxyImpl());
}
Expand Down
13 changes: 13 additions & 0 deletions chrome/browser/resources/settings/privacy_page/security_page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {OpenWindowProxyImpl} from 'chrome://resources/js/open_window_proxy.js';
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';

import {FocusConfig} from '../focus_config.js';
import {HatsBrowserProxyImpl, SecurityPageInteraction} from '../hats_browser_proxy.js';
import {loadTimeData} from '../i18n_setup.js';
import {MetricsBrowserProxy, MetricsBrowserProxyImpl, PrivacyElementInteractions, SafeBrowsingInteractions} from '../metrics_browser_proxy.js';
import {routes} from '../route.js';
Expand Down Expand Up @@ -266,6 +267,7 @@ export class SettingsSecurityPageElement extends
if (prefValue !== selected) {
this.recordInteractionHistogramOnRadioChange_(selected);
this.recordActionOnRadioChange_(selected);
this.interactedWithPage_(selected);
}
if (selected === SafeBrowsingSetting.DISABLED) {
this.showDisableSafebrowsingDialog_ = true;
Expand All @@ -275,6 +277,13 @@ export class SettingsSecurityPageElement extends
}
}

private interactedWithPage_(securityPageInteraction:
SecurityPageInteraction) {
const safeBrowsingValue = this.getPref('generated.safe_browsing').value;
HatsBrowserProxyImpl.getInstance().securityPageInteractionOccurred(
securityPageInteraction, safeBrowsingValue);
}

private getDisabledExtendedSafeBrowsing_(): boolean {
return this.getPref('generated.safe_browsing').value !==
SafeBrowsingSetting.STANDARD;
Expand Down Expand Up @@ -416,12 +425,16 @@ export class SettingsSecurityPageElement extends
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">
Expand Down
2 changes: 1 addition & 1 deletion chrome/browser/resources/settings/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export {SettingsIdleLoadElement} from './controls/settings_idle_load.js';
export {DefaultBrowserBrowserProxy, DefaultBrowserBrowserProxyImpl, DefaultBrowserInfo} from './default_browser_page/default_browser_browser_proxy.js';
export {SettingsDefaultBrowserPageElement} from './default_browser_page/default_browser_page.js';
// </if>
export {HatsBrowserProxy, HatsBrowserProxyImpl, TrustSafetyInteraction} from './hats_browser_proxy.js';
export {HatsBrowserProxy, HatsBrowserProxyImpl, SafeBrowsingSetting, SecurityPageInteraction, TrustSafetyInteraction} from './hats_browser_proxy.js';
export {loadTimeData} from './i18n_setup.js';
export {DeleteBrowsingDataAction, MetricsBrowserProxy, MetricsBrowserProxyImpl, PrivacyElementInteractions, PrivacyGuideInteractions, PrivacyGuideSettingsStates, PrivacyGuideStepsEligibleAndReached, SafeBrowsingInteractions, SafetyCheckInteractions, SafetyCheckNotificationsModuleInteractions, SafetyCheckUnusedSitePermissionsModuleInteractions} from './metrics_browser_proxy.js';
export {NtpExtension, OnStartupBrowserProxy, OnStartupBrowserProxyImpl} from './on_startup_page/on_startup_browser_proxy.js';
Expand Down
10 changes: 10 additions & 0 deletions chrome/browser/ui/hats/survey_config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ constexpr char kHatsSurveyTriggerPrivacySandbox[] = "privacy-sandbox";
constexpr char kHatsSurveyTriggerRedWarning[] = "red-warning";
constexpr char kHatsSurveyTriggerSettings[] = "settings";
constexpr char kHatsSurveyTriggerSettingsPrivacy[] = "settings-privacy";
constexpr char kHatsSurveyTriggerSettingsSecurity[] = "settings-security";
constexpr char kHatsSurveyTriggerTrackingProtectionControlImmediate[] =
"tracking-protection-control-immediate";
constexpr char kHatsSurveyTriggerTrackingProtectionTreatmentImmediate[] =
Expand Down Expand Up @@ -167,6 +168,15 @@ std::vector<hats::SurveyConfig> GetAllSurveyConfigs() {
/*presupplied_trigger_id=*/absl::nullopt,
std::vector<std::string>{"3P cookies blocked",
"Privacy Sandbox enabled"});
survey_configs.emplace_back(
&features::kHappinessTrackingSurveysForSecurityPage,
kHatsSurveyTriggerSettingsSecurity,
/*presupplied_trigger_id=*/
features::kHappinessTrackingSurveysForSecurityPageTriggerId.Get(),
std::vector<std::string>{},
std::vector<std::string>{
"Security Page User Action", "Safe Browsing Setting Before Trigger",
"Safe Browsing Setting After Trigger", "Client Channel"});
survey_configs.emplace_back(
&features::kHappinessTrackingSurveysForDesktopPrivacyGuide,
kHatsSurveyTriggerPrivacyGuide);
Expand Down
1 change: 1 addition & 0 deletions chrome/browser/ui/hats/survey_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ extern const char kHatsSurveyTriggerTrackingProtectionTreatmentImmediate[];
extern const char kHatsSurveyTriggerTrackingProtectionControlDelayed[];
extern const char kHatsSurveyTriggerTrackingProtectionTreatmentDelayed[];
extern const char kHatsSurveyTriggerTrustSafetyPrivacySandbox3ConsentAccept[];
extern const char kHatsSurveyTriggerSettingsSecurity[];
extern const char kHatsSurveyTriggerTrustSafetyPrivacySandbox3ConsentDecline[];
extern const char kHatsSurveyTriggerTrustSafetyPrivacySandbox3NoticeDismiss[];
extern const char kHatsSurveyTriggerTrustSafetyPrivacySandbox3NoticeOk[];
Expand Down
131 changes: 131 additions & 0 deletions chrome/browser/ui/webui/settings/hats_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@
#include "chrome/browser/ui/hats/hats_service_factory.h"
#include "chrome/browser/ui/hats/trust_safety_sentiment_service.h"
#include "chrome/browser/ui/hats/trust_safety_sentiment_service_factory.h"
#include "chrome/common/channel_info.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/pref_names.h"
#include "components/content_settings/core/browser/cookie_settings.h"
#include "components/content_settings/core/common/pref_names.h"
#include "components/prefs/pref_service.h"
#include "components/privacy_sandbox/privacy_sandbox_prefs.h"
#include "components/privacy_sandbox/privacy_sandbox_settings.h"
#include "components/version_info/version_info.h"
#include "content/public/browser/visibility.h"
#include "content/public/browser/web_contents.h"

Expand Down Expand Up @@ -70,6 +72,135 @@ void HatsHandler::RegisterMessages() {
"trustSafetyInteractionOccurred",
base::BindRepeating(&HatsHandler::HandleTrustSafetyInteractionOccurred,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"securityPageInteractionOccurred",
base::BindRepeating(&HatsHandler::HandleSecurityPageInteractionOccurred,
base::Unretained(this)));
}

/**
* First arg in the list indicates the SecurityPageInteraction.
* Second arg in the list indicates the SafeBrowsingSetting.
*/
void HatsHandler::HandleSecurityPageInteractionOccurred(
const base::Value::List& args) {
AllowJavascript();

// There are 2 argument in the input list.
// The first one is the SecurityPageInteraction that triggered the survey.
// The second one is the safe browsing setting the user was on.
CHECK_EQ(2U, args.size());

Profile* profile = Profile::FromWebUI(web_ui());

// Enterprise users consideration.
// If the admin disabled the survey, the survey will not be requested.
if (!safe_browsing::IsSafeBrowsingSurveysEnabled(*profile->GetPrefs())) {
return;
}

// Request HaTS survey.
HatsService* hats_service = HatsServiceFactory::GetForProfile(
profile, /* create_if_necessary = */ true);

// The HaTS service may not be available for the profile, for example if it
// is a guest profile.
if (!hats_service) {
return;
}

// Generate the Product Specific bits data from |profile| and |args|.
SurveyStringData product_specific_string_data =
GetSecurityPageProductSpecificStringData(profile, args);

hats_service->LaunchDelayedSurveyForWebContents(
kHatsSurveyTriggerSettingsSecurity, web_ui()->GetWebContents(),
features::kHappinessTrackingSurveysForSecurityPageTime.Get()
.InMilliseconds(),
/*product_specific_bits_data=*/{},
/*product_specific_string_data=*/product_specific_string_data,
/*require_same_origin=*/true);
}

/**
* Generate the Product Specific string data from |profile| and |args|.
* - First arg in the list indicates the SecurityPageInteraction.
* - Second arg in the list indicates the SafeBrowsingSetting.
*/
SurveyStringData HatsHandler::GetSecurityPageProductSpecificStringData(
Profile* profile,
const base::Value::List& args) {
auto interaction = static_cast<SecurityPageInteraction>(args[0].GetInt());
auto safe_browsing_setting =
static_cast<SafeBrowsingSetting>(args[1].GetInt());

std::string security_page_interaction_type = "";
std::string safe_browsing_setting_before = "";
std::string safe_browsing_setting_current = "";

switch (interaction) {
case SecurityPageInteraction::RADIO_BUTTON_ENHANCED_CLICK: {
security_page_interaction_type =
"enhanced_protection_radio_button_clicked";
break;
}
case SecurityPageInteraction::RADIO_BUTTON_STANDARD_CLICK: {
security_page_interaction_type =
"standard_protection_radio_button_clicked";
break;
}
case SecurityPageInteraction::RADIO_BUTTON_DISABLE_CLICK: {
security_page_interaction_type = "no_protection_radio_button_clicked";
break;
}
case SecurityPageInteraction::EXPAND_BUTTON_ENHANCED_CLICK: {
security_page_interaction_type =
"enhanced_protection_expand_button_clicked.";
break;
}
case SecurityPageInteraction::EXPAND_BUTTON_STANDARD_CLICK: {
security_page_interaction_type =
"standard_protection_expand_button_clicked.";
break;
}
}

switch (safe_browsing_setting) {
case SafeBrowsingSetting::ENHANCED: {
safe_browsing_setting_before = "enhanced_protection";
break;
}
case SafeBrowsingSetting::STANDARD: {
safe_browsing_setting_before = "standard_protection";
break;
}
case SafeBrowsingSetting::DISABLED: {
safe_browsing_setting_before = "no_protection";
break;
}
}

bool safe_browsing_enabled =
profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnabled);
bool safe_browsing_enhanced_enabled =
profile->GetPrefs()->GetBoolean(prefs::kSafeBrowsingEnhanced);
if (safe_browsing_enhanced_enabled) {
safe_browsing_setting_current = "enhanced_protection";
} else if (safe_browsing_enabled) {
safe_browsing_setting_current = "standard_protection";
} else {
safe_browsing_setting_current = "no_protection";
}

std::string client_channel =
std::string(version_info::GetChannelString(chrome::GetChannel()));

return {
{"Security Page User Action", security_page_interaction_type},
{"Safe Browsing Setting Before Trigger", safe_browsing_setting_before},
{"Safe Browsing Setting After Trigger", safe_browsing_setting_current},
{"Client Channel", client_channel},
};
}

void HatsHandler::HandleTrustSafetyInteractionOccurred(
Expand Down
38 changes: 38 additions & 0 deletions chrome/browser/ui/webui/settings/hats_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#define CHROME_BROWSER_UI_WEBUI_SETTINGS_HATS_HANDLER_H_

#include "base/gtest_prod_util.h"
#include "chrome/browser/ui/hats/hats_service.h"
#include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"

namespace settings {
Expand All @@ -26,12 +27,15 @@ class HatsHandler : public SettingsPageUIHandler {

void HandleTrustSafetyInteractionOccurred(const base::Value::List& args);

void HandleSecurityPageInteractionOccurred(const base::Value::List& args);

private:
friend class HatsHandlerTest;
friend class HatsHandlerParamTest;
FRIEND_TEST_ALL_PREFIXES(HatsHandlerTest, PrivacySettingsHats);
FRIEND_TEST_ALL_PREFIXES(HatsHandlerTest, PrivacyGuideHats);
FRIEND_TEST_ALL_PREFIXES(HatsHandlerTest, PrivacySandboxHats);
FRIEND_TEST_ALL_PREFIXES(HatsHandlerTest, SecurityPageInteractions);
FRIEND_TEST_ALL_PREFIXES(HatsHandlerTest, TrustSafetySentimentInteractions);
FRIEND_TEST_ALL_PREFIXES(HatsHandlerNoSandboxTest, PrivacySettings);
FRIEND_TEST_ALL_PREFIXES(HatsHandlerNoSandboxTest,
Expand All @@ -54,6 +58,30 @@ class HatsHandler : public SettingsPageUIHandler {
OPENED_AD_MEASUREMENT_SUBPAGE = 9,
};

/**
* All interactions from the security settings page which may result in a HaTS
* survey. Must be kept in sync with the enum of the same name in
* hats_browser_proxy.js
*/
enum class SecurityPageInteraction {
RADIO_BUTTON_ENHANCED_CLICK = 0,
RADIO_BUTTON_STANDARD_CLICK = 1,
RADIO_BUTTON_DISABLE_CLICK = 2,
EXPAND_BUTTON_ENHANCED_CLICK = 3,
EXPAND_BUTTON_STANDARD_CLICK = 4
};

/**
* 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
*/
enum class SafeBrowsingSetting {
ENHANCED = 0,
STANDARD = 1,
DISABLED = 2,
};

// Requests the appropriate HaTS survey, which may be none, for |interaction|.
void RequestHatsSurvey(TrustSafetyInteraction interaction);

Expand All @@ -63,6 +91,16 @@ class HatsHandler : public SettingsPageUIHandler {
// SettingsPageUIHandler implementation.
void OnJavascriptAllowed() override {}
void OnJavascriptDisallowed() override {}

/**
* Generate the Product Specific string data from |profile| and |args| for
* chrome://settings/security page HaTS.
* - First arg in the list indicates the SecurityPageInteraction.
* - Second arg in the list indicates the SafeBrowsingSetting.
*/
SurveyStringData GetSecurityPageProductSpecificStringData(
Profile* profile,
const base::Value::List& args);
};

} // namespace settings
Expand Down

0 comments on commit 8fff28e

Please sign in to comment.