File: votes_uploader.h

package info (click to toggle)
chromium 139.0.7258.127-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,122,156 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 (448 lines) | stat: -rw-r--r-- 19,716 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
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_VOTES_UPLOADER_H_
#define COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_VOTES_UPLOADER_H_

#include <map>
#include <optional>
#include <string>
#include <vector>

#include "base/memory/raw_ptr.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_field.h"
#include "components/autofill/core/browser/crowdsourcing/autofill_crowdsourcing_encoding.h"
#include "components/autofill/core/browser/field_types.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/proto/server.pb.h"
#include "components/autofill/core/common/signatures.h"
#include "components/autofill/core/common/unique_ids.h"
#include "components/password_manager/core/browser/form_parsing/password_field_prediction.h"
#include "components/password_manager/core/browser/password_form.h"

namespace autofill {
class AutofillField;
class FormData;
class FormStructure;
}  // namespace autofill

namespace password_manager {

class PasswordManagerClient;

// Password attributes (whether a password has special symbols, numeric, etc.)
enum class PasswordAttribute {
  kHasLetter,
  kHasSpecialSymbol,
  kPasswordAttributesCount
};

// Map from a field's renderer id to a field type.
using FieldTypeMap = std::map<autofill::FieldRendererId, autofill::FieldType>;
// A map from field's renderer id to a vote type (e.g. CREDENTIALS_REUSED).
using VoteTypeMap = std::map<autofill::FieldRendererId,
                             autofill::AutofillUploadContents::Field::VoteType>;

using PasswordFormHadMatchingUsername =
    base::StrongAlias<class PasswordFormHadMatchingUsernameTag, bool>;

// Contains information for sending a SINGLE_USERNAME vote.
struct SingleUsernameVoteData {
  SingleUsernameVoteData();
  SingleUsernameVoteData(
      autofill::FieldRendererId renderer_id,
      const std::u16string& username_value,
      const FormPredictions& form_predictions,
      const base::span<const PasswordForm>& stored_credentials,
      PasswordFormHadMatchingUsername password_form_had_matching_username);
  SingleUsernameVoteData(const SingleUsernameVoteData&);
  SingleUsernameVoteData& operator=(const SingleUsernameVoteData&);
  SingleUsernameVoteData(SingleUsernameVoteData&& other);
  ~SingleUsernameVoteData();

  // Renderer id of an input element, for which the SINGLE_USERNAME vote will be
  // sent.
  autofill::FieldRendererId renderer_id;

  // Value of the single username candidate field.
  std::u16string username_candidate_value;

  // Predictions for the form which contains a field with |renderer_id|.
  FormPredictions form_predictions;

  // Information about username edits in a save/update prompt. Not calculated on
  // Android, because it's not possible to edit credentials in prompts on
  // Android.
  autofill::AutofillUploadContents::SingleUsernamePromptEdit prompt_edit;

  // True if the password form has username field whose value matches username
  // value in the single username form.
  // TODO: crbug.com/1468297 - `password_form_had_matching_username` in
  // `VotesUploader` is used for UMA metrics. The variable can be removed once
  // the metrics are not needed anymore.
  PasswordFormHadMatchingUsername password_form_had_matching_username;

  // If set to true, sends `SingleUsernameVoteType::IN_FORM_OVERRULE` vote. Read
  // more about this vote type in proto file.
  bool is_form_overrule;
};

struct PasswordAttributesMetadata {
  // The vote about password attributes (e.g. whether the password has a
  // numeric character).
  std::pair<PasswordAttribute, bool> password_attributes_vote;

  // If `password_attribute_vote` contains (kHasSpecialSymbol, true), this
  // field contains noisified information about a special symbol in a
  // user-created password stored as ASCII code. The default value of 0
  // indicates that no symbol was set.
  int password_symbol_vote = 0;

  // Noisified password length for crowdsourcing.
  int password_length_vote = 0;
};

// This class manages vote uploads for password forms.
class VotesUploader {
 public:
  // The states a changed username can be in.
  enum class UsernameChangeState {
    // The user did not change the username.
    kUnchanged,
    // The user changed the username to a different value that was present in
    // the submitted form. For example, via the dropdown in the Desktop bubble.
    kChangedToKnownValue,
    // The user changed the username to a different value that was not present
    // in the submitted form. For example, via the text field in the Desktop
    // bubble.
    kChangedToUnknownValue,
  };

