diff options
Diffstat (limited to 'chrome/browser/password_manager.cc')
-rw-r--r-- | chrome/browser/password_manager.cc | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/chrome/browser/password_manager.cc b/chrome/browser/password_manager.cc new file mode 100644 index 0000000..0015188 --- /dev/null +++ b/chrome/browser/password_manager.cc @@ -0,0 +1,247 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "chrome/app/theme/theme_resources.h" +#include "chrome/browser/password_manager.h" +#include "chrome/browser/profile.h" +#include "chrome/browser/web_contents.h" +#include "chrome/common/l10n_util.h" +#include "chrome/common/pref_names.h" +#include "chrome/common/resource_bundle.h" +#include "chrome/common/stl_util-inl.h" +#include "base/string_util.h" + +#include "generated_resources.h" + +// static +void PasswordManager::RegisterUserPrefs(PrefService* prefs) { + prefs->RegisterBooleanPref(prefs::kPasswordManagerEnabled, true); +} + +PasswordManager::PasswordManager(WebContents* web_contents) + : web_contents_(web_contents), + current_bar_(NULL), + observer_(NULL), + login_managers_deleter_(&pending_login_managers_) { + password_manager_enabled_.Init(prefs::kPasswordManagerEnabled, + web_contents->profile()->GetPrefs(), NULL); +} + +PasswordManager::~PasswordManager() { + CloseBars(); +} + +void PasswordManager::ProvisionallySavePassword(PasswordForm form) { + if (!web_contents_->controller() || !web_contents_->profile() || + web_contents_->profile()->IsOffTheRecord() || !*password_manager_enabled_) + return; + + // No password to save? Then don't. + if (form.password_value.empty()) + return; + + LoginManagers::iterator iter; + PasswordFormManager* manager = NULL; + for (iter = pending_login_managers_.begin(); + iter != pending_login_managers_.end(); iter++) { + if ((*iter)->DoesManage(form)) { + manager = *iter; + break; + } + } + // If we didn't find a manager, this means a form was submitted without + // first loading the page containing the form. Don't offer to save + // passwords in this case. + if (!manager) + return; + + // If we found a manager but it didn't finish matching yet, the user has + // tried to submit credentials before we had time to even find matching + // results for the given form and autofill. If this is the case, we just + // give up. + if (!manager->HasCompletedMatching()) + return; + + // Also get out of here if the user told us to 'never remember' passwords for + // this form. + if (manager->IsBlacklisted()) + return; + + form.ssl_valid = form.origin.SchemeIsSecure() && + !web_contents_->controller()->ssl_manager()-> + ProcessedSSLErrorFromRequest(); + form.preferred = true; + manager->ProvisionallySave(form); + pending_save_manager_.reset(manager); + pending_login_managers_.erase(iter); + // We don't care about the rest of the forms on the page now that one + // was selected. + STLDeleteElements(&pending_login_managers_); + pending_login_managers_.clear(); +} + +void PasswordManager::DidNavigate() { + // As long as this navigation isn't due to a currently pending + // password form submit, we're ready to reset and move on. + // Rest assured that if a navigation happens due to a redirect between submit + // and landing at a destination page after successful login we don't mess + // anything up, because either the credentials have already been saved or it + // is now the responsibility of the SavePasswordBar to deal with the lingering + // PasswordFormManager. + if (!pending_save_manager_.get() && !pending_login_managers_.empty()) { + STLDeleteElements(&pending_login_managers_); + pending_login_managers_.clear(); + } +} + +void PasswordManager::DidStopLoading() { + if (!pending_save_manager_.get()) + return; + + DCHECK(!web_contents_->profile()->IsOffTheRecord()); + DCHECK(!pending_save_manager_->IsBlacklisted()); + + if (!web_contents_->profile() || + !web_contents_->profile()->GetWebDataService(Profile::IMPLICIT_ACCESS)) + return; + if (!web_contents_->controller()) + return; + + if (pending_save_manager_->IsNewLogin()) { + // Transfer ownership of the pending_save_manager_ to the PasswordBar. + ReplaceInfoBar(new SavePasswordBar(pending_save_manager_.release(), this)); + } else { + // If the save is not a new username entry, then we just want to save this + // data (since the user already has related data saved), so don't prompt. + pending_save_manager_->Save(); + pending_save_manager_.reset(); + } +} + +void PasswordManager::PasswordFormsSeen(const std::vector<PasswordForm>& forms) { + if (!web_contents_->profile() || + !web_contents_->profile()->GetWebDataService(Profile::EXPLICIT_ACCESS)) + return; + if (!web_contents_->controller()) + return; + if (!*password_manager_enabled_) + return; + + // Ask the SSLManager for current security. + bool had_ssl_error = web_contents_->controller()->ssl_manager()-> + ProcessedSSLErrorFromRequest(); + + std::vector<PasswordForm>::const_iterator iter; + for (iter = forms.begin(); iter != forms.end(); iter++) { + if (pending_save_manager_.get() && + pending_save_manager_->DoesManage(*iter)) { + // The form trying to be saved has immediately re-appeared. Assume + // login failure and abort this save. Fallback to pending login state + // since the user may try again. + pending_login_managers_.push_back(pending_save_manager_.release()); + // Don't delete the login managers since the user may try again + // and we want to be able to save in that case. + break; + } else { + bool ssl_valid = iter->origin.SchemeIsSecure() && !had_ssl_error; + PasswordFormManager* manager = + new PasswordFormManager(web_contents_->profile(), + this, *iter, ssl_valid); + pending_login_managers_.push_back(manager); + manager->FetchMatchingLoginsFromWebDatabase(); + } + } +} + +void PasswordManager::Autofill(const PasswordForm& form_for_autofill, + const PasswordFormMap& best_matches, + const PasswordForm* const preferred_match) const { + DCHECK(web_contents_); + DCHECK(preferred_match); + switch (form_for_autofill.scheme) { + case PasswordForm::SCHEME_HTML: { + // Note the check above is required because the observer_ for a non-HTML + // schemed password form may have been freed, so we need to distinguish. + bool action_mismatch = form_for_autofill.action.GetWithEmptyPath() != + preferred_match->action.GetWithEmptyPath(); + scoped_ptr<PasswordFormDomManager::FillData> fill_data( + PasswordFormDomManager::CreateFillData(form_for_autofill, + best_matches, preferred_match, + action_mismatch)); + web_contents_->FillPasswordForm(*fill_data); + return; + } + default: + if (observer_) + observer_->OnAutofillDataAvailable(preferred_match->username_value, + preferred_match->password_value); + } +} + +void PasswordManager::CloseBars() { + if (current_bar_) + current_bar_->Close(); +} + +void PasswordManager::ReplaceInfoBar(InfoBarItemView* bar) { + CloseBars(); + InfoBarView* view = web_contents_->GetInfoBarView(); + view->AddChildView(bar); + current_bar_ = bar; +} + +PasswordManager::SavePasswordBar + ::SavePasswordBar(PasswordFormManager* form_manager, + PasswordManager* password_manager) + : form_manager_(form_manager), + password_manager_(password_manager), + InfoBarConfirmView( + l10n_util::GetString(IDS_PASSWORD_MANAGER_SAVE_PASSWORD_PROMPT)) { + SetOKButtonLabel(l10n_util::GetString(IDS_PASSWORD_MANAGER_SAVE_BUTTON)); + SetCancelButtonLabel(l10n_util::GetString( + IDS_PASSWORD_MANAGER_BLACKLIST_BUTTON)); + ResourceBundle &rb = ResourceBundle::GetSharedInstance(); + SetIcon(*rb.GetBitmapNamed(IDR_INFOBAR_SAVE_PASSWORD)); +} + +PasswordManager::SavePasswordBar::~SavePasswordBar() { + password_manager_->current_bar_ = NULL; + if (form_manager_) + delete form_manager_; +} + +void PasswordManager::SavePasswordBar::OKButtonPressed() { + form_manager_->Save(); + BeginClose(); +} + +void PasswordManager::SavePasswordBar::CancelButtonPressed() { + form_manager_->PermanentlyBlacklist(); + BeginClose(); +}
\ No newline at end of file |