summaryrefslogtreecommitdiffstats
path: root/chrome/browser/password_manager.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome/browser/password_manager.cc')
-rw-r--r--chrome/browser/password_manager.cc247
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