  // Whether two existing single username detection mechanisms (UFF and FPF)
  // have data, overlapping or not. Used for UMA recording, must be in sync with
  // SingleUsernameVoteDataAvailability in "tools/metrics/histograms/enums.xml".
  enum class SingleUsernameVoteDataAvailability {
    // No data available for both UFF and FPF voting.
    kNone = 0,
    // Data only available for single username voting.
    kUsernameFirstOnly = 1,
    // Data only available for forgot password voting.
    kForgotPasswordOnly = 2,
    // Data available for both UFF and FPF voting, but these votes are for
    // different fields.
    kBothNoOverlap = 3,
    // Data available for both UFF and FPF voting, forgot password voting
    // data contains data for UFF voting.
    kBothWithOverlap = 4,
    kMaxValue = kBothWithOverlap
  };

  VotesUploader(PasswordManagerClient* client,
                bool is_possible_change_password_form);
  VotesUploader(const VotesUploader& other);
  ~VotesUploader();

  // Send appropriate votes based on what is currently being saved.
  void SendVotesOnSave(const autofill::FormData& observed,
                       const PasswordForm& submitted_form,
                       const base::span<const PasswordForm>& best_matches,
                       PasswordForm* pending_credentials);

  // Check to see if |pending| corresponds to an account creation form. If we
  // think that it does, we label it as such and upload this state to the
  // Autofill server to vote for the correct username field, and also so that
  // we will trigger password generation in the future. This function will
  // update generation_upload_status of |pending| if an upload is performed.
  void SendVoteOnCredentialsReuse(const autofill::FormData& observed,
                                  const PasswordForm& submitted_form,
                                  PasswordForm* pending);

  // Tries to set all votes (e.g. autofill field types, generation vote) to
  // a |FormStructure| and upload it to the server. Returns true on success.
  bool UploadPasswordVote(
      const PasswordForm& form_to_upload,
      const PasswordForm& submitted_form,
      const autofill::FieldType password_type,
      std::optional<autofill::FormSignature> login_form_signature);

  // Sends USERNAME and PASSWORD votes, when a credential is used to login for
  // the first time. |form_to_upload| is the submitted login form.
  void UploadFirstLoginVotes(const base::span<const PasswordForm>& best_matches,
                             const PasswordForm& pending_credentials,
                             const PasswordForm& form_to_upload);

  // Searches for |username| in |all_alternative_usernames| of |matches|. If the
  // username value is found in |all_alternative_usernames| and the password
  // value of the match is equal to |password|, the match is saved to
  // |username_correction_vote_| and the method returns true.
  bool FindCorrectedUsernameElement(base::span<const PasswordForm> matches,
                                    const std::u16string& username,
                                    const std::u16string& password);

  // Returns a password attributes vote based on `password_value` . Declared as
  // public for testing.
  std::optional<PasswordAttributesMetadata> GeneratePasswordAttributesMetadata(
      const std::u16string& password_value);

  // Stores the |renderer_id| and |values| of the fields in
  // |observed_form| to |initial_field_values_|.
  void StoreInitialFieldValues(const autofill::FormData& observed_form);

  // Sets the low-entropy hash value of the values stored in |initial_values_|
  // for the detected |username_element_renderer_id| field to the corresponding
  // field in |form_structure|.
  void SetInitialHashValueOfUsernameField(
      autofill::FieldRendererId username_element_renderer_id,
      const autofill::FormStructure& form_structure,
      autofill::EncodeUploadRequestOptions& options);

  // Sends single username vote if |single_username_vote_data_| or
  // |forgot_password_vote_data_| is set.
  // The vote sent is either SINGLE_USERNAME (if the user saved the credential
  // with the username cached in |single_username_vote_data|), or
  // SINGLE_USERNAME_FORGOT_PASSWORD (if the user saved the credential
  // with the username cached in |forgot_password_vote_data|), or NOT_USERNAME
  // (if the saved username contradicts cached potential usernames).
  // TODO (crbug.com/959776): Have a single point in code that calls this
  // method.
  void MaybeSendSingleUsernameVotes();

  // Calculate whether the username value was edited in a prompt based on
  // suggested and saved username values and whether it confirms or
  // contradicts the data about potential single username.
  // `all_alternative_usernames` stores text fields inside the password form
  // that might be a username.
  void CalculateUsernamePromptEditState(
      const std::u16string& saved_username,
      const AlternativeElementVector& all_alternative_usernames);

