1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_METRICS_RECORDER_H_
6 #define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_METRICS_RECORDER_H_
7 
8 #include <stdint.h>
9 
10 #include <map>
11 #include <memory>
12 #include <set>
13 #include <vector>
14 
15 #include "base/macros.h"
16 #include "base/memory/ref_counted.h"
17 #include "base/optional.h"
18 #include "base/time/clock.h"
19 #include "components/autofill/core/common/mojom/autofill_types.mojom.h"
20 #include "components/autofill/core/common/signatures.h"
21 #include "components/password_manager/core/browser/password_form.h"
22 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
23 #include "services/metrics/public/cpp/ukm_builders.h"
24 #include "services/metrics/public/cpp/ukm_recorder.h"
25 #include "url/gurl.h"
26 
27 class PrefService;
28 
29 namespace autofill {
30 struct FormData;
31 }
32 
33 namespace password_manager {
34 
35 struct InteractionsStats;
36 
37 // The pupose of this class is to record various types of metrics about the
38 // behavior of the PasswordFormManager and its interaction with the user and
39 // the page. The recorder tracks events tied to the logical life of a password
40 // form, from parsing to having been saved. These events happen on different
41 // places in the code and the logical password form can be captured by multiple
42 // instances of real objects. To allow sharing the single recorder object among
43 // those, this class is refcounted. Reporting happens on destruction of the
44 // metrics recorder. Note that UKM metrics are reported for intervals of length
45 // metrics::GetUploadInterval(). Only metrics that are reported from the time
46 // of creating the PasswordFormMetricsRecorder until the end of current upload
47 // interval are recorded. Everything after the end of the current upload
48 // interval is discarded. For this reason, it is essential that references are
49 // not just kept until browser shutdown.
50 class PasswordFormMetricsRecorder
51     : public base::RefCounted<PasswordFormMetricsRecorder> {
52  public:
53   // Records UKM metrics and reports them on destruction. The |source_id| is
54   // the ID of the WebContents document that the forms belong to.
55   PasswordFormMetricsRecorder(bool is_main_frame_secure,
56                               ukm::SourceId source_id,
57                               PrefService* pref_service);
58 
59   // ManagerAction - What does the PasswordFormManager do with this form? Either
60   // it fills it, or it doesn't. If it doesn't fill it, that's either
61   // because it has no match or it is disabled via the AUTOCOMPLETE=off
62   // attribute. Note that if we don't have an exact match, we still provide
63   // candidates that the user may end up choosing.
64   enum ManagerAction {
65     kManagerActionNone = 0,
66     kManagerActionAutofilled,
67     kManagerActionBlacklisted_Obsolete,
68     kManagerActionMax
69   };
70 
71   // Result - What happens to the form?
72   //
73   // These values are persisted to logs. Entries should not be renumbered and
74   // numeric values should never be reused.
75   //
76   // Needs to stay in sync with PasswordFormSubmissionResult in enums.xml.
77   enum class SubmitResult {
78     kNotSubmitted = 0,
79     kFailed = 1,
80     kPassed = 2,
81   };
82 
83   // Whether the password manager filled a credential on a form.
84   enum ManagerAutofillEvent {
85     // No credential existed that could be filled into a password form.
86     kManagerFillEventNoCredential = 0,
87     // A credential could have been autofilled into a password form but was not
88     // due to a policy. E.g. incognito mode requires a user interaction before
89     // filling can happen. PSL matches are not autofilled and also on password
90     // change forms we do not autofill.
91     kManagerFillEventBlockedOnInteraction,
92     // A credential was autofilled into a form.
93     kManagerFillEventAutofilled
94   };
95 
96   // What the form is used for. SubmittedFormType::kUnspecified is only set
97   // before the SetSubmittedFormType() is called, and should never be actually
98   // uploaded.
99   //
100   // These values are persisted to logs. Entries should not be renumbered and
101   // numeric values should never be reused.
102   //
103   // Needs to stay in sync with PasswordFormType in enums.xml.
104   enum class SubmittedFormType {
105     kLogin = 0,
106     kLoginNoUsername = 1,
107     kChangePasswordEnabled = 2,
108     kChangePasswordDisabled = 3,
109     kChangePasswordNoUsername = 4,
110     kSignup = 5,
111     kSignupNoUsername = 6,
112     kLoginAndSignup = 7,
113     kUnspecified = 8,
114     kCount = 9,
115   };
116 
117   // The reason why a password bubble was shown on the screen.
118   //
119   // These values are persisted to logs. Entries should not be renumbered and
120   // numeric values should never be reused.
121   //
122   // Needs to stay in sync with PasswordBubbleTrigger in enums.xml.
123   enum class BubbleTrigger {
124     kUnknown = 0,
125     // The password manager suggests the user to save a password and asks for
126     // confirmation.
127     kPasswordManagerSuggestionAutomatic = 1,
128     kPasswordManagerSuggestionManual = 2,
129     // The site asked the user to save a password via the credential management
130     // API.
131     kCredentialManagementAPIAutomatic = 3,
132     kCredentialManagementAPIManual = 4,
133   };
134 
135   // The reason why a password bubble was dismissed.
136   //
137   // These values are persisted to logs. Entries should not be renumbered and
138   // numeric values should never be reused.
139   //
140   // Needs to stay in sync with PasswordBubbleDismissalReason in enums.xml.
141   enum class BubbleDismissalReason {
142     kUnknown = 0,
143     kAccepted = 1,
144     kDeclined = 2,
145     kIgnored = 3
146   };
147 
148   // This enum is a designed to be able to collect all kinds of potentially
149   // interesting user interactions with sites and password manager UI in
150   // relation to a given form. In contrast to UserAction, it is intended to be
151   // extensible.
152   enum class DetailedUserAction {
153     // Interactions with password bubble.
154     kEditedUsernameInBubble = 100,
155     kSelectedDifferentPasswordInBubble = 101,
156     kTriggeredManualFallbackForSaving = 102,
157     kObsoleteTriggeredManualFallbackForUpdating = 103,  // unused
158 
159     // Interactions with form.
160     kCorrectedUsernameInForm = 200,
161   };
162 
163   // Indicator whether the user has seen a password generation popup and why.
164   //
165   // These values are persisted to logs. Entries should not be renumbered and
166   // numeric values should never be reused.
167   //
168   // Needs to stay in sync with PasswordGenerationPopupShown in enums.xml.
169   enum class PasswordGenerationPopupShown {
170     kNotShown = 0,
171     kShownAutomatically = 1,
172     kShownManually = 2,
173     kMaxValue = kShownManually,
174   };
175 
176   // Metric: PasswordGeneration.UserDecision
177   enum class GeneratedPasswordStatus {
178     // The generated password was accepted by the user.
179     kPasswordAccepted = 0,
180     // The generated password was edited by the user in the field in which
181     // it was filled after being accepted.
182     kPasswordEdited = 1,
183     // The generated password was deleted by the user from the field
184     // in which it was filled after being accepted.
185     kPasswordDeleted = 2,
186     kPasswordRejectedInDialogObsolete = 3,  // obsolete
187     kMaxValue = kPasswordRejectedInDialogObsolete
188   };
189 
190   // Represents form differences.
191   // 1.This is a bit mask, so new values must be powers of 2.
192   // 2.This is used for UMA, so no deletion, only adding at the end.
193   enum FormDataDifferences {
194     // Different number of fields.
195     kFieldsNumber = 1 << 0,
196     kRendererFieldIDs = 1 << 1,
197     kAutocompleteAttributes = 1 << 2,
198     kFormControlTypes = 1 << 3,
199     kMaxFormDifferencesValue = 1 << 4,
200   };
201 
202   // Used in UMA histogram, please do NOT reorder.
203   // Metric: "PasswordManager.FirstWaitForUsernameReason"
204   // This metric records why the browser instructs the renderer not to fill the
205   // credentials on page load but to wait for the user to confirm the credential
206   // to be filled. This decision is only recorded for the first time, the
207   // browser informs the renderer about credentials for a given form.
208   //
209   // Needs to stay in sync with PasswordManagerFirstWaitForUsernameReason in
210   // enums.xml.
211   enum class WaitForUsernameReason {
212     // Credentials may be filled on page load.
213     kDontWait = 0,
214     // User is browsing in incognito mode.
215     kIncognitoMode = 1,
216     // A credential exists for a PSL matched site but not for the current
217     // security origin.
218     kPublicSuffixMatch = 2,
219     // Form is suspected to be a password change form. (Only recorded for old
220     // form parser)
221     kFormNotGoodForFilling = 3,
222     // User is on a site with an insecure main frame origin.
223     kInsecureOrigin = 4,
224     // The Touch To Fill feature is enabled.
225     kTouchToFill = 5,
226     // Show suggestion on account selection feature is enabled.
227     kFoasFeature = 6,
228     // Re-authenticaion for filling passwords is required.
229     kReauthRequired = 7,
230     // Password is already filled
231     kPasswordPrefilled = 8,
232     kMaxValue = kPasswordPrefilled,
233   };
234 
235   // This metric records the user experience with the passwords filling. The
236   // first 4 buckets are ranging from the best (automatic) to the worst (the
237   // user has to type already saved password). Next 2 buckets showed the cases
238   // when it was impossible to help because the unknown credentials were
239   // submitted. The last bucket are strange cases, that the submitted form has
240   // nor user input, nor autofilled data in password fields.
241   enum class FillingAssistance {
242     // Credential fields were filled automatically.
243     kAutomatic = 0,
244     // Credential fields were filled with involving manual filling (but none
245     // required typing).
246     kManual = 1,
247     // Password was filled (automatically or manually), known username was
248     // typed.
249     kUsernameTypedPasswordFilled = 2,
250     // Known password was typed.
251     kKnownPasswordTyped = 3,
252     // Unknown password was typed while some credentials were stored.
253     kNewPasswordTypedWhileCredentialsExisted = 4,
254     // No saved credentials.
255     kNoSavedCredentials = 5,
256     // Neither user input nor filling.
257     kNoUserInputNoFillingInPasswordFields = 6,
258     // Domain is blacklisted and no other credentials exist.
259     kNoSavedCredentialsAndBlacklisted = 7,
260     // No credentials exist and the user has ignored the save bubble too often,
261     // meaning that they won't be asked to save credentials anymore.
262     kNoSavedCredentialsAndBlacklistedBySmartBubble = 8,
263     kMaxValue = kNoSavedCredentialsAndBlacklistedBySmartBubble,
264   };
265 
266   // Records which store(s) a filled password came from.
267   // These values are persisted to logs. Entries should not be renumbered and
268   // numeric values should never be reused.
269   enum class FillingSource {
270     kNotFilled = 0,
271     kFilledFromProfileStore = 1,
272     kFilledFromAccountStore = 2,
273     kFilledFromBothStores = 3,
274     kMaxValue = kFilledFromBothStores,
275   };
276 
277   // Records whether a password hash was saved or not on Chrome sign-in page.
278   enum class ChromeSignInPageHashSaved {
279     kPasswordTypedHashNotSaved = 0,
280     kHashSaved = 1,
281     kMaxValue = kHashSaved,
282   };
283 
284   // Records user actions when Chrome suggests usernames on a page which are
285   // considered to be username first flow.
286   enum class SavingOnUsernameFirstFlow {
287     kSaved = 0,
288     kSavedWithEditedUsername = 1,
289     kNotSaved = 2,
290     kMaxValue = kNotSaved,
291   };
292 
293   // Used in UMA histogram, please do NOT reorder.
294   // Metric: "PasswordManager.JavaScriptOnlyValueInSubmittedForm"
295   enum class JsOnlyInput {
296     kOnlyJsInputNoFocus = 0,
297     kOnlyJsInputWithFocus = 1,
298     kAutofillOrUserInput = 2,
299     kMaxValue = kAutofillOrUserInput,
300   };
301 
302   // Called if the user could generate a password for this form.
303   void MarkGenerationAvailable();
304 
305   // Stores the user action associated with a generated password.
306   void SetGeneratedPasswordStatus(GeneratedPasswordStatus status);
307 
308   // Stores the password manager action. During destruction the last
309   // set value will be logged.
310   void SetManagerAction(ManagerAction manager_action);
311 
312   // Call these if/when we know the form submission worked or failed.
313   // These routines are used to update internal statistics ("ActionsTaken").
314   void LogSubmitPassed();
315   void LogSubmitFailed();
316 
317   // This can be called multiple times in which case the last value is reported.
318   void SetPasswordGenerationPopupShown(bool generation_popup_was_shown,
319                                        bool is_manual_generation);
320 
321   // Call this once the submitted form type has been determined.
322   void SetSubmittedFormType(SubmittedFormType form_type);
323 
324   // Call this when a password is saved to indicate which path led to
325   // submission.
326   void SetSubmissionIndicatorEvent(
327       autofill::mojom::SubmissionIndicatorEvent event);
328 
329   // Records the event that a password bubble was shown.
330   void RecordPasswordBubbleShown(
331       metrics_util::CredentialSourceType credential_source_type,
332       metrics_util::UIDisplayDisposition display_disposition);
333 
334   // Records the dismissal of a password bubble.
335   void RecordUIDismissalReason(
336       metrics_util::UIDismissalReason ui_dismissal_reason);
337 
338   // Records that the password manager managed or failed to fill a form.
339   void RecordFillEvent(ManagerAutofillEvent event);
340 
341   // Records a DetailedUserAction UKM metric.
342   void RecordDetailedUserAction(DetailedUserAction action);
343 
344   // Hash algorithm for RecordFormSignature. Public for testing.
345   static int64_t HashFormSignature(autofill::FormSignature form_signature);
346 
347   // Records a low entropy hash of the form signature in order to be able to
348   // distinguish two forms on the same site.
349   void RecordFormSignature(autofill::FormSignature form_signature);
350 
351   // Records the readonly status encoded with parsing success after parsing for
352   // filling. The |value| is constructed as follows: The least significant bit
353   // says whether parsing succeeded (1) or not (0). The rest, shifted by one
354   // bit to the right is the FormDataParser::ReadonlyPasswordFields
355   // representation of the readonly status.
356   void RecordReadonlyWhenFilling(uint64_t value);
357 
358   // Records the readonly status encoded with parsing success after parsing for
359   // creating pending credentials. See RecordReadonlyWhenFilling for the meaning
360   // of |value|.
361   void RecordReadonlyWhenSaving(uint64_t value);
362 
363   // Records that Chrome noticed that it should show a manual fallback for
364   // saving.
365   void RecordShowManualFallbackForSaving(bool has_generated_password,
366                                          bool is_update);
367 
368   void RecordFormChangeBitmask(uint32_t bitmask);
369 
370   void RecordFirstFillingResult(int32_t result);
371   void RecordFirstWaitForUsernameReason(WaitForUsernameReason reason);
372 
373   // Calculates FillingAssistance metric for |submitted_form|. The result is
374   // stored in |filling_assistance_| and recorded in the destructor in case when
375   // the successful submission is detected.
376   void CalculateFillingAssistanceMetric(
377       const autofill::FormData& submitted_form,
378       const std::set<std::pair<base::string16, PasswordForm::Store>>&
379           saved_usernames,
380       const std::set<std::pair<base::string16, PasswordForm::Store>>&
381           saved_passwords,
382       bool is_blacklisted,
383       const std::vector<InteractionsStats>& interactions_stats,
384       metrics_util::PasswordAccountStorageUsageLevel
385           account_storage_usage_level);
386 
387   // Calculates whether all field values in |submitted_form| came from
388   // JavaScript. The result is stored in |js_only_input_|.
389   void CalculateJsOnlyInput(const autofill::FormData& submitted_form);
390 
set_user_typed_password_on_chrome_sign_in_page()391   void set_user_typed_password_on_chrome_sign_in_page() {
392     user_typed_password_on_chrome_sign_in_page_ = true;
393   }
394 
set_password_hash_saved_on_chrome_sing_in_page()395   void set_password_hash_saved_on_chrome_sing_in_page() {
396     password_hash_saved_on_chrome_sing_in_page_ = true;
397   }
398 
set_possible_username_used(bool value)399   void set_possible_username_used(bool value) {
400     possible_username_used_ = value;
401   }
402 
set_username_updated_in_bubble(bool value)403   void set_username_updated_in_bubble(bool value) {
404     username_updated_in_bubble_ = value;
405   }
406 
set_clock_for_testing(base::Clock * clock)407   void set_clock_for_testing(base::Clock* clock) { clock_ = clock; }
408 
409  private:
410   friend class base::RefCounted<PasswordFormMetricsRecorder>;
411 
412   // Enum to track which password bubble is currently being displayed.
413   enum class CurrentBubbleOfInterest {
414     // This covers the cases that no password bubble is currently being
415     // displayed or the one displayed is none of the interesting cases.
416     kNone,
417     // The user is currently seeing a password save bubble.
418     kSaveBubble,
419     // The user is currently seeing a password update bubble.
420     kUpdateBubble,
421   };
422 
423   // Destructor reports a couple of UMA metrics as well as calls
424   // RecordUkmMetric.
425   ~PasswordFormMetricsRecorder();
426 
427   // Not owned. Points to base::DefaultClock::GetInstance() by default, but can
428   // be overridden for testing.
429   base::Clock* clock_;
430 
431   // True if the main frame's committed URL, at the time PasswordFormManager
432   // was created, is secure.
433   const bool is_main_frame_secure_;
434 
435   // Whether the user can choose to generate a password for this form.
436   bool generation_available_ = false;
437 
438   // Contains the generated password's status, which resulted from a user
439   // action.
440   base::Optional<GeneratedPasswordStatus> generated_password_status_;
441 
442   // Tracks which bubble is currently being displayed to the user.
443   CurrentBubbleOfInterest current_bubble_ = CurrentBubbleOfInterest::kNone;
444 
445   // Whether the user was shown a prompt to update a password.
446   bool update_prompt_shown_ = false;
447 
448   // Whether the user was shown a prompt to save a new credential.
449   bool save_prompt_shown_ = false;
450 
451   // Whether the user was shown a password generation popup and why.
452   // Only reportet when a popup was shown.
453   PasswordGenerationPopupShown password_generation_popup_shown_ =
454       PasswordGenerationPopupShown::kNotShown;
455 
456   // These three fields record the "ActionsTaken" by the browser and
457   // the user with this form, and the result. They are combined and
458   // recorded in UMA when the PasswordFormMetricsRecorder is destroyed.
459   ManagerAction manager_action_ = kManagerActionNone;
460   SubmitResult submit_result_ = SubmitResult::kNotSubmitted;
461 
462   // Form type of the form that the PasswordFormManager is managing. Set after
463   // submission as the classification of the form can change depending on what
464   // data the user has entered.
465   SubmittedFormType submitted_form_type_ = SubmittedFormType::kUnspecified;
466 
467   // The UKM SourceId of the document the form belongs to.
468   ukm::SourceId source_id_;
469 
470   // Holds URL keyed metrics (UKMs) to be recorded on destruction.
471   ukm::builders::PasswordForm ukm_entry_builder_;
472 
473   PrefService* const pref_service_;
474 
475   // Counter for DetailedUserActions observed during the lifetime of a
476   // PasswordFormManager. Reported upon destruction.
477   std::map<DetailedUserAction, int64_t> detailed_user_actions_counts_;
478 
479   // Bitmap of whether and why a manual fallback for saving was shown:
480   // 1 = the fallback was shown.
481   // 2 = the password was generated.
482   // 4 = this was an update prompt.
483   base::Optional<uint32_t> showed_manual_fallback_for_saving_;
484 
485   base::Optional<uint32_t> form_changes_bitmask_;
486 
487   bool recorded_first_filling_result_ = false;
488 
489   bool recorded_wait_for_username_reason_ = false;
490 
491   bool user_typed_password_on_chrome_sign_in_page_ = false;
492   bool password_hash_saved_on_chrome_sing_in_page_ = false;
493 
494   base::Optional<FillingAssistance> filling_assistance_;
495   base::Optional<FillingSource> filling_source_;
496   base::Optional<metrics_util::PasswordAccountStorageUsageLevel>
497       account_storage_usage_level_;
498 
499   bool possible_username_used_ = false;
500   bool username_updated_in_bubble_ = false;
501 
502   base::Optional<JsOnlyInput> js_only_input_;
503 
504   bool is_mixed_content_form_ = false;
505 
506   DISALLOW_COPY_AND_ASSIGN(PasswordFormMetricsRecorder);
507 };
508 
509 }  // namespace password_manager
510 
511 #endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_PASSWORD_FORM_METRICS_RECORDER_H_
512