Home | History | Annotate | Download | only in password_manager
      1 // Copyright (c) 2012 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 #include "chrome/browser/password_manager/password_form_manager.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/metrics/histogram.h"
     10 #include "base/strings/string_split.h"
     11 #include "base/strings/string_util.h"
     12 #include "chrome/browser/password_manager/password_manager.h"
     13 #include "chrome/browser/password_manager/password_store.h"
     14 #include "chrome/browser/password_manager/password_store_factory.h"
     15 #include "chrome/browser/profiles/profile.h"
     16 #include "components/autofill/content/browser/autofill_driver_impl.h"
     17 #include "components/autofill/content/common/autofill_messages.h"
     18 #include "components/autofill/core/browser/form_structure.h"
     19 #include "components/autofill/core/browser/validation.h"
     20 #include "components/autofill/core/common/password_form.h"
     21 #include "content/public/browser/render_view_host.h"
     22 #include "content/public/browser/web_contents.h"
     23 
     24 using autofill::FormStructure;
     25 using autofill::PasswordForm;
     26 using autofill::PasswordFormMap;
     27 using base::Time;
     28 
     29 PasswordFormManager::PasswordFormManager(Profile* profile,
     30                                          PasswordManager* password_manager,
     31                                          content::WebContents* web_contents,
     32                                          const PasswordForm& observed_form,
     33                                          bool ssl_valid)
     34     : best_matches_deleter_(&best_matches_),
     35       observed_form_(observed_form),
     36       is_new_login_(true),
     37       has_generated_password_(false),
     38       password_manager_(password_manager),
     39       preferred_match_(NULL),
     40       state_(PRE_MATCHING_PHASE),
     41       profile_(profile),
     42       web_contents_(web_contents),
     43       manager_action_(kManagerActionNone),
     44       user_action_(kUserActionNone),
     45       submit_result_(kSubmitResultNotSubmitted) {
     46   DCHECK(profile_);
     47   if (observed_form_.origin.is_valid())
     48     base::SplitString(observed_form_.origin.path(), '/', &form_path_tokens_);
     49   observed_form_.ssl_valid = ssl_valid;
     50 }
     51 
     52 PasswordFormManager::~PasswordFormManager() {
     53   UMA_HISTOGRAM_ENUMERATION("PasswordManager.ActionsTakenWithPsl",
     54                             GetActionsTaken(),
     55                             kMaxNumActionsTaken);
     56 }
     57 
     58 int PasswordFormManager::GetActionsTaken() {
     59   return user_action_ + kUserActionMax * (manager_action_ +
     60          kManagerActionMax * submit_result_);
     61 };
     62 
     63 // TODO(timsteele): use a hash of some sort in the future?
     64 bool PasswordFormManager::DoesManage(const PasswordForm& form,
     65                                      ActionMatch action_match) const {
     66   if (form.scheme != PasswordForm::SCHEME_HTML)
     67       return observed_form_.signon_realm == form.signon_realm;
     68 
     69   // HTML form case.
     70   // At a minimum, username and password element must match.
     71   if (!((form.username_element == observed_form_.username_element) &&
     72         (form.password_element == observed_form_.password_element))) {
     73     return false;
     74   }
     75 
     76   // When action match is required, the action URL must match, but
     77   // the form is allowed to have an empty action URL (See bug 1107719).
     78   // Otherwise ignore action URL, this is to allow saving password form with
     79   // dynamically changed action URL (See bug 27246).
     80   if (form.action.is_valid() && (form.action != observed_form_.action)) {
     81     if (action_match == ACTION_MATCH_REQUIRED)
     82       return false;
     83   }
     84 
     85   // If this is a replay of the same form in the case a user entered an invalid
     86   // password, the origin of the new form may equal the action of the "first"
     87   // form.
     88   if (!((form.origin == observed_form_.origin) ||
     89         (form.origin == observed_form_.action))) {
     90     if (form.origin.SchemeIsSecure() &&
     91         !observed_form_.origin.SchemeIsSecure()) {
     92       // Compare origins, ignoring scheme. There is no easy way to do this
     93       // with GURL because clearing the scheme would result in an invalid url.
     94       // This is for some sites (such as Hotmail) that begin on an http page and
     95       // head to https for the retry when password was invalid.
     96       std::string::const_iterator after_scheme1 = form.origin.spec().begin() +
     97                                                   form.origin.scheme().length();
     98       std::string::const_iterator after_scheme2 =
     99           observed_form_.origin.spec().begin() +
    100           observed_form_.origin.scheme().length();
    101       return std::search(after_scheme1,
    102                          form.origin.spec().end(),
    103                          after_scheme2,
    104                          observed_form_.origin.spec().end())
    105                          != form.origin.spec().end();
    106     }
    107     return false;
    108   }
    109   return true;
    110 }
    111 
    112 bool PasswordFormManager::IsBlacklisted() {
    113   DCHECK_EQ(state_, POST_MATCHING_PHASE);
    114   if (preferred_match_ && preferred_match_->blacklisted_by_user)
    115     return true;
    116   return false;
    117 }
    118 
    119 void PasswordFormManager::PermanentlyBlacklist() {
    120   DCHECK_EQ(state_, POST_MATCHING_PHASE);
    121 
    122   // Configure the form about to be saved for blacklist status.
    123   pending_credentials_.preferred = true;
    124   pending_credentials_.blacklisted_by_user = true;
    125   pending_credentials_.username_value.clear();
    126   pending_credentials_.password_value.clear();
    127 
    128   // Retroactively forget existing matches for this form, so we NEVER prompt or
    129   // autofill it again.
    130   int num_passwords_deleted = 0;
    131   if (!best_matches_.empty()) {
    132     PasswordFormMap::const_iterator iter;
    133     PasswordStore* password_store = PasswordStoreFactory::GetForProfile(
    134         profile_, Profile::EXPLICIT_ACCESS).get();
    135     if (!password_store) {
    136       NOTREACHED();
    137       return;
    138     }
    139     for (iter = best_matches_.begin(); iter != best_matches_.end(); ++iter) {
    140       // We want to remove existing matches for this form so that the exact
    141       // origin match with |blackisted_by_user == true| is the only result that
    142       // shows up in the future for this origin URL. However, we don't want to
    143       // delete logins that were actually saved on a different page (hence with
    144       // different origin URL) and just happened to match this form because of
    145       // the scoring algorithm. See bug 1204493.
    146       if (iter->second->origin == observed_form_.origin) {
    147         password_store->RemoveLogin(*iter->second);
    148         ++num_passwords_deleted;
    149       }
    150     }
    151   }
    152 
    153   UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsDeletedWhenBlacklisting",
    154                        num_passwords_deleted);
    155 
    156   // Save the pending_credentials_ entry marked as blacklisted.
    157   SaveAsNewLogin(false);
    158 }
    159 
    160 bool PasswordFormManager::IsNewLogin() {
    161   DCHECK_EQ(state_, POST_MATCHING_PHASE);
    162   return is_new_login_;
    163 }
    164 
    165 bool PasswordFormManager::IsPendingCredentialsPublicSuffixMatch() {
    166   return pending_credentials_.IsPublicSuffixMatch();
    167 }
    168 
    169 void PasswordFormManager::SetHasGeneratedPassword() {
    170   has_generated_password_ = true;
    171 }
    172 
    173 bool PasswordFormManager::HasGeneratedPassword() {
    174   // This check is permissive, as the user may have generated a password and
    175   // then edited it in the form itself. However, even in this case the user
    176   // has already given consent, so we treat these cases the same.
    177   return has_generated_password_;
    178 }
    179 
    180 bool PasswordFormManager::HasValidPasswordForm() {
    181   DCHECK_EQ(state_, POST_MATCHING_PHASE);
    182   // Non-HTML password forms (primarily HTTP and FTP autentication)
    183   // do not contain username_element and password_element values.
    184   if (observed_form_.scheme != PasswordForm::SCHEME_HTML)
    185     return true;
    186   return !observed_form_.username_element.empty() &&
    187       !observed_form_.password_element.empty();
    188 }
    189 
    190 void PasswordFormManager::ProvisionallySave(
    191     const PasswordForm& credentials,
    192     OtherPossibleUsernamesAction action) {
    193   DCHECK_EQ(state_, POST_MATCHING_PHASE);
    194   DCHECK(DoesManage(credentials, ACTION_MATCH_NOT_REQUIRED));
    195 
    196   // Make sure the important fields stay the same as the initially observed or
    197   // autofilled ones, as they may have changed if the user experienced a login
    198   // failure.
    199   // Look for these credentials in the list containing auto-fill entries.
    200   PasswordFormMap::const_iterator it =
    201       best_matches_.find(credentials.username_value);
    202   if (it != best_matches_.end()) {
    203     // The user signed in with a login we autofilled.
    204     pending_credentials_ = *it->second;
    205 
    206     // Public suffix matches should always be new logins, since we want to store
    207     // them so they can automatically be filled in later.
    208     is_new_login_ = IsPendingCredentialsPublicSuffixMatch();
    209     if (is_new_login_)
    210       user_action_ = kUserActionChoosePslMatch;
    211 
    212     // Check to see if we're using a known username but a new password.
    213     if (pending_credentials_.password_value != credentials.password_value)
    214       user_action_ = kUserActionOverride;
    215   } else if (action == ALLOW_OTHER_POSSIBLE_USERNAMES &&
    216              UpdatePendingCredentialsIfOtherPossibleUsername(
    217                  credentials.username_value)) {
    218     // |pending_credentials_| is now set. Note we don't update
    219     // |pending_credentials_.username_value| to |credentials.username_value|
    220     // yet because we need to keep the original username to modify the stored
    221     // credential.
    222     selected_username_ = credentials.username_value;
    223     is_new_login_ = false;
    224   } else {
    225     // User typed in a new, unknown username.
    226     user_action_ = kUserActionOverride;
    227     pending_credentials_ = observed_form_;
    228     pending_credentials_.username_value = credentials.username_value;
    229     pending_credentials_.other_possible_usernames =
    230         credentials.other_possible_usernames;
    231   }
    232 
    233   pending_credentials_.action = credentials.action;
    234   // If the user selected credentials we autofilled from a PasswordForm
    235   // that contained no action URL (IE6/7 imported passwords, for example),
    236   // bless it with the action URL from the observed form. See bug 1107719.
    237   if (pending_credentials_.action.is_empty())
    238     pending_credentials_.action = observed_form_.action;
    239 
    240   pending_credentials_.password_value = credentials.password_value;
    241   pending_credentials_.preferred = credentials.preferred;
    242 
    243   if (has_generated_password_)
    244     pending_credentials_.type = PasswordForm::TYPE_GENERATED;
    245 }
    246 
    247 void PasswordFormManager::Save() {
    248   DCHECK_EQ(state_, POST_MATCHING_PHASE);
    249   DCHECK(!profile_->IsOffTheRecord());
    250 
    251   if (IsNewLogin())
    252     SaveAsNewLogin(true);
    253   else
    254     UpdateLogin();
    255 }
    256 
    257 void PasswordFormManager::FetchMatchingLoginsFromPasswordStore(
    258     PasswordStore::AuthorizationPromptPolicy prompt_policy) {
    259   DCHECK_EQ(state_, PRE_MATCHING_PHASE);
    260   state_ = MATCHING_PHASE;
    261   PasswordStore* password_store = PasswordStoreFactory::GetForProfile(
    262       profile_, Profile::EXPLICIT_ACCESS).get();
    263   if (!password_store) {
    264     NOTREACHED();
    265     return;
    266   }
    267   password_store->GetLogins(observed_form_, prompt_policy, this);
    268 }
    269 
    270 bool PasswordFormManager::HasCompletedMatching() {
    271   return state_ == POST_MATCHING_PHASE;
    272 }
    273 
    274 void PasswordFormManager::OnRequestDone(
    275     const std::vector<PasswordForm*>& logins_result) {
    276   // Note that the result gets deleted after this call completes, but we own
    277   // the PasswordForm objects pointed to by the result vector, thus we keep
    278   // copies to a minimum here.
    279 
    280   int best_score = 0;
    281   // These credentials will be in the final result regardless of score.
    282   std::vector<PasswordForm> credentials_to_keep;
    283   for (size_t i = 0; i < logins_result.size(); i++) {
    284     if (IgnoreResult(*logins_result[i])) {
    285       delete logins_result[i];
    286       continue;
    287     }
    288     // Score and update best matches.
    289     int current_score = ScoreResult(*logins_result[i]);
    290     // This check is here so we can append empty path matches in the event
    291     // they don't score as high as others and aren't added to best_matches_.
    292     // This is most commonly imported firefox logins. We skip blacklisted
    293     // ones because clearly we don't want to autofill them, and secondly
    294     // because they only mean something when we have no other matches already
    295     // saved in Chrome - in which case they'll make it through the regular
    296     // scoring flow below by design. Note signon_realm == origin implies empty
    297     // path logins_result, since signon_realm is a prefix of origin for HTML
    298     // password forms.
    299     // TODO(timsteele): Bug 1269400. We probably should do something more
    300     // elegant for any shorter-path match instead of explicitly handling empty
    301     // path matches.
    302     if ((observed_form_.scheme == PasswordForm::SCHEME_HTML) &&
    303         (observed_form_.signon_realm == logins_result[i]->origin.spec()) &&
    304         (current_score > 0) && (!logins_result[i]->blacklisted_by_user)) {
    305       credentials_to_keep.push_back(*logins_result[i]);
    306     }
    307 
    308     // Always keep generated passwords as part of the result set. If a user
    309     // generates a password on a signup form, it should show on a login form
    310     // even if they have a previous login saved.
    311     // TODO(gcasto): We don't want to cut credentials that were saved on signup
    312     // forms even if they weren't generated, but currently it's hard to
    313     // distinguish between those forms and two different login forms on the
    314     // same domain. Filed http://crbug.com/294468 to look into this.
    315     if (logins_result[i]->type == PasswordForm::TYPE_GENERATED)
    316       credentials_to_keep.push_back(*logins_result[i]);
    317 
    318     if (current_score < best_score) {
    319       delete logins_result[i];
    320       continue;
    321     }
    322     if (current_score == best_score) {
    323       best_matches_[logins_result[i]->username_value] = logins_result[i];
    324     } else if (current_score > best_score) {
    325       best_score = current_score;
    326       // This new login has a better score than all those up to this point
    327       // Note 'this' owns all the PasswordForms in best_matches_.
    328       STLDeleteValues(&best_matches_);
    329       best_matches_.clear();
    330       preferred_match_ = NULL;  // Don't delete, its owned by best_matches_.
    331       best_matches_[logins_result[i]->username_value] = logins_result[i];
    332     }
    333     preferred_match_ = logins_result[i]->preferred ? logins_result[i]
    334                                                    : preferred_match_;
    335   }
    336   // We're done matching now.
    337   state_ = POST_MATCHING_PHASE;
    338 
    339   if (best_score <= 0) {
    340     return;
    341   }
    342 
    343   for (std::vector<PasswordForm>::const_iterator it =
    344            credentials_to_keep.begin();
    345        it != credentials_to_keep.end(); ++it) {
    346     // If we don't already have a result with the same username, add the
    347     // lower-scored match (if it had equal score it would already be in
    348     // best_matches_).
    349     if (best_matches_.find(it->username_value) == best_matches_.end())
    350       best_matches_[it->username_value] = new PasswordForm(*it);
    351   }
    352 
    353   UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsNotShown",
    354                        logins_result.size() - best_matches_.size());
    355 
    356   // It is possible we have at least one match but have no preferred_match_,
    357   // because a user may have chosen to 'Forget' the preferred match. So we
    358   // just pick the first one and whichever the user selects for submit will
    359   // be saved as preferred.
    360   DCHECK(!best_matches_.empty());
    361   if (!preferred_match_)
    362     preferred_match_ = best_matches_.begin()->second;
    363 
    364   // Check to see if the user told us to ignore this site in the past.
    365   if (preferred_match_->blacklisted_by_user) {
    366     manager_action_ = kManagerActionBlacklisted;
    367     return;
    368   }
    369 
    370   // If not blacklisted, send a message to allow password generation.
    371   SendNotBlacklistedToRenderer();
    372 
    373   // Proceed to autofill.
    374   // Note that we provide the choices but don't actually prefill a value if:
    375   // (1) we are in Incognito mode, (2) the ACTION paths don't match,
    376   // or (3) if it matched using public suffix domain matching.
    377   bool wait_for_username =
    378       profile_->IsOffTheRecord() ||
    379       observed_form_.action.GetWithEmptyPath() !=
    380           preferred_match_->action.GetWithEmptyPath() ||
    381           preferred_match_->IsPublicSuffixMatch();
    382   if (wait_for_username)
    383     manager_action_ = kManagerActionNone;
    384   else
    385     manager_action_ = kManagerActionAutofilled;
    386   password_manager_->Autofill(observed_form_, best_matches_,
    387                               *preferred_match_, wait_for_username);
    388 }
    389 
    390 void PasswordFormManager::OnPasswordStoreRequestDone(
    391       CancelableRequestProvider::Handle handle,
    392       const std::vector<autofill::PasswordForm*>& result) {
    393   // TODO(kaiwang): Remove this function.
    394   NOTREACHED();
    395 }
    396 
    397 void PasswordFormManager::OnGetPasswordStoreResults(
    398       const std::vector<autofill::PasswordForm*>& results) {
    399   DCHECK_EQ(state_, MATCHING_PHASE);
    400 
    401   if (results.empty()) {
    402     state_ = POST_MATCHING_PHASE;
    403     // No result means that we visit this site the first time so we don't need
    404     // to check whether this site is blacklisted or not. Just send a message
    405     // to allow password generation.
    406     SendNotBlacklistedToRenderer();
    407     return;
    408   }
    409   OnRequestDone(results);
    410 }
    411 
    412 bool PasswordFormManager::IgnoreResult(const PasswordForm& form) const {
    413   // Ignore change password forms until we have some change password
    414   // functionality
    415   if (observed_form_.old_password_element.length() != 0) {
    416     return true;
    417   }
    418   // Don't match an invalid SSL form with one saved under secure
    419   // circumstances.
    420   if (form.ssl_valid && !observed_form_.ssl_valid) {
    421     return true;
    422   }
    423   return false;
    424 }
    425 
    426 void PasswordFormManager::SaveAsNewLogin(bool reset_preferred_login) {
    427   DCHECK_EQ(state_, POST_MATCHING_PHASE);
    428   DCHECK(IsNewLogin());
    429   // The new_form is being used to sign in, so it is preferred.
    430   DCHECK(pending_credentials_.preferred);
    431   // new_form contains the same basic data as observed_form_ (because its the
    432   // same form), but with the newly added credentials.
    433 
    434   DCHECK(!profile_->IsOffTheRecord());
    435 
    436   PasswordStore* password_store = PasswordStoreFactory::GetForProfile(
    437       profile_, Profile::IMPLICIT_ACCESS).get();
    438   if (!password_store) {
    439     NOTREACHED();
    440     return;
    441   }
    442 
    443   pending_credentials_.date_created = Time::Now();
    444   SanitizePossibleUsernames(&pending_credentials_);
    445   password_store->AddLogin(pending_credentials_);
    446 
    447   if (reset_preferred_login) {
    448     UpdatePreferredLoginState(password_store);
    449   }
    450 }
    451 
    452 void PasswordFormManager::SanitizePossibleUsernames(PasswordForm* form) {
    453   // Remove any possible usernames that could be credit cards or SSN for privacy
    454   // reasons. Also remove duplicates, both in other_possible_usernames and
    455   // between other_possible_usernames and username_value.
    456   std::set<base::string16> set;
    457   for (std::vector<base::string16>::iterator it =
    458            form->other_possible_usernames.begin();
    459        it != form->other_possible_usernames.end(); ++it) {
    460     if (!autofill::IsValidCreditCardNumber(*it) && !autofill::IsSSN(*it))
    461       set.insert(*it);
    462   }
    463   set.erase(form->username_value);
    464   std::vector<base::string16> temp(set.begin(), set.end());
    465   form->other_possible_usernames.swap(temp);
    466 }
    467 
    468 void PasswordFormManager::UpdatePreferredLoginState(
    469     PasswordStore* password_store) {
    470   DCHECK(password_store);
    471   PasswordFormMap::iterator iter;
    472   for (iter = best_matches_.begin(); iter != best_matches_.end(); iter++) {
    473     if (iter->second->username_value != pending_credentials_.username_value &&
    474         iter->second->preferred) {
    475       // This wasn't the selected login but it used to be preferred.
    476       iter->second->preferred = false;
    477       if (user_action_ == kUserActionNone)
    478         user_action_ = kUserActionChoose;
    479       password_store->UpdateLogin(*iter->second);
    480     }
    481   }
    482 }
    483 
    484 void PasswordFormManager::UpdateLogin() {
    485   DCHECK_EQ(state_, POST_MATCHING_PHASE);
    486   DCHECK(preferred_match_);
    487   // If we're doing an Update, we either autofilled correctly and need to
    488   // update the stats, or the user typed in a new password for autofilled
    489   // username, or the user selected one of the non-preferred matches,
    490   // thus requiring a swap of preferred bits.
    491   DCHECK(!IsNewLogin() && pending_credentials_.preferred);
    492   DCHECK(!profile_->IsOffTheRecord());
    493 
    494   PasswordStore* password_store = PasswordStoreFactory::GetForProfile(
    495       profile_, Profile::IMPLICIT_ACCESS).get();
    496   if (!password_store) {
    497     NOTREACHED();
    498     return;
    499   }
    500 
    501   // Update metadata.
    502   ++pending_credentials_.times_used;
    503 
    504   // Check to see if this form is a candidate for password generation.
    505   CheckForAccountCreationForm(pending_credentials_, observed_form_);
    506 
    507   UpdatePreferredLoginState(password_store);
    508 
    509   // Remove alternate usernames. At this point we assume that we have found
    510   // the right username.
    511   pending_credentials_.other_possible_usernames.clear();
    512 
    513   // Update the new preferred login.
    514   if (!selected_username_.empty()) {
    515     // An other possible username is selected. We set this selected username
    516     // as the real username. The PasswordStore API isn't designed to update
    517     // username, so we delete the old credentials and add a new one instead.
    518     password_store->RemoveLogin(pending_credentials_);
    519     pending_credentials_.username_value = selected_username_;
    520     password_store->AddLogin(pending_credentials_);
    521   } else if ((observed_form_.scheme == PasswordForm::SCHEME_HTML) &&
    522              (observed_form_.origin.spec().length() >
    523               observed_form_.signon_realm.length()) &&
    524              (observed_form_.signon_realm ==
    525               pending_credentials_.origin.spec())) {
    526     // Note origin.spec().length > signon_realm.length implies the origin has a
    527     // path, since signon_realm is a prefix of origin for HTML password forms.
    528     //
    529     // The user logged in successfully with one of our autofilled logins on a
    530     // page with non-empty path, but the autofilled entry was initially saved/
    531     // imported with an empty path. Rather than just mark this entry preferred,
    532     // we create a more specific copy for this exact page and leave the "master"
    533     // unchanged. This is to prevent the case where that master login is used
    534     // on several sites (e.g site.com/a and site.com/b) but the user actually
    535     // has a different preference on each site. For example, on /a, he wants the
    536     // general empty-path login so it is flagged as preferred, but on /b he logs
    537     // in with a different saved entry - we don't want to remove the preferred
    538     // status of the former because upon return to /a it won't be the default-
    539     // fill match.
    540     // TODO(timsteele): Bug 1188626 - expire the master copies.
    541     PasswordForm copy(pending_credentials_);
    542     copy.origin = observed_form_.origin;
    543     copy.action = observed_form_.action;
    544     password_store->AddLogin(copy);
    545   } else {
    546     password_store->UpdateLogin(pending_credentials_);
    547   }
    548 }
    549 
    550 bool PasswordFormManager::UpdatePendingCredentialsIfOtherPossibleUsername(
    551     const base::string16& username) {
    552   for (PasswordFormMap::const_iterator it = best_matches_.begin();
    553        it != best_matches_.end(); ++it) {
    554     for (size_t i = 0; i < it->second->other_possible_usernames.size(); ++i) {
    555       if (it->second->other_possible_usernames[i] == username) {
    556         pending_credentials_ = *it->second;
    557         return true;
    558       }
    559     }
    560   }
    561   return false;
    562 }
    563 
    564 void PasswordFormManager::CheckForAccountCreationForm(
    565     const PasswordForm& pending, const PasswordForm& observed) {
    566   // We check to see if the saved form_data is the same as the observed
    567   // form_data, which should never be true for passwords saved on account
    568   // creation forms. This check is only made the first time a password is used
    569   // to cut down on false positives. Specifically a site may have multiple login
    570   // forms with different markup, which might look similar to a signup form.
    571   if (pending.times_used == 1) {
    572     FormStructure pending_structure(pending.form_data);
    573     FormStructure observed_structure(observed.form_data);
    574     // Ignore |pending_structure| if its FormData has no fields. This is to
    575     // weed out those credentials that were saved before FormData was added
    576     // to PasswordForm. Even without this check, these FormStructure's won't
    577     // be uploaded, but it makes it hard to see if we are encountering
    578     // unexpected errors.
    579     if (!pending.form_data.fields.empty() &&
    580         pending_structure.FormSignature() !=
    581             observed_structure.FormSignature()) {
    582       autofill::AutofillDriverImpl* driver =
    583           autofill::AutofillDriverImpl::FromWebContents(web_contents_);
    584       if (driver && driver->autofill_manager()) {
    585         // Note that this doesn't guarantee that the upload succeeded, only that
    586         // |pending.form_data| is considered uploadable.
    587         bool success = driver->autofill_manager()->UploadPasswordGenerationForm(
    588             pending.form_data);
    589         UMA_HISTOGRAM_BOOLEAN("PasswordGeneration.UploadStarted", success);
    590       }
    591     }
    592   }
    593 }
    594 
    595 int PasswordFormManager::ScoreResult(const PasswordForm& candidate) const {
    596   DCHECK_EQ(state_, MATCHING_PHASE);
    597   // For scoring of candidate login data:
    598   // The most important element that should match is the origin, followed by
    599   // the action, the password name, the submit button name, and finally the
    600   // username input field name.
    601   // Exact origin match gives an addition of 64 (1 << 6) + # of matching url
    602   // dirs.
    603   // Partial match gives an addition of 32 (1 << 5) + # matching url dirs
    604   // That way, a partial match cannot trump an exact match even if
    605   // the partial one matches all other attributes (action, elements) (and
    606   // regardless of the matching depth in the URL path).
    607   // If public suffix origin match was not used, it gives an addition of
    608   // 16 (1 << 4).
    609   int score = 0;
    610   if (candidate.origin == observed_form_.origin) {
    611     // This check is here for the most common case which
    612     // is we have a single match in the db for the given host,
    613     // so we don't generally need to walk the entire URL path (the else
    614     // clause).
    615     score += (1 << 6) + static_cast<int>(form_path_tokens_.size());
    616   } else {
    617     // Walk the origin URL paths one directory at a time to see how
    618     // deep the two match.
    619     std::vector<std::string> candidate_path_tokens;
    620     base::SplitString(candidate.origin.path(), '/', &candidate_path_tokens);
    621     size_t depth = 0;
    622     size_t max_dirs = std::min(form_path_tokens_.size(),
    623                                candidate_path_tokens.size());
    624     while ((depth < max_dirs) && (form_path_tokens_[depth] ==
    625                                   candidate_path_tokens[depth])) {
    626       depth++;
    627       score++;
    628     }
    629     // do we have a partial match?
    630     score += (depth > 0) ? 1 << 5 : 0;
    631   }
    632   if (observed_form_.scheme == PasswordForm::SCHEME_HTML) {
    633     if (!candidate.IsPublicSuffixMatch())
    634       score += 1 << 4;
    635     if (candidate.action == observed_form_.action)
    636       score += 1 << 3;
    637     if (candidate.password_element == observed_form_.password_element)
    638       score += 1 << 2;
    639     if (candidate.submit_element == observed_form_.submit_element)
    640       score += 1 << 1;
    641     if (candidate.username_element == observed_form_.username_element)
    642       score += 1 << 0;
    643   }
    644 
    645   return score;
    646 }
    647 
    648 void PasswordFormManager::SubmitPassed() {
    649   submit_result_ = kSubmitResultPassed;
    650 }
    651 
    652 void PasswordFormManager::SubmitFailed() {
    653   submit_result_ = kSubmitResultFailed;
    654 }
    655 
    656 void PasswordFormManager::SendNotBlacklistedToRenderer() {
    657   content::RenderViewHost* host = web_contents_->GetRenderViewHost();
    658   host->Send(new AutofillMsg_FormNotBlacklisted(host->GetRoutingID(),
    659                                                  observed_form_));
    660 }
    661