  // Cache the vote data for a form that is likely a forgot password form
  // (a form, into which the user inputs their username to start the
  // password recovery process).
  void AddForgotPasswordVoteData(const SingleUsernameVoteData& vote_data);

  void set_generation_popup_was_shown(bool generation_popup_was_shown) {
    generation_popup_was_shown_ = generation_popup_was_shown;
  }

  void set_is_manual_generation(bool is_manual_generation) {
    is_manual_generation_ = is_manual_generation;
  }

  void set_generation_element(autofill::FieldRendererId generation_element) {
    generation_element_ = generation_element;
  }

  void set_username_change_state(UsernameChangeState username_change_state) {
    username_change_state_ = username_change_state;
  }

  bool passwords_revealed_vote() const { return has_passwords_revealed_vote_; }
  void set_has_passwords_revealed_vote(bool has_passwords_revealed_vote) {
    has_passwords_revealed_vote_ = has_passwords_revealed_vote;
  }

  void set_password_overridden(bool password_overridden) {
    password_overridden_ = password_overridden;
  }

  void set_has_generated_password(bool has_generated_password) {
    has_generated_password_ = has_generated_password;
  }

  bool generated_password_changed() const {
    return generated_password_changed_;
  }

  void set_generated_password_changed(bool generated_password_changed) {
    generated_password_changed_ = generated_password_changed;
  }

  void clear_single_username_votes_data() {
    single_username_votes_data_.clear();
  }

  void add_single_username_vote_data(const SingleUsernameVoteData& data) {
    single_username_votes_data_.push_back(data);
  }

  void set_suggested_username(const std::u16string& suggested_username) {
    suggested_username_ = suggested_username;
  }

  void set_should_send_username_first_flow_votes(bool value) {
    should_send_username_first_flow_votes_ = value;
  }

#if defined(UNIT_TEST)
  const std::u16string& suggested_username() const {
    return suggested_username_;
  }
#endif

 private:
  // The outcome of the form classifier.
  enum FormClassifierOutcome {
    kNoOutcome,
    kNoGenerationElement,
    kFoundGenerationElement
  };

  // Adds a vote on password generation usage to |form_structure|.
  void AddGeneratedVote(autofill::FormStructure& form_structure,
                        autofill::EncodeUploadRequestOptions& options);

  // Sets the known-value flag for each field, indicating that the field
  // contained a previously stored credential on submission.
  void SetKnownValueFlag(const PasswordForm& pending_credentials,
                         const base::span<const PasswordForm>& best_matches,
                         autofill::FormStructure* form_to_upload);

  // Searches for |username| in |all_alternative_usernames| of |match|. If the
  // username value is found, the match is saved to |username_correction_vote_|
  // and the function returns true.
  bool FindUsernameInOtherAlternativeUsernames(const PasswordForm& match,
                                               const std::u16string& username);

  // Wrapper around `autofill::EncodeUploadRequest`. Given the form, returns the
  // information that needs to be sent to the Autofill server.
  std::vector<autofill::AutofillUploadContents> EncodeUploadRequest(
      autofill::FormStructure& form,
      const autofill::EncodeUploadRequestOptions& options,
      std::optional<PasswordAttributesMetadata> password_attributes,
      bool should_set_passwords_were_revealed);

  // Wrapper around `AutofillCrowdsourcingManager::StartUploadRequest`. Returns
  // `true` if the vote is sent, `false` otherwise.
  bool SendUploadRequest(
      autofill::FormStructure& form_to_upload,
      const autofill::EncodeUploadRequestOptions& options,
      std::optional<PasswordAttributesMetadata> password_attributes,
      bool should_set_passwords_were_revealed);

  // On username first and forgot password flows votes are uploaded both for the
  // single username form and for the single password form. This method sets the
  // data needed to upload vote on the username form. The vote is based on the
  // user interaction with the save prompt (i.e. whether the suggested value was
  // actually saved).
  bool SetSingleUsernameVoteOnUsernameForm(
      autofill::AutofillField* field,
      const SingleUsernameVoteData& single_username,
      autofill::EncodeUploadRequestOptions& options,
      autofill::FormSignature form_signature,
      autofill::IsMostRecentSingleUsernameCandidate
          is_most_recent_single_username_candidate,
      bool is_forgot_password_vote);

