This source file includes following definitions.
- LogPasswordGenerationSubmissionEvent
- submit_result_
- GetActionsTaken
- DoesManage
- IsBlacklisted
- PermanentlyBlacklist
- SetUseAdditionalPasswordAuthentication
- IsNewLogin
- IsPendingCredentialsPublicSuffixMatch
- SetHasGeneratedPassword
- HasGeneratedPassword
- HasValidPasswordForm
- ProvisionallySave
- Save
- FetchMatchingLoginsFromPasswordStore
- HasCompletedMatching
- OnRequestDone
- OnGetPasswordStoreResults
- IgnoreResult
- SaveAsNewLogin
- SanitizePossibleUsernames
- UpdatePreferredLoginState
- UpdateLogin
- UpdatePendingCredentialsIfOtherPossibleUsername
- CheckForAccountCreationForm
- ScoreResult
- SubmitPassed
- SubmitFailed
#include "components/password_manager/core/browser/password_form_manager.h"
#include <algorithm>
#include "base/metrics/histogram.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "components/autofill/core/browser/autofill_manager.h"
#include "components/autofill/core/browser/form_structure.h"
#include "components/autofill/core/browser/validation.h"
#include "components/autofill/core/common/password_form.h"
#include "components/password_manager/core/browser/password_manager.h"
#include "components/password_manager/core/browser/password_manager_client.h"
#include "components/password_manager/core/browser/password_manager_driver.h"
#include "components/password_manager/core/browser/password_store.h"
using autofill::FormStructure;
using autofill::PasswordForm;
using autofill::PasswordFormMap;
using base::Time;
namespace {
enum PasswordGenerationSubmissionEvent {
  
  PASSWORD_SUBMITTED,
  
  PASSWORD_SUBMISSION_FAILED,
  
  
  PASSWORD_NOT_SUBMITTED,
  
  
  
  PASSWORD_OVERRIDDEN,
  
