File: trust_safety_sentiment_service.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (304 lines) | stat: -rw-r--r-- 13,709 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_UI_HATS_TRUST_SAFETY_SENTIMENT_SERVICE_H_
#define CHROME_BROWSER_UI_HATS_TRUST_SAFETY_SENTIMENT_SERVICE_H_

#include "base/gtest_prod_util.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_multi_source_observation.h"
#include "base/time/time.h"
#include "chrome/browser/download/download_item_warning_data.h"
#include "chrome/browser/metrics/desktop_session_duration/desktop_session_duration_tracker.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_observer.h"
#include "components/browsing_data/core/browsing_data_utils.h"
#include "components/download/public/common/download_danger_type.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/safe_browsing/core/browser/db/v4_protocol_manager_util.h"
#include "components/safe_browsing/core/browser/password_protection/metrics_util.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"

using PasswordProtectionUIType = safe_browsing::WarningUIType;
using PasswordProtectionUIAction = safe_browsing::WarningAction;

inline constexpr base::TimeDelta kPasswordChangeInactivity = base::Minutes(30);
inline constexpr base::TimeDelta kSafetyHubSurveyDelay = base::Minutes(10);

// Service which receives events from Trust & Safety features and determines
// whether or not to launch a HaTS survey on the NTP for the user.
class TrustSafetySentimentService
    : public KeyedService,
      public ProfileObserver,
      public metrics::DesktopSessionDurationTracker::Observer {
 public:
  explicit TrustSafetySentimentService(Profile* profile);
  ~TrustSafetySentimentService() override;

  // Called when the user opens an NTP. This allows the service to update its
  // eligibility logic, and potentially show a survey. Virtual to allow mocking
  // in tests.
  virtual void OpenedNewTabPage();

  // Called when the user interacts with the privacy settings on
  // chrome://settings in |web_contents|. Interaction in this context could be
  // using a link row on the privacy settings card. Calling this allows the
  // service to monitor |web_contents| to determine if the user stays on
  // settings for the required time. Virtual to allow mocking in tests.
  virtual void InteractedWithPrivacySettings(
      content::WebContents* web_contents);

  // Called when the user runs safety check. This is immediately considered as a
  // trigger action. Virtual to allow mocking in tests.
  virtual void RanSafetyCheck();

  // Called when the user opens Page Info.
  virtual void PageInfoOpened();

  // Called when the user interacts in some way with Page Info.
  virtual void InteractedWithPageInfo();

  // Called when the user saves a password via the manage passwords UI. This is
  // the native UI shown when Chrome detects a password has been entered into
  // the web page.
  virtual void SavedPassword();

  // Called when the user closes Page Info. If Page Info was opened for the
  // target time, or the user interacted with it while it was open, a trigger
  // action is recorded.
  virtual void PageInfoClosed();

  // Called when the user visits chrome://settings/passwords. Calling this
  // allows the service to monitor |web_contents| to determine if the user
  // remains on settings after visiting the page for the required time. Virtual
  // to allow mocking in tests.
  virtual void OpenedPasswordManager(content::WebContents* web_contents);

  // Called when the user saves a card through the native UI bubble shown after
  // the user uses a card on a website.
  virtual void SavedCard();

  // Called when the user runs password check. Virtual to allow mocking in
  // tests.
  virtual void RanPasswordCheck();

  // Called when the user deletes data from Clear Browsing Data dialog.
  virtual void ClearedBrowsingData(browsing_data::BrowsingDataType datatype);

  // Called when the user finishes the privacy guide. Virtual to allow mocking
  // in tests.
  virtual void FinishedPrivacyGuide();

  // Profile Observer:
  void OnOffTheRecordProfileCreated(Profile* off_the_record) override;
  void OnProfileWillBeDestroyed(Profile* profile) override;

  // metrics::DesktopSessionDurationTracker::Observer
  void OnSessionEnded(base::TimeDelta session_length,
                      base::TimeTicks session_end) override;

  // The feature areas that the service delivers HaTS surveys for. Each feature
  // area is associated with a different Listnr survey, and has a different set
  // of Product Specific Data (PSD). kIneligible is an exception, and
  // is not associated with any survey, but rather represents the collection of
  // features for which interaction with should also be considered when
  // determining elibigility for a survey.

  // These values are persisted to logs and entries should not be renumbered or
  // reused and kept up to date with TrustSafetySentimentFeatureArea in
  // enums.xml.
  enum class FeatureArea {
    kIneligible = 0,
    kPrivacySettings = 1,
    kTrustedSurface = 2,
    kTransactions = 3,
    // kPrivacySandbox3ConsentAccept = 4, // DEPRECATED.
    // kPrivacySandbox3ConsentDecline = 5, // DEPRECATED.
    // kPrivacySandbox3NoticeDismiss = 6, // DEPRECATED.
    // kPrivacySandbox3NoticeOk = 7, // DEPRECATED.
    // kPrivacySandbox3NoticeSettings = 8, // DEPRECATED.
    // kPrivacySandbox3NoticeLearnMore = 9, // DEPRECATED.
    kSafetyCheck = 10,
    kPasswordCheck = 11,
    kBrowsingData = 12,
    kPrivacyGuide = 13,
    kControlGroup = 14,
    // kPrivacySandbox4ConsentAccept = 15, // DEPRECATED.
    // kPrivacySandbox4ConsentDecline = 16, // DEPRECATED.
    // kPrivacySandbox4NoticeOk = 17, // DEPRECATED.
    // kPrivacySandbox4NoticeSettings = 18, // DEPRECATED.
    kSafeBrowsingInterstitial = 19,
    kDownloadWarningUI = 20,
    kPasswordProtectionUI = 21,
    kSafetyHubNotification = 22,
    kSafetyHubInteracted = 23,
    kMaxValue = kSafetyHubInteracted,
  };

  // Called when the user interacts with a safe browsing blocking page.
  virtual void InteractedWithSafeBrowsingInterstitial(
      bool did_proceed,
      safe_browsing::SBThreatType threat_type);

  // Called when the user completes terminal action within a download warning.
  // These actions can include: DISCARD, and PROCEED.
  virtual void InteractedWithDownloadWarningUI(
      DownloadItemWarningData::WarningSurface surface,
      DownloadItemWarningData::WarningAction action);

  // Called when user clicks to protect/reset/check their password on a password
  // protection UI. This triggers a survey if the user has not finished changing
  // their password after a certain period of time.
  virtual void ProtectResetOrCheckPasswordClicked(
      PasswordProtectionUIType ui_type);

  // Called when a user sees a password protection warning and decides to ignore
  // the warning, close the warning, or mark the warning as legitimate.
  virtual void PhishedPasswordUpdateNotClicked(
      PasswordProtectionUIType ui_type,
      PasswordProtectionUIAction action);

  // Called when a user finishes updating their phished password after seeing a
  // warning.
  virtual void PhishedPasswordUpdateFinished();

  // Checks that this feature area is valid for the current version.
  static bool VersionCheck(FeatureArea feature_area);

  // Gets the HaTS trigger for a feature area.
  static std::string GetHatsTriggerForFeatureArea(FeatureArea feature_area);

  // Performs a FeatureArea and Version-specific dice roll.
  // Returns true if succeeds, else false.
  static bool ProbabilityCheck(FeatureArea feature_area);

  // Triggers a survey for Safety Hub for the given feature area (visiting SH or
  // seeing a notification).
  virtual void TriggerSafetyHubSurvey(
      TrustSafetySentimentService::FeatureArea feature_area,
      std::map<std::string, bool> product_specific_data);

 private:
  friend class TrustSafetySentimentServiceTest;
  FRIEND_TEST_ALL_PREFIXES(TrustSafetySentimentServiceTest,
                           Eligibility_NtpOpens);
  FRIEND_TEST_ALL_PREFIXES(TrustSafetySentimentServiceTest, Eligibility_Time);
  FRIEND_TEST_ALL_PREFIXES(TrustSafetySentimentServiceTest, TriggerProbability);
  FRIEND_TEST_ALL_PREFIXES(TrustSafetySentimentServiceTest,
                           TriggersClearOnLaunch);
  FRIEND_TEST_ALL_PREFIXES(TrustSafetySentimentServiceTest,
                           SettingsWatcher_PrivacySettings);
  FRIEND_TEST_ALL_PREFIXES(TrustSafetySentimentServiceTest,
                           SettingsWatcher_PasswordManager);
  FRIEND_TEST_ALL_PREFIXES(TrustSafetySentimentServiceTest, RanSafetyCheck);
  FRIEND_TEST_ALL_PREFIXES(TrustSafetySentimentServiceTest,
                           PrivacySettingsProductSpecificData);
  FRIEND_TEST_ALL_PREFIXES(TrustSafetySentimentServiceTest,
                           Eligibility_V1FeatureWhileV2Enabled);
  FRIEND_TEST_ALL_PREFIXES(TrustSafetySentimentServiceTest, V2_SafetyCheck);
  FRIEND_TEST_ALL_PREFIXES(TrustSafetySentimentServiceTest, V2_TrustedSurface);
  FRIEND_TEST_ALL_PREFIXES(TrustSafetySentimentServiceTest, V2_PasswordCheck);
  FRIEND_TEST_ALL_PREFIXES(TrustSafetySentimentServiceTest, V2_BrowsingData);
  FRIEND_TEST_ALL_PREFIXES(TrustSafetySentimentServiceTest,
                           V2_BrowsingData_NotInterested);
  FRIEND_TEST_ALL_PREFIXES(TrustSafetySentimentServiceTest, V2_PrivacyGuide);
  FRIEND_TEST_ALL_PREFIXES(TrustSafetySentimentServiceTest, V2_ControlGroup);
  FRIEND_TEST_ALL_PREFIXES(TrustSafetySentimentServiceTest,
                           SafetyHubInteractionState);

  // Struct representing a trigger (user action relevant to T&S) that previously
  // occurred, and is awaiting the appropriate eligibility steps before causing
  // a survey to be shown.
  struct PendingTrigger {
    PendingTrigger();
    PendingTrigger(const PendingTrigger& other);
    PendingTrigger(const std::map<std::string, bool>& product_specific_data,
                   int remaining_ntps_to_open);
    explicit PendingTrigger(int remaining_ntps_to_open);
    ~PendingTrigger();

    std::map<std::string, bool> product_specific_data;
    int remaining_ntps_to_open;
    base::Time occurred_time;
  };

  // Class which observes the provided |web_contents| for |required_open_time|
  // and then checks if |web_contents| is currently visible, and has settings
  // open. Calls |success_callback| if the user stays on settings for the
  // required time, calls |complete_callback| when the observation time has
  // expired, or |web_contents| has been destroyed.
  class SettingsWatcher : content::WebContentsObserver {
   public:
    SettingsWatcher(content::WebContents* web_contents,
                    base::TimeDelta required_open_time,
                    base::OnceCallback<void()> success_callback,
                    base::OnceCallback<void()> complete_callback);
    ~SettingsWatcher() override;

    // WebContentsObserver:
    void WebContentsDestroyed() override;

   private:
    void TimerComplete();

    raw_ptr<content::WebContents> web_contents_;
    base::OnceCallback<void()> success_callback_;
    base::OnceCallback<void()> complete_callback_;
    base::WeakPtrFactory<SettingsWatcher> weak_ptr_factory_{this};
  };

  // Struct which represents the PageInfo state of interest to the service.
  struct PageInfoState {
    PageInfoState();
    base::Time opened_time;
    bool interacted = false;
  };

  // Struct which represents the PhishedPasswordChange state. When a user clicks
  // to change their password, we want to wait to trigger a survey until after
  // they change their password or the user has been inactive for some time.
  struct PhishedPasswordChangeState {
    PhishedPasswordChangeState();
    base::Time password_change_click_ts_;
    PasswordProtectionUIType ui_type_;
    bool finished_action = false;
  };

  void SettingsWatcherComplete();

  // Record that a trigger occurred, placing it in the set of pending triggers.
  // Private as the service itself determines when a trigger has occurred, and
  // is responsible for generating the appropriate |product_specific_data|.
  void TriggerOccurred(
      FeatureArea feature_area,
      const std::map<std::string, bool>& product_specific_data);

  // Record that the user performed an action which should make them temporarily
  // ineligible to receive a survey. This records a trigger for the kIneligible
  // feature area, which just like any other trigger will prevent a survey from
  // being shown, but will not result in a survey.
  void PerformedIneligibleAction();

  static bool ShouldBlockSurvey(const PendingTrigger& trigger);

  // Called by |ProtectResetOrCheckPasswordClicked| and
  // |PhishedPasswordUpdateNotClicked|. Triggers a survey if one has not already
  // been triggered for the user journey.
  void MaybeTriggerPasswordProtectionSurvey(PasswordProtectionUIType ui_type,
                                            PasswordProtectionUIAction action);

  const raw_ptr<Profile> profile_;
  std::map<FeatureArea, PendingTrigger> pending_triggers_;
  std::unique_ptr<SettingsWatcher> settings_watcher_;
  std::unique_ptr<PageInfoState> page_info_state_;
  std::unique_ptr<PhishedPasswordChangeState> phished_password_change_state_;
  base::ScopedMultiSourceObservation<Profile, ProfileObserver>
      observed_profiles_{this};
  bool performed_control_group_dice_roll_;
  base::WeakPtrFactory<TrustSafetySentimentService> weak_ptr_factory_{this};
};

#endif  // CHROME_BROWSER_UI_HATS_TRUST_SAFETY_SENTIMENT_SERVICE_H_