Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(431)

Unified Diff: components/password_manager/core/browser/password_form_manager.cc

Issue 1050903002: Postpone check if password form is loaded from store (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Comments fix Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/password_manager/core/browser/password_form_manager.cc
diff --git a/components/password_manager/core/browser/password_form_manager.cc b/components/password_manager/core/browser/password_form_manager.cc
index 8f2305531eea7e9b3dbbe966ab35076a33f987d7..64ade29c67b883917d197e43fe1fa73a289c97d1 100644
--- a/components/password_manager/core/browser/password_form_manager.cc
+++ b/components/password_manager/core/browser/password_form_manager.cc
@@ -92,6 +92,9 @@ PasswordFormManager::PasswordFormManager(
bool ssl_valid)
: best_matches_deleter_(&best_matches_),
observed_form_(CopyAndModifySSLValidity(observed_form, ssl_valid)),
+ provisionally_saved_form_(nullptr),
+ other_possible_username_action_(
+ PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES),
is_new_login_(true),
has_generated_password_(false),
password_manager_(password_manager),
@@ -258,7 +261,7 @@ bool PasswordFormManager::HasGeneratedPassword() const {
}
bool PasswordFormManager::HasValidPasswordForm() const {
- DCHECK_EQ(state_, POST_MATCHING_PHASE);
+ DCHECK(state_ == MATCHING_PHASE || state_ == POST_MATCHING_PHASE) << state_;
// Non-HTML password forms (primarily HTTP and FTP autentication)
// do not contain username_element and password_element values.
if (observed_form_.scheme != PasswordForm::SCHEME_HTML)
@@ -270,120 +273,13 @@ bool PasswordFormManager::HasValidPasswordForm() const {
void PasswordFormManager::ProvisionallySave(
const PasswordForm& credentials,
OtherPossibleUsernamesAction action) {
- DCHECK_EQ(state_, POST_MATCHING_PHASE);
+ DCHECK(state_ == MATCHING_PHASE || state_ == POST_MATCHING_PHASE) << state_;
DCHECK_NE(RESULT_NO_MATCH, DoesManage(credentials));
+ provisionally_saved_form_.reset(new PasswordForm(credentials));
+ other_possible_username_action_ = action;
- base::string16 password_to_save(PasswordToSave(credentials));
-
- // Make sure the important fields stay the same as the initially observed or
- // autofilled ones, as they may have changed if the user experienced a login
- // failure.
- // Look for these credentials in the list containing auto-fill entries.
- PasswordFormMap::const_iterator it =
- best_matches_.find(credentials.username_value);
- if (it != best_matches_.end()) {
- // The user signed in with a login we autofilled.
- pending_credentials_ = *it->second;
- bool password_changed =
- pending_credentials_.password_value != password_to_save;
- if (IsPendingCredentialsPublicSuffixMatch()) {
- // If the autofilled credentials were only a PSL match, store a copy with
- // the current origin and signon realm. This ensures that on the next
- // visit, a precise match is found.
- is_new_login_ = true;
- user_action_ = password_changed ? kUserActionChoosePslMatch
- : kUserActionOverridePassword;
-
- // Update credential to reflect that it has been used for submission.
- // If this isn't updated, then password generation uploads are off for
- // sites where PSL matching is required to fill the login form, as two
- // PASSWORD votes are uploaded per saved password instead of one.
- //
- // TODO(gcasto): It would be nice if other state were shared such that if
- // say a password was updated on one match it would update on all related
- // passwords. This is a much larger change.
- UpdateMetadataForUsage(pending_credentials_);
-
- // Normally, the copy of the PSL matched credentials, adapted for the
- // current domain, is saved automatically without asking the user, because
- // the copy likely represents the same account, i.e., the one for which
- // the user already agreed to store a password.
- //
- // However, if the user changes the suggested password, it might indicate
- // that the autofilled credentials and |credentials| actually correspond
- // to two different accounts (see http://crbug.com/385619). In that case
- // the user should be asked again before saving the password. This is
- // ensured by clearing |original_signon_realm| on |pending_credentials_|,
- // which unmarks it as a PSL match.
- //
- // There is still the edge case when the autofilled credentials represent
- // the same account as |credentials| but the stored password was out of
- // date. In that case, the user just had to manually enter the new
- // password, which is now in |credentials|. The best thing would be to
- // save automatically, and also update the original credentials. However,
- // we have no way to tell if this is the case. This will likely happen
- // infrequently, and the inconvenience put on the user by asking them is
- // not significant, so we are fine with asking here again.
- if (password_changed) {
- pending_credentials_.original_signon_realm.clear();
- DCHECK(!IsPendingCredentialsPublicSuffixMatch());
- }
- } else { // Not a PSL match.
- is_new_login_ = false;
- if (password_changed)
- user_action_ = kUserActionOverridePassword;
- }
- } else if (action == ALLOW_OTHER_POSSIBLE_USERNAMES &&
- UpdatePendingCredentialsIfOtherPossibleUsername(
- credentials.username_value)) {
- // |pending_credentials_| is now set. Note we don't update
- // |pending_credentials_.username_value| to |credentials.username_value|
- // yet because we need to keep the original username to modify the stored
- // credential.
- selected_username_ = credentials.username_value;
- is_new_login_ = false;
- } else {
- // User typed in a new, unknown username.
- user_action_ = kUserActionOverrideUsernameAndPassword;
- pending_credentials_ = observed_form_;
- if (credentials.was_parsed_using_autofill_predictions)
- pending_credentials_.username_element = credentials.username_element;
- pending_credentials_.username_value = credentials.username_value;
- pending_credentials_.other_possible_usernames =
- credentials.other_possible_usernames;
-
- // The password value will be filled in later, remove any garbage for now.
- pending_credentials_.password_value.clear();
- pending_credentials_.new_password_value.clear();
-
- // If this was a sign-up or change password form, the names of the elements
- // are likely different than those on a login form, so do not bother saving
- // them. We will fill them with meaningful values in UpdateLogin() when the
- // user goes onto a real login form for the first time.
- if (!credentials.new_password_element.empty()) {
- pending_credentials_.password_element.clear();
- pending_credentials_.new_password_element.clear();
- }
- }
-
- pending_credentials_.action = credentials.action;
- // If the user selected credentials we autofilled from a PasswordForm
- // that contained no action URL (IE6/7 imported passwords, for example),
- // bless it with the action URL from the observed form. See bug 1107719.
- if (pending_credentials_.action.is_empty())
- pending_credentials_.action = observed_form_.action;
-
- pending_credentials_.password_value = password_to_save;
- pending_credentials_.preferred = credentials.preferred;
-
- if (user_action_ == kUserActionOverridePassword &&
- pending_credentials_.type == PasswordForm::TYPE_GENERATED &&
- !has_generated_password_) {
- LogPasswordGenerationSubmissionEvent(PASSWORD_OVERRIDDEN);
- }
-
- if (has_generated_password_)
- pending_credentials_.type = PasswordForm::TYPE_GENERATED;
+ if (HasCompletedMatching())
+ CreatePendingCredentials();
}
void PasswordFormManager::Save() {
@@ -623,6 +519,11 @@ void PasswordFormManager::OnGetPasswordStoreResults(
OnRequestDone(results.Pass());
state_ = POST_MATCHING_PHASE;
+ // If password store was slow and provisionally saved form is already here
+ // then create pending credentials (see http://crbug.com/470322).
+ if (provisionally_saved_form_)
+ CreatePendingCredentials();
battre 2017/07/13 13:30:51 Do you remember why you decided not to return here
vabr (Chromium) 2017/07/13 14:01:26 The PasswordFormManager still needs to ensure save
+
if (manager_action_ != kManagerActionBlacklisted) {
for (auto const& driver : drivers_)
ProcessFrame(driver);
@@ -869,6 +770,128 @@ bool PasswordFormManager::UploadPasswordForm(
return success;
}
+void PasswordFormManager::CreatePendingCredentials() {
+ DCHECK(provisionally_saved_form_);
+ base::string16 password_to_save(PasswordToSave(*provisionally_saved_form_));
+
+ // Make sure the important fields stay the same as the initially observed or
+ // autofilled ones, as they may have changed if the user experienced a login
+ // failure.
+ // Look for these credentials in the list containing auto-fill entries.
+ PasswordFormMap::const_iterator it =
+ best_matches_.find(provisionally_saved_form_->username_value);
+ if (it != best_matches_.end()) {
+ // The user signed in with a login we autofilled.
+ pending_credentials_ = *it->second;
+ bool password_changed =
+ pending_credentials_.password_value != password_to_save;
+ if (IsPendingCredentialsPublicSuffixMatch()) {
+ // If the autofilled credentials were only a PSL match, store a copy with
+ // the current origin and signon realm. This ensures that on the next
+ // visit, a precise match is found.
+ is_new_login_ = true;
+ user_action_ = password_changed ? kUserActionChoosePslMatch
+ : kUserActionOverridePassword;
+
+ // Update credential to reflect that it has been used for submission.
+ // If this isn't updated, then password generation uploads are off for
+ // sites where PSL matching is required to fill the login form, as two
+ // PASSWORD votes are uploaded per saved password instead of one.
+ //
+ // TODO(gcasto): It would be nice if other state were shared such that if
+ // say a password was updated on one match it would update on all related
+ // passwords. This is a much larger change.
+ UpdateMetadataForUsage(pending_credentials_);
+
+ // Normally, the copy of the PSL matched credentials, adapted for the
+ // current domain, is saved automatically without asking the user, because
+ // the copy likely represents the same account, i.e., the one for which
+ // the user already agreed to store a password.
+ //
+ // However, if the user changes the suggested password, it might indicate
+ // that the autofilled credentials and |provisionally_saved_form_|
+ // actually correspond to two different accounts (see
+ // http://crbug.com/385619). In that case the user should be asked again
+ // before saving the password. This is ensured by clearing
+ // |original_signon_realm| on |pending_credentials_|, which unmarks it as
+ // a PSL match.
+ //
+ // There is still the edge case when the autofilled credentials represent
+ // the same account as |provisionally_saved_form_| but the stored password
+ // was out of date. In that case, the user just had to manually enter the
+ // new password, which is now in |provisionally_saved_form_|. The best
+ // thing would be to save automatically, and also update the original
+ // credentials. However, we have no way to tell if this is the case.
+ // This will likely happen infrequently, and the inconvenience put on the
+ // user by asking them is not significant, so we are fine with asking
+ // here again.
+ if (password_changed) {
+ pending_credentials_.original_signon_realm.clear();
+ DCHECK(!IsPendingCredentialsPublicSuffixMatch());
+ }
+ } else { // Not a PSL match.
+ is_new_login_ = false;
+ if (password_changed)
+ user_action_ = kUserActionOverridePassword;
+ }
+ } else if (other_possible_username_action_ ==
+ ALLOW_OTHER_POSSIBLE_USERNAMES &&
+ UpdatePendingCredentialsIfOtherPossibleUsername(
+ provisionally_saved_form_->username_value)) {
+ // |pending_credentials_| is now set. Note we don't update
+ // |pending_credentials_.username_value| to |credentials.username_value|
+ // yet because we need to keep the original username to modify the stored
+ // credential.
+ selected_username_ = provisionally_saved_form_->username_value;
+ is_new_login_ = false;
+ } else {
+ // User typed in a new, unknown username.
+ user_action_ = kUserActionOverrideUsernameAndPassword;
+ pending_credentials_ = observed_form_;
+ if (provisionally_saved_form_->was_parsed_using_autofill_predictions)
+ pending_credentials_.username_element =
+ provisionally_saved_form_->username_element;
+ pending_credentials_.username_value =
+ provisionally_saved_form_->username_value;
+ pending_credentials_.other_possible_usernames =
+ provisionally_saved_form_->other_possible_usernames;
+
+ // The password value will be filled in later, remove any garbage for now.
+ pending_credentials_.password_value.clear();
+ pending_credentials_.new_password_value.clear();
+
+ // If this was a sign-up or change password form, the names of the elements
+ // are likely different than those on a login form, so do not bother saving
+ // them. We will fill them with meaningful values in UpdateLogin() when the
+ // user goes onto a real login form for the first time.
+ if (!provisionally_saved_form_->new_password_element.empty()) {
+ pending_credentials_.password_element.clear();
+ pending_credentials_.new_password_element.clear();
+ }
+ }
+
+ pending_credentials_.action = provisionally_saved_form_->action;
+ // If the user selected credentials we autofilled from a PasswordForm
+ // that contained no action URL (IE6/7 imported passwords, for example),
+ // bless it with the action URL from the observed form. See bug 1107719.
+ if (pending_credentials_.action.is_empty())
+ pending_credentials_.action = observed_form_.action;
+
+ pending_credentials_.password_value = password_to_save;
+ pending_credentials_.preferred = provisionally_saved_form_->preferred;
+
+ if (user_action_ == kUserActionOverridePassword &&
+ pending_credentials_.type == PasswordForm::TYPE_GENERATED &&
+ !has_generated_password_) {
+ LogPasswordGenerationSubmissionEvent(PASSWORD_OVERRIDDEN);
+ }
+
+ if (has_generated_password_)
+ pending_credentials_.type = PasswordForm::TYPE_GENERATED;
+
+ provisionally_saved_form_.reset();
+}
+
int PasswordFormManager::ScoreResult(const PasswordForm& candidate) const {
DCHECK_EQ(state_, MATCHING_PHASE);
// For scoring of candidate login data:

Powered by Google App Engine
This is Rietveld 408576698