  SUBMISSION_EVENT_ENUM_COUNT
};
void LogPasswordGenerationSubmissionEvent(
    PasswordGenerationSubmissionEvent event) {
  UMA_HISTOGRAM_ENUMERATION("PasswordGeneration.SubmissionEvent",
                            event, SUBMISSION_EVENT_ENUM_COUNT);
}
}  
PasswordFormManager::PasswordFormManager(PasswordManager* password_manager,
                                         PasswordManagerClient* client,
                                         PasswordManagerDriver* driver,
                                         const PasswordForm& observed_form,
                                         bool ssl_valid)
    : best_matches_deleter_(&best_matches_),
      observed_form_(observed_form),
      is_new_login_(true),
      has_generated_password_(false),
      password_manager_(password_manager),
      preferred_match_(NULL),
      state_(PRE_MATCHING_PHASE),
      client_(client),
      driver_(driver),
      manager_action_(kManagerActionNone),
      user_action_(kUserActionNone),
      submit_result_(kSubmitResultNotSubmitted) {
  if (observed_form_.origin.is_valid())
    base::SplitString(observed_form_.origin.path(), '/', &form_path_tokens_);
  observed_form_.ssl_valid = ssl_valid;
}
PasswordFormManager::~PasswordFormManager() {
  UMA_HISTOGRAM_ENUMERATION(
      "PasswordManager.ActionsTakenV3", GetActionsTaken(), kMaxNumActionsTaken);
  if (has_generated_password_ && submit_result_ == kSubmitResultNotSubmitted)
    LogPasswordGenerationSubmissionEvent(PASSWORD_NOT_SUBMITTED);
}
int PasswordFormManager::GetActionsTaken() {
  return user_action_ + kUserActionMax * (manager_action_ +
         kManagerActionMax * submit_result_);
};
bool PasswordFormManager::DoesManage(const PasswordForm& form,
                                     ActionMatch action_match) const {
  if (form.scheme != PasswordForm::SCHEME_HTML)
      return observed_form_.signon_realm == form.signon_realm;
  
  
  if (!((form.username_element == observed_form_.username_element) &&
        (form.password_element == observed_form_.password_element))) {
    return false;
  }
  
  
  
  
  if (form.action.is_valid() && (form.action != observed_form_.action)) {
    if (action_match == ACTION_MATCH_REQUIRED)
      return false;
  }
  
  
  
  if (!((form.origin == observed_form_.origin) ||
        (form.origin == observed_form_.action))) {
    if (form.origin.SchemeIsSecure() &&
        !observed_form_.origin.SchemeIsSecure()) {
      
      
      
      
      std::string::const_iterator after_scheme1 = form.origin.spec().begin() +
                                                  form.origin.scheme().length();
      std::string::const_iterator after_scheme2 =
          observed_form_.origin.spec().begin() +
          observed_form_.origin.scheme().length();
      return std::search(after_scheme1,
                         form.origin.spec().end(),
                         after_scheme2,
                         observed_form_.origin.spec().end())
                         != form.origin.spec().end();
    }
    return false;
  }
  return true;
}
bool PasswordFormManager::IsBlacklisted() {
  DCHECK_EQ(state_, POST_MATCHING_PHASE);
  if (preferred_match_ && preferred_match_->blacklisted_by_user)
    return true;
  return false;
}
void PasswordFormManager::PermanentlyBlacklist() {
  DCHECK_EQ(state_, POST_MATCHING_PHASE);
  
  pending_credentials_.preferred = true;
  pending_credentials_.blacklisted_by_user = true;
  pending_credentials_.username_value.clear();
  pending_credentials_.password_value.clear();
  
  
  int num_passwords_deleted = 0;
  if (!best_matches_.empty()) {
    PasswordFormMap::const_iterator iter;
    PasswordStore* password_store = client_->GetPasswordStore();
    if (!password_store) {
      NOTREACHED();
      return;
    }
    for (iter = best_matches_.begin(); iter != best_matches_.end(); ++iter) {
      
      
      
      
      
      
      if (iter->second->origin == observed_form_.origin) {
        password_store->RemoveLogin(*iter->second);
        ++num_passwords_deleted;
      }
    }
  }
  UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsDeletedWhenBlacklisting",
                       num_passwords_deleted);
  
  SaveAsNewLogin(false);
}
void PasswordFormManager::SetUseAdditionalPasswordAuthentication(
    bool use_additional_authentication) {
  pending_credentials_.use_additional_authentication =
      use_additional_authentication;
}
bool PasswordFormManager::IsNewLogin() {
  DCHECK_EQ(state_, POST_MATCHING_PHASE);
  return is_new_login_;
}
bool PasswordFormManager::IsPendingCredentialsPublicSuffixMatch() {
  return pending_credentials_.IsPublicSuffixMatch();
}
void PasswordFormManager::SetHasGeneratedPassword() {
  has_generated_password_ = true;
}
bool PasswordFormManager::HasGeneratedPassword() {
  
  
  
  return has_generated_password_;
}
bool PasswordFormManager::HasValidPasswordForm() {
  DCHECK_EQ(state_, POST_MATCHING_PHASE);
  
  
  if (observed_form_.scheme != PasswordForm::SCHEME_HTML)
    return true;
  return !observed_form_.username_element.empty() &&
      !observed_form_.password_element.empty();
}
void PasswordFormManager::ProvisionallySave(
    const PasswordForm& credentials,
    OtherPossibleUsernamesAction action) {
  DCHECK_EQ(state_, POST_MATCHING_PHASE);
  DCHECK(DoesManage(credentials, ACTION_MATCH_NOT_REQUIRED));
  
  
  
  
  PasswordFormMap::const_iterator it =
      best_matches_.find(credentials.username_value);
  if (it != best_matches_.end()) {
    
    pending_credentials_ = *it->second;
    
    
    is_new_login_ = IsPendingCredentialsPublicSuffixMatch();
    if (is_new_login_)
      user_action_ = kUserActionChoosePslMatch;
    
    if (pending_credentials_.password_value != credentials.password_value)
      user_action_ = kUserActionOverridePassword;
  } else if (action == ALLOW_OTHER_POSSIBLE_USERNAMES &&
             UpdatePendingCredentialsIfOtherPossibleUsername(
                 credentials.username_value)) {
    
    
    
    
    selected_username_ = credentials.username_value;
    is_new_login_ = false;
  } else {
    
    user_action_ = kUserActionOverrideUsernameAndPassword;
    pending_credentials_ = observed_form_;
    pending_credentials_.username_value = credentials.username_value;
    pending_credentials_.other_possible_usernames =
        credentials.other_possible_usernames;
  }
  pending_credentials_.action = credentials.action;
  
  
  
  if (pending_credentials_.action.is_empty())
    pending_credentials_.action = observed_form_.action;
  
  if (pending_credentials_.password_element.empty())
    pending_credentials_.password_element = observed_form_.password_element;
  if (pending_credentials_.username_element.empty())
    pending_credentials_.username_element = observed_form_.username_element;
  if (pending_credentials_.submit_element.empty())
    pending_credentials_.submit_element = observed_form_.submit_element;
  pending_credentials_.password_value = credentials.password_value;
  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;
}
void PasswordFormManager::Save() {
  DCHECK_EQ(state_, POST_MATCHING_PHASE);
  DCHECK(!driver_->IsOffTheRecord());
  if (IsNewLogin())
    SaveAsNewLogin(true);
  else
    UpdateLogin();
}
void PasswordFormManager::FetchMatchingLoginsFromPasswordStore(
    PasswordStore::AuthorizationPromptPolicy prompt_policy) {
  DCHECK_EQ(state_, PRE_MATCHING_PHASE);
  state_ = MATCHING_PHASE;
  PasswordStore* password_store = client_->GetPasswordStore();
  if (!password_store) {
    NOTREACHED();
    return;
  }
  password_store->GetLogins(observed_form_, prompt_policy, this);
}
bool PasswordFormManager::HasCompletedMatching() {
  return state_ == POST_MATCHING_PHASE;
}
void PasswordFormManager::OnRequestDone(
    const std::vector<PasswordForm*>& logins_result) {
  
  
  
  int best_score = 0;
  
  std::vector<PasswordForm> credentials_to_keep;
  for (size_t i = 0; i < logins_result.size(); i++) {
    if (IgnoreResult(*logins_result[i])) {
      delete logins_result[i];
      continue;
    }
    
    int current_score = ScoreResult(*logins_result[i]);
    
    
    
    
    
    
    
    
    
    
    
    
    if ((observed_form_.scheme == PasswordForm::SCHEME_HTML) &&
        (observed_form_.signon_realm == logins_result[i]->origin.spec()) &&
        (current_score > 0) && (!logins_result[i]->blacklisted_by_user)) {
      credentials_to_keep.push_back(*logins_result[i]);
    }
    
    
    
    
    
    
    
    if (logins_result[i]->type == PasswordForm::TYPE_GENERATED)
      credentials_to_keep.push_back(*logins_result[i]);
    if (current_score < best_score) {
      delete logins_result[i];
      continue;
    }
    if (current_score == best_score) {
      best_matches_[logins_result[i]->username_value] = logins_result[i];
    } else if (current_score > best_score) {
      best_score = current_score;
      
      
      STLDeleteValues(&best_matches_);
      best_matches_.clear();
      preferred_match_ = NULL;  
      best_matches_[logins_result[i]->username_value] = logins_result[i];
    }
    preferred_match_ = logins_result[i]->preferred ? logins_result[i]
                                                   : preferred_match_;
  }
  
  state_ = POST_MATCHING_PHASE;
  if (best_score <= 0) {
    return;
  }
  for (std::vector<PasswordForm>::const_iterator it =
           credentials_to_keep.begin();
       it != credentials_to_keep.end(); ++it) {
    
    
    
    if (best_matches_.find(it->username_value) == best_matches_.end())
      best_matches_[it->username_value] = new PasswordForm(*it);
  }
  UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsNotShown",
                       logins_result.size() - best_matches_.size());
  
  
  
  
  DCHECK(!best_matches_.empty());
  if (!preferred_match_)
    preferred_match_ = best_matches_.begin()->second;
  
  if (preferred_match_->blacklisted_by_user) {
    manager_action_ = kManagerActionBlacklisted;
    return;
  }
  
  
  driver_->AllowPasswordGenerationForForm(&observed_form_);
  
  
  
  
  bool wait_for_username =
      driver_->IsOffTheRecord() ||
      observed_form_.action.GetWithEmptyPath() !=
          preferred_match_->action.GetWithEmptyPath() ||
          preferred_match_->IsPublicSuffixMatch();
  if (wait_for_username)
    manager_action_ = kManagerActionNone;
  else
    manager_action_ = kManagerActionAutofilled;
  password_manager_->Autofill(observed_form_, best_matches_,
                              *preferred_match_, wait_for_username);
}
void PasswordFormManager::OnGetPasswordStoreResults(
      const std::vector<autofill::PasswordForm*>& results) {
  DCHECK_EQ(state_, MATCHING_PHASE);
  if (results.empty()) {
    state_ = POST_MATCHING_PHASE;
    
    
    
    driver_->AllowPasswordGenerationForForm(&observed_form_);
    return;
  }
  OnRequestDone(results);
}
bool PasswordFormManager::IgnoreResult(const PasswordForm& form) const {
  
  
  if (observed_form_.old_password_element.length() != 0) {
    return true;
  }
  
  
  if (form.ssl_valid && !observed_form_.ssl_valid) {
    return true;
  }
  return false;
}
void PasswordFormManager::SaveAsNewLogin(bool reset_preferred_login) {
  DCHECK_EQ(state_, POST_MATCHING_PHASE);
  DCHECK(IsNewLogin());
  
  DCHECK(pending_credentials_.preferred);
  
  
  DCHECK(!driver_->IsOffTheRecord());
  PasswordStore* password_store = client_->GetPasswordStore();
  if (!password_store) {
    NOTREACHED();
    return;
  }
  pending_credentials_.date_created = Time::Now();
  SanitizePossibleUsernames(&pending_credentials_);
  password_store->AddLogin(pending_credentials_);
  if (reset_preferred_login) {
    UpdatePreferredLoginState(password_store);
  }
}
void PasswordFormManager::SanitizePossibleUsernames(PasswordForm* form) {
  
  
  
  std::set<base::string16> set;
  for (std::vector<base::string16>::iterator it =
           form->other_possible_usernames.begin();
       it != form->other_possible_usernames.end(); ++it) {
    if (!autofill::IsValidCreditCardNumber(*it) && !autofill::IsSSN(*it))
      set.insert(*it);
  }
  set.erase(form->username_value);
  std::vector<base::string16> temp(set.begin(), set.end());
  form->other_possible_usernames.swap(temp);
}
void PasswordFormManager::UpdatePreferredLoginState(
    PasswordStore* password_store) {
  DCHECK(password_store);
  PasswordFormMap::iterator iter;
  for (iter = best_matches_.begin(); iter != best_matches_.end(); iter++) {
    if (iter->second->username_value != pending_credentials_.username_value &&
        iter->second->preferred) {
      
      iter->second->preferred = false;
      if (user_action_ == kUserActionNone)
        user_action_ = kUserActionChoose;
      password_store->UpdateLogin(*iter->second);
    }
  }
}
void PasswordFormManager::UpdateLogin() {
  DCHECK_EQ(state_, POST_MATCHING_PHASE);
  DCHECK(preferred_match_);
  
  
  
  
  DCHECK(!IsNewLogin() && pending_credentials_.preferred);
  DCHECK(!driver_->IsOffTheRecord());
  PasswordStore* password_store = client_->GetPasswordStore();
  if (!password_store) {
    NOTREACHED();
    return;
  }
  
  ++pending_credentials_.times_used;
  
  CheckForAccountCreationForm(pending_credentials_, observed_form_);
  UpdatePreferredLoginState(password_store);
  
  
  pending_credentials_.other_possible_usernames.clear();
  
  if (!selected_username_.empty()) {
    
    
    
    password_store->RemoveLogin(pending_credentials_);
    pending_credentials_.username_value = selected_username_;
    password_store->AddLogin(pending_credentials_);
  } else if ((observed_form_.scheme == PasswordForm::SCHEME_HTML) &&
             (observed_form_.origin.spec().length() >
              observed_form_.signon_realm.length()) &&
             (observed_form_.signon_realm ==
              pending_credentials_.origin.spec())) {
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    PasswordForm copy(pending_credentials_);
    copy.origin = observed_form_.origin;
    copy.action = observed_form_.action;
    password_store->AddLogin(copy);
  } else {
    password_store->UpdateLogin(pending_credentials_);
  }
}
bool PasswordFormManager::UpdatePendingCredentialsIfOtherPossibleUsername(
    const base::string16& username) {
  for (PasswordFormMap::const_iterator it = best_matches_.begin();
       it != best_matches_.end(); ++it) {
    for (size_t i = 0; i < it->second->other_possible_usernames.size(); ++i) {
      if (it->second->other_possible_usernames[i] == username) {
        pending_credentials_ = *it->second;
        return true;
      }
    }
  }
  return false;
}
void PasswordFormManager::CheckForAccountCreationForm(
    const PasswordForm& pending, const PasswordForm& observed) {
  
  
  
  
  
  if (pending.times_used == 1) {
    FormStructure pending_structure(pending.form_data);
    FormStructure observed_structure(observed.form_data);
    
    
    
    
    
    if (!pending.form_data.fields.empty() &&
        pending_structure.FormSignature() !=
            observed_structure.FormSignature()) {
      autofill::AutofillManager* autofill_manager;
      if ((autofill_manager = driver_->GetAutofillManager())) {
        
        
        bool success =
            autofill_manager->UploadPasswordGenerationForm(pending.form_data);
        UMA_HISTOGRAM_BOOLEAN("PasswordGeneration.UploadStarted", success);
      }
    }
  }
}
int PasswordFormManager::ScoreResult(const PasswordForm& candidate) const {
  DCHECK_EQ(state_, MATCHING_PHASE);
  
  
  
  
  
  
  
  
  
  
  
  
  int score = 0;
  if (candidate.origin == observed_form_.origin) {
    
    
    
    
    score += (1 << 6) + static_cast<int>(form_path_tokens_.size());
  } else {
    
    
    std::vector<std::string> candidate_path_tokens;
    base::SplitString(candidate.origin.path(), '/', &candidate_path_tokens);
    size_t depth = 0;
    size_t max_dirs = std::min(form_path_tokens_.size(),
                               candidate_path_tokens.size());
    while ((depth < max_dirs) && (form_path_tokens_[depth] ==
                                  candidate_path_tokens[depth])) {
      depth++;
      score++;
    }
    
    score += (depth > 0) ? 1 << 5 : 0;
  }
  if (observed_form_.scheme == PasswordForm::SCHEME_HTML) {
    if (!candidate.IsPublicSuffixMatch())
      score += 1 << 4;
    if (candidate.action == observed_form_.action)
      score += 1 << 3;
    if (candidate.password_element == observed_form_.password_element)
      score += 1 << 2;
    if (candidate.submit_element == observed_form_.submit_element)
      score += 1 << 1;
    if (candidate.username_element == observed_form_.username_element)
      score += 1 << 0;
  }
  return score;
}
void PasswordFormManager::SubmitPassed() {
  submit_result_ = kSubmitResultPassed;
  if (has_generated_password_)
    LogPasswordGenerationSubmissionEvent(PASSWORD_SUBMITTED);
}
void PasswordFormManager::SubmitFailed() {
  submit_result_ = kSubmitResultFailed;
  if (has_generated_password_)
    LogPasswordGenerationSubmissionEvent(PASSWORD_SUBMISSION_FAILED);
}