  // Returns whether `IN_FORM_OVERRULE` vote should be sent. `IN_FORM_OVERRULE`
  // signal can be either positive or negative. If positive (`autofill_type` is
  // `SINGLE_USERNAME`), votes signal that user was prompted with a Save/Update
  // bubble with a username value found inside the password form and edited it
  // to one of the values that was found outside of the password form. If
  // negative (`autofill_type` is `NOT_USERNAME`), user was prompted with a
  // username value outside the password form and edited it to one of the values
  // that is found inside the password form.
  bool CalculateInFormOverrule(
      const std::u16string& saved_username,
      const std::u16string& potential_username,
      const AlternativeElementVector& all_alternative_usernames);

  // Calculates whether the |saved_username| (the value actually saved in the
  // Password Manager) confirms or contradicts |potential_username| (Password
  // Manager's guess based on preceding text fields that the user has interacted
  // with).
  autofill::AutofillUploadContents::SingleUsernamePromptEdit
  CalculateUsernamePromptEdit(const std::u16string& saved_username,
                              const std::u16string& potential_username);

  // Attempts to send a vote for a single username form.
  // `is_most_recent_single_username_candidate` specifies whether the single
  // username is the most recent field outside of the password form that was
  // modified by the user. Set to `std::nullopt` if vote is on a forgot
  // password form.
  // `is_forgot_password_form` specifies whether the form is considered to be a
  // part of a username first or a forgot password flow:
  // 1) When it's true, SINGLE_USERNAME_FORGOT_PASSWORD & NOT_USERNAME can be
  // sent.
  // 2) When it's false, SINGLE_USERNAME & NOT_USERNAME votes can be sent.
  // Returns true if the vote is sent.
  bool MaybeSendSingleUsernameVote(
      const SingleUsernameVoteData& single_username,
      const FormPredictions& predictions,
      autofill::IsMostRecentSingleUsernameCandidate
          is_most_recent_single_username_candidate,
      bool is_forgot_password_vote);

  // The client which implements embedder-specific PasswordManager operations.
  raw_ptr<PasswordManagerClient> client_ = nullptr;

  // Whether generation popup was shown at least once.
  bool generation_popup_was_shown_ = false;

  // Whether password generation was manually triggered.
  bool is_manual_generation_ = false;

  // A password field that is used for generation.
  autofill::FieldRendererId generation_element_;

  // Captures whether the user changed the username to a known value, an unknown
  // value, or didn't change the username at all.
  UsernameChangeState username_change_state_ = UsernameChangeState::kUnchanged;

  // If the user typed username that doesn't match any saved credentials, but
  // matches an entry from `all_alternative_usernames` of a saved credential,
  // `username_correction_vote_` stores the credential with matched username.
  // The matched credential is copied to `username_correction_vote_`, but
  // `username_correction_vote_.username_element` is set to the name of the
  // field where the matched username was found.
  std::optional<PasswordForm> username_correction_vote_;

  // Whether the password values have been shown to the user on the save prompt.
  bool has_passwords_revealed_vote_ = false;

  // Whether the saved password was overridden.
  bool password_overridden_ = false;

  // True if the observed form of owning PasswordFormManager is considered to be
  // change password form.
  bool is_possible_change_password_form_ = false;

  // Whether this form has an auto generated password.
  bool has_generated_password_ = false;

  // Whether this form has a generated password changed by user.
  bool generated_password_changed_ = false;

  // Maps a unique renderer ID to the initial value of the fields of an
  // observed form.
  std::map<autofill::FieldRendererId, std::u16string> initial_values_;

  // The data for voting on potential single username form for the username
  // first flow. Populated when the password form, that follows single username
  // form, is submitted.
  std::vector<SingleUsernameVoteData> single_username_votes_data_;

  // If set to true, Username First Flow was detected and a vote on the
  // candidate field(s) should be sent. Used only in Username First Flow, not
  // used in Forgot Password Form.
  bool should_send_username_first_flow_votes_ = false;

  // The username that is suggested in a save/update prompt. The user might
  // modify it in the prompt before saving.
  std::u16string suggested_username_;

  // The data for voting on potential forgot password forms (forms, into
  // which the user inputs their username to start the password recovery
  // process). These forms do not contain password fields, so voting requires
  // the same information as for single username forms for username first flow.
  // Populated when the password reset form, that follows the forgot password
  // form, is submitted.
  std::map<autofill::FieldRendererId, SingleUsernameVoteData>
      forgot_password_vote_data_;
};

}  // namespace password_manager

#endif  // COMPONENTS_PASSWORD_MANAGER_CORE_BROWSER_VOTES_UPLOADER_H_