From d28225c31e12cb7ebea0d4246478e71ef5456304 Mon Sep 17 00:00:00 2001 From: Umesh Kumar Patel Date: Fri, 6 Jun 2014 17:17:20 +0530 Subject: [PATCH] WCS Feature : Chrome reused files Change-Id: Ie7498630ba2cd1e0891e1b5b6bdd65be0cdf25ff --- .../content_password_manager_driver.cc | 112 +++ .../content_password_manager_driver.h | 63 ++ .../password_manager/password_form_manager.cc | 648 ++++++++++++++++++ .../password_manager/password_form_manager.h | 320 +++++++++ .../password_generation_manager.cc | 117 ++++ .../password_generation_manager.h | 128 ++++ .../password_manager/password_manager.cc | 380 ++++++++++ .../password_manager/password_manager.h | 182 +++++ .../password_manager_client.cc | 17 + .../password_manager_client.h | 61 ++ .../password_manager_driver.h | 55 ++ .../password_manager/password_manager_util.h | 42 ++ .../password_store_factory.cc | 116 ++++ .../password_manager/password_store_factory.h | 55 ++ .../impl/browser/webdata/web_data_service.cc | 36 + .../impl/browser/webdata/web_data_service.h | 68 ++ .../webdata/web_data_service_factory.cc | 143 ++++ .../webdata/web_data_service_factory.h | 66 ++ 18 files changed, 2609 insertions(+) create mode 100644 tizen_src/impl/browser/password_manager/content_password_manager_driver.cc create mode 100644 tizen_src/impl/browser/password_manager/content_password_manager_driver.h create mode 100644 tizen_src/impl/browser/password_manager/password_form_manager.cc create mode 100644 tizen_src/impl/browser/password_manager/password_form_manager.h create mode 100644 tizen_src/impl/browser/password_manager/password_generation_manager.cc create mode 100644 tizen_src/impl/browser/password_manager/password_generation_manager.h create mode 100644 tizen_src/impl/browser/password_manager/password_manager.cc create mode 100644 tizen_src/impl/browser/password_manager/password_manager.h create mode 100644 tizen_src/impl/browser/password_manager/password_manager_client.cc create mode 100644 tizen_src/impl/browser/password_manager/password_manager_client.h create mode 100644 tizen_src/impl/browser/password_manager/password_manager_driver.h create mode 100644 tizen_src/impl/browser/password_manager/password_manager_util.h create mode 100644 tizen_src/impl/browser/password_manager/password_store_factory.cc create mode 100644 tizen_src/impl/browser/password_manager/password_store_factory.h create mode 100644 tizen_src/impl/browser/webdata/web_data_service.cc create mode 100644 tizen_src/impl/browser/webdata/web_data_service.h create mode 100644 tizen_src/impl/browser/webdata/web_data_service_factory.cc create mode 100644 tizen_src/impl/browser/webdata/web_data_service_factory.h diff --git a/tizen_src/impl/browser/password_manager/content_password_manager_driver.cc b/tizen_src/impl/browser/password_manager/content_password_manager_driver.cc new file mode 100644 index 000000000000..583ab82ab43e --- /dev/null +++ b/tizen_src/impl/browser/password_manager/content_password_manager_driver.cc @@ -0,0 +1,112 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifdef TIZEN_AUTOFILL_SUPPORT + +#include "browser/password_manager/content_password_manager_driver.h" + +#include "components/autofill/content/browser/autofill_driver_impl.h" +#include "components/autofill/content/common/autofill_messages.h" +#include "components/autofill/core/common/password_form.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/navigation_details.h" +#include "content/public/browser/navigation_entry.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/page_transition_types.h" +#include "content/public/common/ssl_status.h" +#include "ipc/ipc_message_macros.h" +#include "net/cert/cert_status_flags.h" + +ContentPasswordManagerDriver::ContentPasswordManagerDriver( + content::WebContents* web_contents, + PasswordManagerClient* client) + : WebContentsObserver(web_contents), + password_manager_(client), + password_generation_manager_(web_contents, client) { + DCHECK(web_contents); +} + +ContentPasswordManagerDriver::~ContentPasswordManagerDriver() {} + +void ContentPasswordManagerDriver::FillPasswordForm( + const autofill::PasswordFormFillData& form_data) { + DCHECK(web_contents()); + web_contents()->GetRenderViewHost()->Send(new AutofillMsg_FillPasswordForm( + web_contents()->GetRenderViewHost()->GetRoutingID(), form_data)); +} + +bool ContentPasswordManagerDriver::DidLastPageLoadEncounterSSLErrors() { + DCHECK(web_contents()); + content::NavigationEntry* entry = + web_contents()->GetController().GetActiveEntry(); + if (!entry) { + NOTREACHED(); + return false; + } + + return net::IsCertStatusError(entry->GetSSL().cert_status); +} + +bool ContentPasswordManagerDriver::IsOffTheRecord() { + DCHECK(web_contents()); + return web_contents()->GetBrowserContext()->IsOffTheRecord(); +} + +PasswordGenerationManager* +ContentPasswordManagerDriver::GetPasswordGenerationManager() { + return &password_generation_manager_; +} + +PasswordManager* ContentPasswordManagerDriver::GetPasswordManager() { + return &password_manager_; +} + +void ContentPasswordManagerDriver::DidNavigateMainFrame( + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params) { + password_manager_.DidNavigateMainFrame(details.is_in_page); +} + +bool ContentPasswordManagerDriver::OnMessageReceived( + const IPC::Message& message) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(PasswordManager, message) + IPC_MESSAGE_FORWARD(AutofillHostMsg_PasswordFormsParsed, + &password_manager_, + PasswordManager::OnPasswordFormsParsed) + IPC_MESSAGE_FORWARD(AutofillHostMsg_PasswordFormsRendered, + &password_manager_, + PasswordManager::OnPasswordFormsRendered) + IPC_MESSAGE_FORWARD(AutofillHostMsg_PasswordFormSubmitted, + &password_manager_, + PasswordManager::OnPasswordFormSubmitted) + IPC_MESSAGE_FORWARD(AutofillHostMsg_ShowPasswordGenerationPopup, + &password_generation_manager_, + PasswordGenerationManager::OnShowPasswordGenerationPopup) + IPC_MESSAGE_FORWARD(AutofillHostMsg_ShowPasswordEditingPopup, + &password_generation_manager_, + PasswordGenerationManager::OnShowPasswordEditingPopup) + IPC_MESSAGE_FORWARD(AutofillHostMsg_HidePasswordGenerationPopup, + &password_generation_manager_, + PasswordGenerationManager::OnHidePasswordGenerationPopup) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + + return handled; +} + +autofill::AutofillManager* ContentPasswordManagerDriver::GetAutofillManager() { + autofill::AutofillDriverImpl* driver = + autofill::AutofillDriverImpl::FromWebContents(web_contents()); + return driver ? driver->autofill_manager() : NULL; +} + +void ContentPasswordManagerDriver::AllowPasswordGenerationForForm( + autofill::PasswordForm* form) { + content::RenderViewHost* host = web_contents()->GetRenderViewHost(); + host->Send(new AutofillMsg_FormNotBlacklisted(host->GetRoutingID(), *form)); +} + +#endif // TIZEN_AUTOFILL_SUPPORT diff --git a/tizen_src/impl/browser/password_manager/content_password_manager_driver.h b/tizen_src/impl/browser/password_manager/content_password_manager_driver.h new file mode 100644 index 000000000000..67f25e07a710 --- /dev/null +++ b/tizen_src/impl/browser/password_manager/content_password_manager_driver.h @@ -0,0 +1,63 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + + +#ifndef CONTENT_PASSWORD_MANAGER_DRIVER_H +#define CONTENT_PASSWORD_MANAGER_DRIVER_H + +#ifdef TIZEN_AUTOFILL_SUPPORT + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "browser/password_manager/password_generation_manager.h" +#include "browser/password_manager/password_manager.h" +#include "browser/password_manager/password_manager_driver.h" +#include "content/public/browser/web_contents_observer.h" + +namespace autofill { +class AutofillManager; +struct PasswordForm; +} + +namespace content { +class WebContents; +} + +class ContentPasswordManagerDriver : public PasswordManagerDriver, + public content::WebContentsObserver { + public: + explicit ContentPasswordManagerDriver(content::WebContents* web_contents, + PasswordManagerClient* client); + virtual ~ContentPasswordManagerDriver(); + + // PasswordManagerDriver implementation. + virtual void FillPasswordForm(const autofill::PasswordFormFillData& form_data) + OVERRIDE; + virtual bool DidLastPageLoadEncounterSSLErrors() OVERRIDE; + virtual bool IsOffTheRecord() OVERRIDE; + virtual PasswordGenerationManager* GetPasswordGenerationManager() OVERRIDE; + virtual PasswordManager* GetPasswordManager() OVERRIDE; + virtual autofill::AutofillManager* GetAutofillManager() OVERRIDE; + virtual void AllowPasswordGenerationForForm(autofill::PasswordForm* form) + OVERRIDE; + + // content::WebContentsObserver overrides. + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + virtual void DidNavigateMainFrame( + const content::LoadCommittedDetails& details, + const content::FrameNavigateParams& params) OVERRIDE; + + private: + // Must outlive this instance. + PasswordManagerClient* client_; + + PasswordManager password_manager_; + PasswordGenerationManager password_generation_manager_; + + DISALLOW_COPY_AND_ASSIGN(ContentPasswordManagerDriver); +}; + +#endif // TIZEN_AUTOFILL_SUPPORT + +#endif // CONTENT_PASSWORD_MANAGER_DRIVER_H diff --git a/tizen_src/impl/browser/password_manager/password_form_manager.cc b/tizen_src/impl/browser/password_manager/password_form_manager.cc new file mode 100644 index 000000000000..0c1375e87086 --- /dev/null +++ b/tizen_src/impl/browser/password_manager/password_form_manager.cc @@ -0,0 +1,648 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifdef TIZEN_AUTOFILL_SUPPORT + +#include "browser/password_manager/password_form_manager.h" + +#include +#include "base/metrics/histogram.h" +#include "base/strings/string_split.h" +#include "base/strings/string_util.h" +#include "browser/password_manager/password_manager.h" +#include "browser/password_manager/password_manager_client.h" +#include "browser/password_manager/password_manager_driver.h" +#include "browser/password_manager/password_store_factory.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_store.h" + +using autofill::FormStructure; +using autofill::PasswordForm; +using autofill::PasswordFormMap; +using base::Time; + +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.ActionsTakenWithPsl", + GetActionsTaken(), + kMaxNumActionsTaken); +} + +int PasswordFormManager::GetActionsTaken() { + return user_action_ + kUserActionMax * (manager_action_ + + kManagerActionMax * submit_result_); +}; + +// TODO(timsteele): use a hash of some sort in the future? +bool PasswordFormManager::DoesManage(const PasswordForm& form, + ActionMatch action_match) const { + if (form.scheme != PasswordForm::SCHEME_HTML) + return observed_form_.signon_realm == form.signon_realm; + + // HTML form case. + // At a minimum, username and password element must match. + if (!((form.username_element == observed_form_.username_element) && + (form.password_element == observed_form_.password_element))) { + return false; + } + + // When action match is required, the action URL must match, but + // the form is allowed to have an empty action URL (See bug 1107719). + // Otherwise ignore action URL, this is to allow saving password form with + // dynamically changed action URL (See bug 27246). + if (form.action.is_valid() && (form.action != observed_form_.action)) { + if (action_match == ACTION_MATCH_REQUIRED) + return false; + } + + // If this is a replay of the same form in the case a user entered an invalid + // password, the origin of the new form may equal the action of the "first" + // form. + if (!((form.origin == observed_form_.origin) || + (form.origin == observed_form_.action))) { + if (form.origin.SchemeIsSecure() && + !observed_form_.origin.SchemeIsSecure()) { + // Compare origins, ignoring scheme. There is no easy way to do this + // with GURL because clearing the scheme would result in an invalid url. + // This is for some sites (such as Hotmail) that begin on an http page and + // head to https for the retry when password was invalid. + 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); + + // Configure the form about to be saved for blacklist status. + pending_credentials_.preferred = true; + pending_credentials_.blacklisted_by_user = true; + pending_credentials_.username_value.clear(); + pending_credentials_.password_value.clear(); + + // Retroactively forget existing matches for this form, so we NEVER prompt or + // autofill it again. + 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) { + // We want to remove existing matches for this form so that the exact + // origin match with |blackisted_by_user == true| is the only result that + // shows up in the future for this origin URL. However, we don't want to + // delete logins that were actually saved on a different page (hence with + // different origin URL) and just happened to match this form because of + // the scoring algorithm. See bug 1204493. + if (iter->second->origin == observed_form_.origin) { + password_store->RemoveLogin(*iter->second); + ++num_passwords_deleted; + } + } + } + + UMA_HISTOGRAM_COUNTS("PasswordManager.NumPasswordsDeletedWhenBlacklisting", + num_passwords_deleted); + + // Save the pending_credentials_ entry marked as blacklisted. + 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() { + // This check is permissive, as the user may have generated a password and + // then edited it in the form itself. However, even in this case the user + // has already given consent, so we treat these cases the same. + return has_generated_password_; +} + +bool PasswordFormManager::HasValidPasswordForm() { + DCHECK_EQ(state_, POST_MATCHING_PHASE); + // 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) + 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)); + + // 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; + + // Public suffix matches should always be new logins, since we want to store + // them so they can automatically be filled in later. + is_new_login_ = IsPendingCredentialsPublicSuffixMatch(); + if (is_new_login_) + user_action_ = kUserActionChoosePslMatch; + + // Check to see if we're using a known username but a new password. + if (pending_credentials_.password_value != credentials.password_value) + user_action_ = kUserActionOverride; + } 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_ = kUserActionOverride; + 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 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 = credentials.password_value; + pending_credentials_.preferred = credentials.preferred; + + 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& logins_result) { + // Note that the result gets deleted after this call completes, but we own + // the PasswordForm objects pointed to by the result vector, thus we keep + // copies to a minimum here. + + int best_score = 0; + // These credentials will be in the final result regardless of score. + std::vector credentials_to_keep; + for (size_t i = 0; i < logins_result.size(); i++) { + if (IgnoreResult(*logins_result[i])) { + delete logins_result[i]; + continue; + } + // Score and update best matches. + int current_score = ScoreResult(*logins_result[i]); + // This check is here so we can append empty path matches in the event + // they don't score as high as others and aren't added to best_matches_. + // This is most commonly imported firefox logins. We skip blacklisted + // ones because clearly we don't want to autofill them, and secondly + // because they only mean something when we have no other matches already + // saved in Chrome - in which case they'll make it through the regular + // scoring flow below by design. Note signon_realm == origin implies empty + // path logins_result, since signon_realm is a prefix of origin for HTML + // password forms. + // TODO(timsteele): Bug 1269400. We probably should do something more + // elegant for any shorter-path match instead of explicitly handling empty + // path matches. + 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]); + } + + // Always keep generated passwords as part of the result set. If a user + // generates a password on a signup form, it should show on a login form + // even if they have a previous login saved. + // TODO(gcasto): We don't want to cut credentials that were saved on signup + // forms even if they weren't generated, but currently it's hard to + // distinguish between those forms and two different login forms on the + // same domain. Filed http://crbug.com/294468 to look into this. + 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; + // This new login has a better score than all those up to this point + // Note 'this' owns all the PasswordForms in best_matches_. + STLDeleteValues(&best_matches_); + best_matches_.clear(); + preferred_match_ = NULL; // Don't delete, its owned by best_matches_. + best_matches_[logins_result[i]->username_value] = logins_result[i]; + } + preferred_match_ = logins_result[i]->preferred ? logins_result[i] + : preferred_match_; + } + // We're done matching now. + state_ = POST_MATCHING_PHASE; + + if (best_score <= 0) { + return; + } + + for (std::vector::const_iterator it = + credentials_to_keep.begin(); + it != credentials_to_keep.end(); ++it) { + // If we don't already have a result with the same username, add the + // lower-scored match (if it had equal score it would already be in + // best_matches_). + 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()); + + // It is possible we have at least one match but have no preferred_match_, + // because a user may have chosen to 'Forget' the preferred match. So we + // just pick the first one and whichever the user selects for submit will + // be saved as preferred. + DCHECK(!best_matches_.empty()); + if (!preferred_match_) + preferred_match_ = best_matches_.begin()->second; + + // Check to see if the user told us to ignore this site in the past. + if (preferred_match_->blacklisted_by_user) { + manager_action_ = kManagerActionBlacklisted; + return; + } + + // If not blacklisted, inform the driver that password generation is allowed + // for |observed_form_|. + driver_->AllowPasswordGenerationForForm(&observed_form_); + + // Proceed to autofill. + // Note that we provide the choices but don't actually prefill a value if: + // (1) we are in Incognito mode, (2) the ACTION paths don't match, + // or (3) if it matched using public suffix domain matching. + 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& results) { + DCHECK_EQ(state_, MATCHING_PHASE); + + if (results.empty()) { + state_ = POST_MATCHING_PHASE; + // No result means that we visit this site the first time so we don't need + // to check whether this site is blacklisted or not. Just send a message + // to allow password generation. + driver_->AllowPasswordGenerationForForm(&observed_form_); + return; + } + OnRequestDone(results); +} + +bool PasswordFormManager::IgnoreResult(const PasswordForm& form) const { + // Ignore change password forms until we have some change password + // functionality + if (observed_form_.old_password_element.length() != 0) { + return true; + } + // Don't match an invalid SSL form with one saved under secure + // circumstances. + 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()); + // The new_form is being used to sign in, so it is preferred. + DCHECK(pending_credentials_.preferred); + // new_form contains the same basic data as observed_form_ (because its the + // same form), but with the newly added credentials. + + 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) { + // Remove any possible usernames that could be credit cards or SSN for privacy + // reasons. Also remove duplicates, both in other_possible_usernames and + // between other_possible_usernames and username_value. + std::set set; + for (std::vector::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 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) { + // This wasn't the selected login but it used to be 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_); + // If we're doing an Update, we either autofilled correctly and need to + // update the stats, or the user typed in a new password for autofilled + // username, or the user selected one of the non-preferred matches, + // thus requiring a swap of preferred bits. + DCHECK(!IsNewLogin() && pending_credentials_.preferred); + DCHECK(!driver_->IsOffTheRecord()); + + PasswordStore* password_store = client_->GetPasswordStore(); + if (!password_store) { + NOTREACHED(); + return; + } + + // Update metadata. + ++pending_credentials_.times_used; + + // Check to see if this form is a candidate for password generation. + CheckForAccountCreationForm(pending_credentials_, observed_form_); + + UpdatePreferredLoginState(password_store); + + // Remove alternate usernames. At this point we assume that we have found + // the right username. + pending_credentials_.other_possible_usernames.clear(); + + // Update the new preferred login. + if (!selected_username_.empty()) { + // An other possible username is selected. We set this selected username + // as the real username. The PasswordStore API isn't designed to update + // username, so we delete the old credentials and add a new one instead. + 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())) { + // Note origin.spec().length > signon_realm.length implies the origin has a + // path, since signon_realm is a prefix of origin for HTML password forms. + // + // The user logged in successfully with one of our autofilled logins on a + // page with non-empty path, but the autofilled entry was initially saved/ + // imported with an empty path. Rather than just mark this entry preferred, + // we create a more specific copy for this exact page and leave the "master" + // unchanged. This is to prevent the case where that master login is used + // on several sites (e.g site.com/a and site.com/b) but the user actually + // has a different preference on each site. For example, on /a, he wants the + // general empty-path login so it is flagged as preferred, but on /b he logs + // in with a different saved entry - we don't want to remove the preferred + // status of the former because upon return to /a it won't be the default- + // fill match. + // TODO(timsteele): Bug 1188626 - expire the master copies. + 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) { + // We check to see if the saved form_data is the same as the observed + // form_data, which should never be true for passwords saved on account + // creation forms. This check is only made the first time a password is used + // to cut down on false positives. Specifically a site may have multiple login + // forms with different markup, which might look similar to a signup form. + if (pending.times_used == 1) { + FormStructure pending_structure(pending.form_data); + FormStructure observed_structure(observed.form_data); + // Ignore |pending_structure| if its FormData has no fields. This is to + // weed out those credentials that were saved before FormData was added + // to PasswordForm. Even without this check, these FormStructure's won't + // be uploaded, but it makes it hard to see if we are encountering + // unexpected errors. + if (!pending.form_data.fields.empty() && + pending_structure.FormSignature() != + observed_structure.FormSignature()) { + autofill::AutofillManager* autofill_manager; + if ((autofill_manager = driver_->GetAutofillManager())) { + // Note that this doesn't guarantee that the upload succeeded, only that + // |pending.form_data| is considered uploadable. + 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); + // For scoring of candidate login data: + // The most important element that should match is the origin, followed by + // the action, the password name, the submit button name, and finally the + // username input field name. + // Exact origin match gives an addition of 64 (1 << 6) + # of matching url + // dirs. + // Partial match gives an addition of 32 (1 << 5) + # matching url dirs + // That way, a partial match cannot trump an exact match even if + // the partial one matches all other attributes (action, elements) (and + // regardless of the matching depth in the URL path). + // If public suffix origin match was not used, it gives an addition of + // 16 (1 << 4). + int score = 0; + if (candidate.origin == observed_form_.origin) { + // This check is here for the most common case which + // is we have a single match in the db for the given host, + // so we don't generally need to walk the entire URL path (the else + // clause). + score += (1 << 6) + static_cast(form_path_tokens_.size()); + } else { + // Walk the origin URL paths one directory at a time to see how + // deep the two match. + std::vector 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++; + } + // do we have a partial match? + 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; +} + +void PasswordFormManager::SubmitFailed() { + submit_result_ = kSubmitResultFailed; +} +#endif // TIZEN_AUTOFILL_SUPPORT diff --git a/tizen_src/impl/browser/password_manager/password_form_manager.h b/tizen_src/impl/browser/password_manager/password_form_manager.h new file mode 100644 index 000000000000..55df4c9e426c --- /dev/null +++ b/tizen_src/impl/browser/password_manager/password_form_manager.h @@ -0,0 +1,320 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PASSWORD_FORM_MANAGER_H +#define PASSWORD_FORM_MANAGER_H + +#ifdef TIZEN_AUTOFILL_SUPPORT + +#include +#include + +#include "build/build_config.h" + +#include "base/stl_util.h" +#include "browser/password_manager/password_manager_driver.h" +#include "components/autofill/core/common/password_form.h" +#include "components/password_manager/core/browser/password_store.h" +#include "components/password_manager/core/browser/password_store_consumer.h" + +namespace content { +class WebContents; +} // namespace content + +class PasswordManager; +class PasswordManagerClient; + +// Per-password-form-{on-page, dialog} class responsible for interactions +// between a given form, the per-tab PasswordManager, and the PasswordStore. +class PasswordFormManager : public PasswordStoreConsumer { + public: + // |password_manager| owns this object + // |form_on_page| is the form that may be submitted and could need login data. + // |ssl_valid| represents the security of the page containing observed_form, + // used to filter login results from database. + PasswordFormManager(PasswordManager* password_manager, + PasswordManagerClient* client, + PasswordManagerDriver* driver, + const autofill::PasswordForm& observed_form, + bool ssl_valid); + virtual ~PasswordFormManager(); + + enum ActionMatch { + ACTION_MATCH_REQUIRED, + ACTION_MATCH_NOT_REQUIRED + }; + + enum OtherPossibleUsernamesAction { + ALLOW_OTHER_POSSIBLE_USERNAMES, + IGNORE_OTHER_POSSIBLE_USERNAMES + }; + + // Compare basic data of observed_form_ with argument. Only check the action + // URL when action match is required. + bool DoesManage(const autofill::PasswordForm& form, + ActionMatch action_match) const; + + // Retrieves potential matching logins from the database. + // |prompt_policy| indicates whether it's permissible to prompt the user to + // authorize access to locked passwords. This argument is only used on + // platforms that support prompting the user for access (such as Mac OS). + void FetchMatchingLoginsFromPasswordStore( + PasswordStore::AuthorizationPromptPolicy prompt_policy); + + // Simple state-check to verify whether this object as received a callback + // from the PasswordStore and completed its matching phase. Note that the + // callback in question occurs on the same (and only) main thread from which + // instances of this class are ever used, but it is required since it is + // conceivable that a user (or ui test) could attempt to submit a login + // prompt before the callback has occured, which would InvokeLater a call to + // PasswordManager::ProvisionallySave, which would interact with this object + // before the db has had time to answer with matching password entries. + // This is intended to be a one-time check; if the return value is false the + // expectation is caller will give up. This clearly won't work if you put it + // in a loop and wait for matching to complete; you're (supposed to be) on + // the same thread! + bool HasCompletedMatching(); + + // Determines if the user opted to 'never remember' passwords for this form. + bool IsBlacklisted(); + + // Used by PasswordManager to determine whether or not to display + // a SavePasswordBar when given the green light to save the PasswordForm + // managed by this. + bool IsNewLogin(); + + // Returns true if the current pending credentials were found using + // origin matching of the public suffix, instead of the signon realm of the + // form. + bool IsPendingCredentialsPublicSuffixMatch(); + + // Checks if the form is a valid password form. Forms which lack either + // login or password field are not considered valid. + bool HasValidPasswordForm(); + + // These functions are used to determine if this form has had it's password + // auto generated by the browser. + bool HasGeneratedPassword(); + void SetHasGeneratedPassword(); + + // Determines if we need to autofill given the results of the query. + // Takes ownership of the elements in |result|. + void OnRequestDone(const std::vector& result); + + virtual void OnGetPasswordStoreResults( + const std::vector& results) OVERRIDE; + + // A user opted to 'never remember' passwords for this form. + // Blacklist it so that from now on when it is seen we ignore it. + // TODO: Make this private once we switch to the new UI. + void PermanentlyBlacklist(); + + // Sets whether the password form should use additional password + // authentication if available before being used for autofill. + void SetUseAdditionalPasswordAuthentication( + bool use_additional_authentication); + + // If the user has submitted observed_form_, provisionally hold on to + // the submitted credentials until we are told by PasswordManager whether + // or not the login was successful. |action| describes how we deal with + // possible usernames. If |action| is ALLOW_OTHER_POSSIBLE_USERNAMES we will + // treat a possible usernames match as a sign that our original heuristics + // were wrong and that the user selected the correct username from the + // Autofill UI. + void ProvisionallySave(const autofill::PasswordForm& credentials, + OtherPossibleUsernamesAction action); + + // Handles save-as-new or update of the form managed by this manager. + // Note the basic data of updated_credentials must match that of + // observed_form_ (e.g DoesManage(pending_credentials_) == true). + // TODO: Make this private once we switch to the new UI. + void Save(); + + // Call these if/when we know the form submission worked or failed. + // These routines are used to update internal statistics ("ActionsTaken"). + void SubmitPassed(); + void SubmitFailed(); + + // Returns the username associated with the credentials. + const base::string16& associated_username() const { + return pending_credentials_.username_value; + } + + // Returns the pending credentials. + const autofill::PasswordForm pending_credentials() const { + return pending_credentials_; + } + + // Returns the best matches. + const autofill::PasswordFormMap best_matches() const { + return best_matches_; + } + + // Returns the realm URL for the form managed my this manager. + const std::string& realm() const { + return pending_credentials_.signon_realm; + } + + private: + friend class PasswordFormManagerTest; + + // ManagerAction - What does the manager do with this form? Either it + // fills it, or it doesn't. If it doesn't fill it, that's either + // because it has no match, or it is blacklisted, or it is disabled + // via the AUTOCOMPLETE=off attribute. Note that if we don't have + // an exact match, we still provide candidates that the user may + // end up choosing. + enum ManagerAction { + kManagerActionNone = 0, + kManagerActionAutofilled, + kManagerActionBlacklisted, + kManagerActionMax + }; + + // UserAction - What does the user do with this form? If he or she + // does nothing (either by accepting what the password manager did, or + // by simply (not typing anything at all), you get None. If there were + // multiple choices and the user selects one other than the default, + // you get Choose, if user selects an entry from matching against the Public + // Suffix List you get ChoosePslMatch, and if the user types in a new value, + // you get Override. + enum UserAction { + kUserActionNone = 0, + kUserActionChoose, + kUserActionChoosePslMatch, + kUserActionOverride, + kUserActionMax + }; + + // Result - What happens to the form? + enum SubmitResult { + kSubmitResultNotSubmitted = 0, + kSubmitResultFailed, + kSubmitResultPassed, + kSubmitResultMax + }; + + // The maximum number of combinations of the three preceding enums. + // This is used when recording the actions taken by the form in UMA. + static const int kMaxNumActionsTaken = kManagerActionMax * kUserActionMax * + kSubmitResultMax; + + // Helper for OnGetPasswordStoreResults to determine whether or not + // the given result form is worth scoring. + bool IgnoreResult(const autofill::PasswordForm& form) const; + + // Helper for Save in the case that best_matches.size() == 0, meaning + // we have no prior record of this form/username/password and the user + // has opted to 'Save Password'. If |reset_preferred_login| is set, + // the previously preferred login from |best_matches_| will be reset. + void SaveAsNewLogin(bool reset_preferred_login); + + // Helper for OnGetPasswordStoreResults to score an individual result + // against the observed_form_. + int ScoreResult(const autofill::PasswordForm& form) const; + + // Helper for Save in the case that best_matches.size() > 0, meaning + // we have at least one match for this form/username/password. This + // Updates the form managed by this object, as well as any matching forms + // that now need to have preferred bit changed, since updated_credentials + // is now implicitly 'preferred'. + void UpdateLogin(); + + // Check to see if |pending| corresponds to an account creation form. If we + // think that it does, we label it as such and upload this state to the + // Autofill server, so that we will trigger password generation in the future. + void CheckForAccountCreationForm(const autofill::PasswordForm& pending, + const autofill::PasswordForm& observed); + + // Update all login matches to reflect new preferred state - preferred flag + // will be reset on all matched logins that different than the current + // |pending_credentials_|. + void UpdatePreferredLoginState(PasswordStore* password_store); + + // Returns true if |username| is one of the other possible usernames for a + // password form in |best_matches_| and sets |pending_credentials_| to the + // match which had this username. + bool UpdatePendingCredentialsIfOtherPossibleUsername( + const base::string16& username); + + // Converts the "ActionsTaken" fields into an int so they can be logged to + // UMA. + int GetActionsTaken(); + + // Remove possible_usernames that may contains sensitive information and + // duplicates. + void SanitizePossibleUsernames(autofill::PasswordForm* form); + + // Set of PasswordForms from the DB that best match the form + // being managed by this. Use a map instead of vector, because we most + // frequently require lookups by username value in IsNewLogin. + autofill::PasswordFormMap best_matches_; + + // Cleans up when best_matches_ goes out of scope. + STLValueDeleter best_matches_deleter_; + + // The PasswordForm from the page or dialog managed by this. + autofill::PasswordForm observed_form_; + + // The origin url path of observed_form_ tokenized, for convenience when + // scoring. + std::vector form_path_tokens_; + + // Stores updated credentials when the form was submitted but success is + // still unknown. + autofill::PasswordForm pending_credentials_; + + // Whether pending_credentials_ stores a new login or is an update + // to an existing one. + bool is_new_login_; + + // Whether this form has an auto generated password. + bool has_generated_password_; + + // Set if the user has selected one of the other possible usernames in + // |pending_credentials_|. + base::string16 selected_username_; + + // PasswordManager owning this. + const PasswordManager* const password_manager_; + + // Convenience pointer to entry in best_matches_ that is marked + // as preferred. This is only allowed to be null if there are no best matches + // at all, since there will always be one preferred login when there are + // multiple matches (when first saved, a login is marked preferred). + const autofill::PasswordForm* preferred_match_; + + typedef enum { + PRE_MATCHING_PHASE, // Have not yet invoked a GetLogins query to find + // matching login information from password store. + MATCHING_PHASE, // We've made a GetLogins request, but + // haven't received or finished processing result. + POST_MATCHING_PHASE // We've queried the DB and processed matching + // login results. + } PasswordFormManagerState; + + // State of matching process, used to verify that we don't call methods + // assuming we've already processed the request for matching logins, + // when we actually haven't. + PasswordFormManagerState state_; + + // The client which implements embedder-specific PasswordManager operations. + PasswordManagerClient* client_; + + // The driver which implements platform-specific PasswordManager operations. + PasswordManagerDriver* driver_; + + // These three fields record the "ActionsTaken" by the browser and + // the user with this form, and the result. They are combined and + // recorded in UMA when the manager is destroyed. + ManagerAction manager_action_; + UserAction user_action_; + SubmitResult submit_result_; + + DISALLOW_COPY_AND_ASSIGN(PasswordFormManager); +}; + +#endif // TIZEN_AUTOFILL_SUPPORT + +#endif // PASSWORD_FORM_MANAGER_H diff --git a/tizen_src/impl/browser/password_manager/password_generation_manager.cc b/tizen_src/impl/browser/password_manager/password_generation_manager.cc new file mode 100644 index 000000000000..6b67e225b73f --- /dev/null +++ b/tizen_src/impl/browser/password_manager/password_generation_manager.cc @@ -0,0 +1,117 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifdef TIZEN_AUTOFILL_SUPPORT + +#include "browser/password_manager/password_generation_manager.h" + +#include "browser/password_manager/password_manager.h" +#include "browser/password_manager/password_manager_client.h" +#include "browser/password_manager/password_manager_driver.h" +#include "components/autofill/content/common/autofill_messages.h" +#include "components/autofill/core/browser/autofill_field.h" +#include "components/autofill/core/browser/field_types.h" +#include "components/autofill/core/browser/form_structure.h" +#include "components/autofill/core/browser/password_generator.h" +#include "components/autofill/core/common/form_data.h" +#include "components/autofill/core/common/password_form.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_view.h" +#include "ui/gfx/rect.h" + +PasswordGenerationManager::PasswordGenerationManager( + content::WebContents* contents, + PasswordManagerClient* client) + : web_contents_(contents), + observer_(NULL), + client_(client), + driver_(client->GetDriver()) {} + +PasswordGenerationManager::~PasswordGenerationManager() {} + +void PasswordGenerationManager::SetTestObserver( + autofill::PasswordGenerationPopupObserver* observer) { + observer_ = observer; +} + +void PasswordGenerationManager::DetectAccountCreationForms( + const std::vector& forms) { + std::vector account_creation_forms; + for (std::vector::const_iterator form_it = + forms.begin(); form_it != forms.end(); ++form_it) { + autofill::FormStructure* form = *form_it; + for (std::vector::const_iterator field_it = + form->begin(); field_it != form->end(); ++field_it) { + autofill::AutofillField* field = *field_it; + if (field->server_type() == autofill::ACCOUNT_CREATION_PASSWORD) { + account_creation_forms.push_back(form->ToFormData()); + break; + } + } + } + if (!account_creation_forms.empty() && IsGenerationEnabled()) { + SendAccountCreationFormsToRenderer(web_contents_->GetRenderViewHost(), + account_creation_forms); + } +} + +// In order for password generation to be enabled, we need to make sure: +// (1) Password sync is enabled, and +// (2) Password saving is enabled. +bool PasswordGenerationManager::IsGenerationEnabled() const +{ + if (!driver_->GetPasswordManager()->IsPasswordManagerEnabled()) { + DVLOG(2) << "Generation disabled because password saving is disabled"; + return false; + } + + if (!client_->IsPasswordSyncEnabled()) { + DVLOG(2) << "Generation disabled because passwords are not being synced"; + return false; + } + + return true; +} + +void PasswordGenerationManager::SendAccountCreationFormsToRenderer( + content::RenderViewHost* host, + const std::vector& forms) { + host->Send(new AutofillMsg_AccountCreationFormsDetected( + host->GetRoutingID(), forms)); +} + +gfx::RectF PasswordGenerationManager::GetBoundsInScreenSpace( + const gfx::RectF& bounds) { + gfx::Rect client_area; + web_contents_->GetView()->GetContainerBounds(&client_area); + return bounds + client_area.OffsetFromOrigin(); +} + +void PasswordGenerationManager::OnShowPasswordGenerationPopup( + const gfx::RectF& bounds, + int max_length, + const autofill::PasswordForm& form) +{ + // TODO: Call Popup for Password +} + +void PasswordGenerationManager::OnShowPasswordEditingPopup( + const gfx::RectF& bounds, + const autofill::PasswordForm& form) +{ + // TODO: Call Popup for Edit Password +} + +void PasswordGenerationManager::OnHidePasswordGenerationPopup() +{ + HidePopup(); +} + +void PasswordGenerationManager::HidePopup() +{ + // TODO: Call Popup Hide +} + +#endif // TIZEN_AUTOFILL_SUPPORT diff --git a/tizen_src/impl/browser/password_manager/password_generation_manager.h b/tizen_src/impl/browser/password_manager/password_generation_manager.h new file mode 100644 index 000000000000..cd06de2350de --- /dev/null +++ b/tizen_src/impl/browser/password_manager/password_generation_manager.h @@ -0,0 +1,128 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PASSWORD_GENERATION_MANAGER_H +#define PASSWORD_GENERATION_MANAGER_H + +#ifdef TIZEN_AUTOFILL_SUPPORT + +#include + +#include "base/basictypes.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "ui/gfx/rect.h" + +class PasswordManager; +class PasswordManagerClient; +class PasswordManagerDriver; + +namespace autofill { +struct FormData; +class FormStructure; +class PasswordGenerator; +class PasswordGenerationPopupObserver; +struct PasswordForm; +} + +namespace content { +class RenderViewHost; +class WebContents; +} + +namespace user_prefs { +class PrefRegistrySyncable; +} + +// Per-tab manager for password generation. Will enable this feature only if +// +// - Password manager is enabled +// - Password sync is enabled +// +// NOTE: At the moment, the creation of the renderer PasswordGenerationManager +// is controlled by a switch (--enable-password-generation) so this feature will +// not be enabled regardless of the above criteria without the switch being +// present. +// +// This class is used to determine what forms we should offer to generate +// passwords for and manages the popup which is created if the user chooses to +// generate a password. +class PasswordGenerationManager { + public: + PasswordGenerationManager(content::WebContents* contents, + PasswordManagerClient* client); + virtual ~PasswordGenerationManager(); + + // Detect account creation forms from forms with autofill type annotated. + // Will send a message to the renderer if we find a correctly annotated form + // and the feature is enabled. + void DetectAccountCreationForms( + const std::vector& forms); + + // Hide any visible password generation related popups. + void HidePopup(); + + // Observer for PasswordGenerationPopup events. Used for testing. + void SetTestObserver(autofill::PasswordGenerationPopupObserver* observer); + + // Causes the password generation UI to be shown for the specified form. + // The popup will be anchored at |element_bounds|. The generated password + // will be no longer than |max_length|. + void OnShowPasswordGenerationPopup(const gfx::RectF& element_bounds, + int max_length, + const autofill::PasswordForm& form); + + // Causes the password editing UI to be shown anchored at |element_bounds|. + void OnShowPasswordEditingPopup(const gfx::RectF& element_bounds, + const autofill::PasswordForm& form); + + // Hides any visible UI. + void OnHidePasswordGenerationPopup(); + + private: + friend class PasswordGenerationManagerTest; + + // Determines current state of password generation + bool IsGenerationEnabled() const; + + // Sends a message to the renderer specifying form(s) that we should enable + // password generation on. This is a separate function to aid in testing. + virtual void SendAccountCreationFormsToRenderer( + content::RenderViewHost* host, + const std::vector& forms); + + // Given |bounds| in the renderers coordinate system, return the same bounds + // in the screens coordinate system. + gfx::RectF GetBoundsInScreenSpace(const gfx::RectF& bounds); + + // The WebContents instance associated with this instance. Scoped to the + // lifetime of this class, as this class is indirectly a WCUD via + // ChromePasswordManagerClient. + // TODO(blundell): Eliminate this ivar. crbug.com/340675 + content::WebContents* web_contents_; + + // Observer for password generation popup. + autofill::PasswordGenerationPopupObserver* observer_; + + // Controls how passwords are generated. + scoped_ptr password_generator_; + + // Controls the popup + //base::WeakPtr< + // autofill::PasswordGenerationPopupControllerImpl> popup_controller_; + + // The PasswordManagerClient instance associated with this instance. Must + // outlive this instance. + PasswordManagerClient* client_; + + // The PasswordManagerDriver instance associated with this instance. Must + // outlive this instance. + PasswordManagerDriver* driver_; + + DISALLOW_COPY_AND_ASSIGN(PasswordGenerationManager); +}; + +#endif // TIZEN_AUTOFILL_SUPPORT + +#endif // PASSWORD_GENERATION_MANAGER_H diff --git a/tizen_src/impl/browser/password_manager/password_manager.cc b/tizen_src/impl/browser/password_manager/password_manager.cc new file mode 100644 index 000000000000..cfc7f9e146af --- /dev/null +++ b/tizen_src/impl/browser/password_manager/password_manager.cc @@ -0,0 +1,380 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifdef TIZEN_AUTOFILL_SUPPORT + +#include "browser/password_manager/password_manager.h" + +#include "base/command_line.h" +#include "base/metrics/field_trial.h" +#include "base/metrics/histogram.h" +#include "base/prefs/pref_service.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "base/threading/platform_thread.h" +#include "browser/password_manager/password_form_manager.h" +#include "browser/password_manager/password_manager_client.h" +#include "browser/password_manager/password_manager_driver.h" +#include "components/autofill/core/common/password_autofill_util.h" +#include "components/password_manager/core/browser/password_manager_metrics_util.h" +#include "components/password_manager/core/common/password_manager_pref_names.h" +#include "components/user_prefs/pref_registry_syncable.h" + +using autofill::PasswordForm; +using autofill::PasswordFormMap; + +namespace { + +const char kSpdyProxyRealm[] = "/SpdyProxy"; + +// This routine is called when PasswordManagers are constructed. +// +// Currently we report metrics only once at startup. We require +// that this is only ever called from a single thread in order to +// avoid needing to lock (a static boolean flag is then sufficient to +// guarantee running only once). +void ReportMetrics(bool password_manager_enabled) { + static base::PlatformThreadId initial_thread_id = + base::PlatformThread::CurrentId(); + DCHECK(initial_thread_id == base::PlatformThread::CurrentId()); + + static bool ran_once = false; + if (ran_once) + return; + ran_once = true; + + UMA_HISTOGRAM_BOOLEAN("PasswordManager.Enabled", password_manager_enabled); +} + +} // namespace + +const char PasswordManager::kOtherPossibleUsernamesExperiment[] = + "PasswordManagerOtherPossibleUsernames"; + +// static +void PasswordManager::RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) { +} + +PasswordManager::PasswordManager(PasswordManagerClient* client) + : client_(client), driver_(client->GetDriver()) { + DCHECK(client_); + DCHECK(driver_); + password_manager_enabled_ = false; +} + +PasswordManager::~PasswordManager() +{ + FOR_EACH_OBSERVER(LoginModelObserver, observers_, OnLoginModelDestroying()); +} + +void PasswordManager::SetFormHasGeneratedPassword(const PasswordForm& form) { + for (ScopedVector::iterator iter = + pending_login_managers_.begin(); + iter != pending_login_managers_.end(); ++iter) { + if ((*iter)->DoesManage( + form, PasswordFormManager::ACTION_MATCH_REQUIRED)) { + (*iter)->SetHasGeneratedPassword(); + return; + } + } + // If there is no corresponding PasswordFormManager, we create one. This is + // not the common case, and should only happen when there is a bug in our + // ability to detect forms. + bool ssl_valid = (form.origin.SchemeIsSecure() && + !driver_->DidLastPageLoadEncounterSSLErrors()); + PasswordFormManager* manager = new PasswordFormManager( + this, client_, driver_, form, ssl_valid); + pending_login_managers_.push_back(manager); + manager->SetHasGeneratedPassword(); +} + +bool PasswordManager::IsPasswordManagerEnabled() const +{ + return password_manager_enabled_ && !driver_->IsOffTheRecord(); +} + +void PasswordManager::SetPasswordManagerEnabled(bool enabled) +{ + password_manager_enabled_ = enabled; +} + +void PasswordManager::ProvisionallySavePassword(const PasswordForm& form) +{ + if (!IsPasswordManagerEnabled()) { + RecordFailure(SAVING_DISABLED, form.origin.host()); + return; + } + + // No password to save? Then don't. + if (form.password_value.empty()) { + RecordFailure(EMPTY_PASSWORD, form.origin.host()); + return; + } + + scoped_ptr manager; + ScopedVector::iterator matched_manager_it = + pending_login_managers_.end(); + for (ScopedVector::iterator iter = + pending_login_managers_.begin(); + iter != pending_login_managers_.end(); ++iter) { + // If we find a manager that exactly matches the submitted form including + // the action URL, exit the loop. + if ((*iter)->DoesManage( + form, PasswordFormManager::ACTION_MATCH_REQUIRED)) { + matched_manager_it = iter; + break; + // If the current manager matches the submitted form excluding the action + // URL, remember it as a candidate and continue searching for an exact + // match. + } else if ((*iter)->DoesManage( + form, PasswordFormManager::ACTION_MATCH_NOT_REQUIRED)) { + matched_manager_it = iter; + } + } + // 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 (matched_manager_it != pending_login_managers_.end()) { + // Transfer ownership of the manager from |pending_login_managers_| to + // |manager|. + manager.reset(*matched_manager_it); + pending_login_managers_.weak_erase(matched_manager_it); + } else { + RecordFailure(NO_MATCHING_FORM, form.origin.host()); + return; + } + + if (!manager->HasCompletedMatching()) { + RecordFailure(MATCHING_NOT_COMPLETE, form.origin.host()); + return; + } + + if (manager->IsBlacklisted()) { + RecordFailure(FORM_BLACKLISTED, form.origin.host()); + return; + } + + // Bail if we're missing any of the necessary form components. + if (!manager->HasValidPasswordForm()) { + RecordFailure(INVALID_FORM, form.origin.host()); + return; + } + + // Always save generated passwords, as the user expresses explicit intent for + // Chrome to manage such passwords. For other passwords, respect the + // autocomplete attribute if autocomplete='off' is not ignored. + if (!autofill::ShouldIgnoreAutocompleteOffForPasswordFields() && + !manager->HasGeneratedPassword() && + !form.password_autocomplete_set) { + RecordFailure(AUTOCOMPLETE_OFF, form.origin.host()); + return; + } + + PasswordForm provisionally_saved_form(form); + provisionally_saved_form.ssl_valid = + form.origin.SchemeIsSecure() && + !driver_->DidLastPageLoadEncounterSSLErrors(); + provisionally_saved_form.preferred = true; + PasswordFormManager::OtherPossibleUsernamesAction action = + PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES; + if (OtherPossibleUsernamesEnabled()) + action = PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES; + manager->ProvisionallySave(provisionally_saved_form, action); + provisional_save_manager_.swap(manager); +} + +void PasswordManager::RecordFailure(ProvisionalSaveFailure failure, const std::string& form_origin) +{ +} + +void PasswordManager::AddSubmissionCallback( + const PasswordSubmittedCallback& callback) { + submission_callbacks_.push_back(callback); +} + +void PasswordManager::AddObserver(LoginModelObserver* observer) { + observers_.AddObserver(observer); +} + +void PasswordManager::RemoveObserver(LoginModelObserver* observer) { + observers_.RemoveObserver(observer); +} + +void PasswordManager::DidNavigateMainFrame(bool is_in_page) { + // Clear data after main frame navigation if the navigation was to a + // different page. + if (!is_in_page) + pending_login_managers_.clear(); +} + +void PasswordManager::OnPasswordFormSubmitted( + const PasswordForm& password_form) { + ProvisionallySavePassword(password_form); + for (size_t i = 0; i < submission_callbacks_.size(); ++i) { + submission_callbacks_[i].Run(password_form); + } + + pending_login_managers_.clear(); +} + +void PasswordManager::OnPasswordFormsParsed( + const std::vector& forms) { + if(!IsPasswordManagerEnabled()) { + return; + } + // Ask the SSLManager for current security. + bool had_ssl_error = driver_->DidLastPageLoadEncounterSSLErrors(); + + for (std::vector::const_iterator iter = forms.begin(); + iter != forms.end(); ++iter) { + // Don't involve the password manager if this form corresponds to + // SpdyProxy authentication, as indicated by the realm. + if (EndsWith(iter->signon_realm, kSpdyProxyRealm, true)) + continue; + + bool ssl_valid = iter->origin.SchemeIsSecure() && !had_ssl_error; + PasswordFormManager* manager = new PasswordFormManager( + this, client_, driver_, *iter, ssl_valid); + pending_login_managers_.push_back(manager); + + // Avoid prompting the user for access to a password if they don't have + // password saving enabled. + PasswordStore::AuthorizationPromptPolicy prompt_policy = + password_manager_enabled_ ? PasswordStore::ALLOW_PROMPT + : PasswordStore::DISALLOW_PROMPT; + + manager->FetchMatchingLoginsFromPasswordStore(prompt_policy); + } +} + +bool PasswordManager::ShouldPromptUserToSavePassword() const { + return provisional_save_manager_->IsNewLogin() && + !provisional_save_manager_->HasGeneratedPassword() && + !provisional_save_manager_->IsPendingCredentialsPublicSuffixMatch(); +} + +void PasswordManager::OnPasswordFormsRendered( + const std::vector& visible_forms) { + if(!IsPasswordManagerEnabled()) { + return; + } + + if (!provisional_save_manager_.get()) { + return; + } + // If we see the login form again, then the login failed. + for (size_t i = 0; i < visible_forms.size(); ++i) { + // TODO(vabr): The similarity check is just action equality for now. If it + // becomes more complex, it may make sense to consider modifying and using + // PasswordFormManager::DoesManage for it. + if (visible_forms[i].action.is_valid() && + provisional_save_manager_->pending_credentials().action == + visible_forms[i].action) { + provisional_save_manager_->SubmitFailed(); + provisional_save_manager_.reset(); + return; + } + } + + // Looks like a successful login attempt. Either show an infobar or + // automatically save the login data. We prompt when the user hasn't already + // given consent, either through previously accepting the infobar or by having + // the browser generate the password. + provisional_save_manager_->SubmitPassed(); + if (provisional_save_manager_->HasGeneratedPassword()) + UMA_HISTOGRAM_COUNTS("PasswordGeneration.Submitted", 1); + + if (ShouldPromptUserToSavePassword()) { + client_->PromptUserToSavePassword(provisional_save_manager_.release()); + } else { + provisional_save_manager_->Save(); + provisional_save_manager_.reset(); + } +} + +void PasswordManager::PossiblyInitializeUsernamesExperiment( + const PasswordFormMap& best_matches) const { + if (base::FieldTrialList::Find(kOtherPossibleUsernamesExperiment)) + return; + + bool other_possible_usernames_exist = false; + for (autofill::PasswordFormMap::const_iterator it = best_matches.begin(); + it != best_matches.end(); ++it) { + if (!it->second->other_possible_usernames.empty()) { + other_possible_usernames_exist = true; + break; + } + } + + if (!other_possible_usernames_exist) + return; + + const base::FieldTrial::Probability kDivisor = 100; + scoped_refptr trial( + base::FieldTrialList::FactoryGetFieldTrial( + kOtherPossibleUsernamesExperiment, + kDivisor, + "Disabled", + 2013, 12, 31, + base::FieldTrial::ONE_TIME_RANDOMIZED, + NULL)); + base::FieldTrial::Probability enabled_probability = + client_->GetProbabilityForExperiment(kOtherPossibleUsernamesExperiment); + trial->AppendGroup("Enabled", enabled_probability); +} + +bool PasswordManager::OtherPossibleUsernamesEnabled() const { + return base::FieldTrialList::FindFullName( + kOtherPossibleUsernamesExperiment) == "Enabled"; +} + +void PasswordManager::Autofill( + const PasswordForm& form_for_autofill, + const PasswordFormMap& best_matches, + const PasswordForm& preferred_match, + bool wait_for_username) const { + PossiblyInitializeUsernamesExperiment(best_matches); + + // TODO(tedchoc): Switch to only requesting authentication if the user is + // acting on the autofilled forms (crbug.com/342594) instead + // of on page load. + bool authentication_required = preferred_match.use_additional_authentication; + for (autofill::PasswordFormMap::const_iterator it = best_matches.begin(); + !authentication_required && it != best_matches.end(); ++it) { + if (it->second->use_additional_authentication) + authentication_required = true; + } + + switch (form_for_autofill.scheme) { + case PasswordForm::SCHEME_HTML: { + // Note the check above is required because the observers_ for a non-HTML + // schemed password form may have been freed, so we need to distinguish. + scoped_ptr fill_data( + new autofill::PasswordFormFillData()); + InitPasswordFormFillData(form_for_autofill, + best_matches, + &preferred_match, + wait_for_username, + OtherPossibleUsernamesEnabled(), + fill_data.get()); + if (authentication_required) + client_->AuthenticateAutofillAndFillForm(fill_data.Pass()); + else + driver_->FillPasswordForm(*fill_data.get()); + break; + } + default: + FOR_EACH_OBSERVER( + LoginModelObserver, + observers_, + OnAutofillDataAvailable(preferred_match.username_value, + preferred_match.password_value)); + break; + } + + client_->PasswordWasAutofilled(best_matches); +} + +#endif // TIZEN_AUTOFILL_SUPPORT + diff --git a/tizen_src/impl/browser/password_manager/password_manager.h b/tizen_src/impl/browser/password_manager/password_manager.h new file mode 100644 index 000000000000..d6889453a69d --- /dev/null +++ b/tizen_src/impl/browser/password_manager/password_manager.h @@ -0,0 +1,182 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PASSWORD_MANAGER_H +#define PASSWORD_MANAGER_H + +#ifdef TIZEN_AUTOFILL_SUPPORT + +#include + +#include "base/callback.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/scoped_vector.h" +#include "base/observer_list.h" +#include "base/prefs/pref_member.h" +#include "base/stl_util.h" +#include "browser/password_manager/password_form_manager.h" +#include "components/autofill/core/common/password_form.h" +#include "components/autofill/core/common/password_form_fill_data.h" +#include "components/password_manager/core/browser/login_model.h" + +class PasswordManagerClient; +class PasswordManagerDriver; +class PasswordManagerTest; +class PasswordFormManager; +class PrefRegistrySimple; + +namespace content { +class WebContents; +} + +namespace user_prefs { +class PrefRegistrySyncable; +} + +// Per-tab password manager. Handles creation and management of UI elements, +// receiving password form data from the renderer and managing the password +// database through the PasswordStore. The PasswordManager is a LoginModel +// for purposes of supporting HTTP authentication dialogs. +class PasswordManager : public LoginModel { + public: + static const char kOtherPossibleUsernamesExperiment[]; + + static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry); + + explicit PasswordManager(PasswordManagerClient* client); + virtual ~PasswordManager(); + + typedef base::Callback + PasswordSubmittedCallback; + + // There is no corresponding remove function as currently all of the + // owners of these callbacks have sufficient lifetimes so that the callbacks + // should always be valid when called. + void AddSubmissionCallback(const PasswordSubmittedCallback& callback); + + // Is password manager enabled for autofill password + bool IsPasswordManagerEnabled() const; + + // Set password manager enabled for autofill password + void SetPasswordManagerEnabled(bool enabled); + + // Called by a PasswordFormManager when it decides a form can be autofilled + // on the page. + virtual void Autofill(const autofill::PasswordForm& form_for_autofill, + const autofill::PasswordFormMap& best_matches, + const autofill::PasswordForm& preferred_match, + bool wait_for_username) const; + + // LoginModel implementation. + virtual void AddObserver(LoginModelObserver* observer) OVERRIDE; + virtual void RemoveObserver(LoginModelObserver* observer) OVERRIDE; + + // Mark this form as having a generated password. + void SetFormHasGeneratedPassword(const autofill::PasswordForm& form); + + // TODO(isherman): This should not be public, but is currently being used by + // the LoginPrompt code. + // When a form is submitted, we prepare to save the password but wait + // until we decide the user has successfully logged in. This is step 1 + // of 2 (see SavePassword). + void ProvisionallySavePassword(const autofill::PasswordForm& form); + + // Should be called when the user navigates the main frame. + void DidNavigateMainFrame(bool is_in_page); + + // Handles password forms being parsed. + void OnPasswordFormsParsed( + const std::vector& forms); + + // Handles password forms being rendered. + void OnPasswordFormsRendered( + const std::vector& visible_forms); + + // Handles a password form being submitted. + virtual void OnPasswordFormSubmitted( + const autofill::PasswordForm& password_form); + + private: + enum ProvisionalSaveFailure { + SAVING_DISABLED, + EMPTY_PASSWORD, + NO_MATCHING_FORM, + MATCHING_NOT_COMPLETE, + FORM_BLACKLISTED, + INVALID_FORM, + AUTOCOMPLETE_OFF, + MAX_FAILURE_VALUE + }; + + // Log failure for UMA. Logs additional metrics if the |form_origin| + // corresponds to one of the top, explicitly monitored websites. + void RecordFailure(ProvisionalSaveFailure failure, + const std::string& form_origin); + + // Possibly set up FieldTrial for testing other possible usernames. This only + // happens if there are other_possible_usernames to be shown and the + // experiment hasn't already been initialized. We setup the experiment at + // such a late time because this experiment will only affect a small number + // of users so we want to include a larger fraction of these users than the + // normal 10%. + void PossiblyInitializeUsernamesExperiment( + const autofill::PasswordFormMap& matches) const; + + // Returns true if we can show possible usernames to users in cases where + // the username for the form is ambigious. + bool OtherPossibleUsernamesEnabled() const; + + // Returns true if the user needs to be prompted before a password can be + // saved (instead of automatically saving + // the password), based on inspecting the state of + // |provisional_save_manager_|. + bool ShouldPromptUserToSavePassword() const; + + // Note about how a PasswordFormManager can transition from + // pending_login_managers_ to provisional_save_manager_ and the infobar. + // + // 1. form "seen" + // | new + // | ___ Infobar + // pending_login -- form submit --> provisional_save ___/ + // ^ | \___ (update DB) + // | fail + // |-----------<------<---------| !new + // + // When a form is "seen" on a page, a PasswordFormManager is created + // and stored in this collection until user navigates away from page. + + ScopedVector pending_login_managers_; + + // When the user submits a password/credential, this contains the + // PasswordFormManager for the form in question until we deem the login + // attempt to have succeeded (as in valid credentials). If it fails, we + // send the PasswordFormManager back to the pending_login_managers_ set. + // Scoped in case PasswordManager gets deleted (e.g tab closes) between the + // time a user submits a login form and gets to the next page. + scoped_ptr provisional_save_manager_; + + // The embedder-level client. Must outlive this class. + PasswordManagerClient* const client_; + + // The platform-level driver. Must outlive this class. + PasswordManagerDriver* const driver_; + + // Set to false to disable the password manager (will no longer ask if you + // want to save passwords but will continue to fill passwords). + bool password_manager_enabled_; + + // Observers to be notified of LoginModel events. This is mutable to allow + // notification in const member functions. + mutable ObserverList observers_; + + // Callbacks to be notified when a password form has been submitted. + std::vector submission_callbacks_; + + DISALLOW_COPY_AND_ASSIGN(PasswordManager); +}; + +#endif // TIZEN_AUTOFILL_SUPPORT + +#endif // PASSWORD_MANAGER_H diff --git a/tizen_src/impl/browser/password_manager/password_manager_client.cc b/tizen_src/impl/browser/password_manager/password_manager_client.cc new file mode 100644 index 000000000000..84d9ec6dfb96 --- /dev/null +++ b/tizen_src/impl/browser/password_manager/password_manager_client.cc @@ -0,0 +1,17 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifdef TIZEN_AUTOFILL_SUPPORT + +#include "browser/password_manager/password_manager_client.h" + +base::FieldTrial::Probability +PasswordManagerClient::GetProbabilityForExperiment( + const std::string& experiment_name) { + return 0; +} + +bool PasswordManagerClient::IsPasswordSyncEnabled() { return false; } + +#endif // TIZEN_AUTOFILL_SUPPORT \ No newline at end of file diff --git a/tizen_src/impl/browser/password_manager/password_manager_client.h b/tizen_src/impl/browser/password_manager/password_manager_client.h new file mode 100644 index 000000000000..aa536e809cbf --- /dev/null +++ b/tizen_src/impl/browser/password_manager/password_manager_client.h @@ -0,0 +1,61 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PASSWORD_MANAGER_CLIENT_H +#define PASSWORD_MANAGER_CLIENT_H + +#ifdef TIZEN_AUTOFILL_SUPPORT + +#include "base/metrics/field_trial.h" +#include "components/autofill/core/common/password_form.h" +#include "components/autofill/core/common/password_form_fill_data.h" + +class PasswordFormManager; +class PasswordManagerDriver; +class PasswordStore; +class PrefService; + +// An abstraction of operations that depend on the embedders (e.g. Chrome) +// environment. +class PasswordManagerClient { + public: + PasswordManagerClient() {} + virtual ~PasswordManagerClient() {} + + // Informs the embedder of a password form that can be saved if the user + // allows it. The embedder is not required to prompt the user if it decides + // that this form doesn't need to be saved. + virtual void PromptUserToSavePassword(PasswordFormManager* form_to_save) = 0; + + // Called when a password is autofilled. Default implementation is a no-op. + virtual void PasswordWasAutofilled( + const autofill::PasswordFormMap& best_matches) const {} + + // Called to authenticate the autofill password data. If authentication is + // successful, this should continue filling the form. + virtual void AuthenticateAutofillAndFillForm( + scoped_ptr fill_data) = 0; + + // Returns the PasswordStore associated with this instance. + virtual PasswordStore* GetPasswordStore() = 0; + + // Returns the PasswordManagerDriver instance associated with this instance. + virtual PasswordManagerDriver* GetDriver() = 0; + + // Returns the probability that the experiment identified by |experiment_name| + // should be enabled. The default implementation returns 0. + virtual base::FieldTrial::Probability GetProbabilityForExperiment( + const std::string& experiment_name); + + // Returns true if password sync is enabled in the embedder. The default + // implementation returns false. + virtual bool IsPasswordSyncEnabled(); + + private: + DISALLOW_COPY_AND_ASSIGN(PasswordManagerClient); +}; + +#endif // TIZEN_AUTOFILL_SUPPORT + +#endif // PASSWORD_MANAGER_CLIENT_H diff --git a/tizen_src/impl/browser/password_manager/password_manager_driver.h b/tizen_src/impl/browser/password_manager/password_manager_driver.h new file mode 100644 index 000000000000..734deb507e81 --- /dev/null +++ b/tizen_src/impl/browser/password_manager/password_manager_driver.h @@ -0,0 +1,55 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PASSWORD_MANAGER_DRIVER_H +#define PASSWORD_MANAGER_DRIVER_H + +#ifdef TIZEN_AUTOFILL_SUPPORT + +class PasswordGenerationManager; +class PasswordManager; + +namespace autofill { +class AutofillManager; +struct PasswordForm; +struct PasswordFormFillData; +} // namespace autofill + +// Interface that allows PasswordManager core code to interact with its driver +// (i.e., obtain information from it and give information to it). +class PasswordManagerDriver { + public: + PasswordManagerDriver() {} + virtual ~PasswordManagerDriver() {} + + // Fills forms matching |form_data|. + virtual void FillPasswordForm( + const autofill::PasswordFormFillData& form_data) = 0; + + // Returns whether any SSL certificate errors were encountered as a result of + // the last page load. + virtual bool DidLastPageLoadEncounterSSLErrors() = 0; + + // If this browsing session should not be persisted. + virtual bool IsOffTheRecord() = 0; + + // Returns the PasswordGenerationManager associated with this instance. + virtual PasswordGenerationManager* GetPasswordGenerationManager() = 0; + + // Returns the PasswordManager associated with this instance. + virtual PasswordManager* GetPasswordManager() = 0; + + // Returns the AutofillManager associated with this instance. + virtual autofill::AutofillManager* GetAutofillManager() = 0; + + // Informs the driver that |form| can be used for password generation. + virtual void AllowPasswordGenerationForForm(autofill::PasswordForm* form) = 0; + + private: + DISALLOW_COPY_AND_ASSIGN(PasswordManagerDriver); +}; + +#endif // TIZEN_AUTOFILL_SUPPORT + +#endif // PASSWORD_MANAGER_DRIVER_H diff --git a/tizen_src/impl/browser/password_manager/password_manager_util.h b/tizen_src/impl/browser/password_manager/password_manager_util.h new file mode 100644 index 000000000000..f60da36c887c --- /dev/null +++ b/tizen_src/impl/browser/password_manager/password_manager_util.h @@ -0,0 +1,42 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PASSWORD_MANAGER_UTIL_H +#define PASSWORD_MANAGER_UTIL_H + +#ifdef TIZEN_AUTOFILL_SUPPORT + +#include "base/basictypes.h" +#include "ui/gfx/native_widget_types.h" + +namespace password_manager_util { + +enum OsPasswordStatus { + PASSWORD_STATUS_UNKNOWN = 0, + PASSWORD_STATUS_UNSUPPORTED, + PASSWORD_STATUS_BLANK, + PASSWORD_STATUS_NONBLANK, + PASSWORD_STATUS_WIN_DOMAIN, + // NOTE: Add new status types only immediately above this line. Also, + // make sure the enum list in tools/histogram/histograms.xml is + // updated with any change in here. + MAX_PASSWORD_STATUS +}; + +// Attempts to (re-)authenticate the user of the OS account. Returns true if +// the user was successfully authenticated, or if authentication was not +// possible. On platforms where reauthentication is not possible or does not +// make sense, the default implementation always returns true. +bool AuthenticateUser(gfx::NativeWindow window); + +// Query the system to determine whether the current logged on user has a +// password set on their OS account. Returns one of the OsPasswordStatus +// enum values. +OsPasswordStatus GetOsPasswordStatus(); + +} // namespace password_manager_util + +#endif // TIZEN_AUTOFILL_SUPPORT + +#endif // PASSWORD_MANAGER_UTIL_H diff --git a/tizen_src/impl/browser/password_manager/password_store_factory.cc b/tizen_src/impl/browser/password_manager/password_store_factory.cc new file mode 100644 index 000000000000..82e70e496423 --- /dev/null +++ b/tizen_src/impl/browser/password_manager/password_store_factory.cc @@ -0,0 +1,116 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifdef TIZEN_AUTOFILL_SUPPORT + +#include "browser/password_manager/password_store_factory.h" + +#include "base/command_line.h" +#include "base/environment.h" +#include "base/prefs/pref_service.h" +#include "base/path_service.h" +#include "base/files/file_path.h" +#include "paths_efl.h" +#include "browser/webdata/web_data_service.h" +#include "browser/webdata/web_data_service_factory.h" +#include "components/browser_context_keyed_service/browser_context_dependency_manager.h" +#include "components/password_manager/core/browser/login_database.h" +#include "components/password_manager/core/browser/password_store.h" +#include "components/password_manager/core/browser/password_store_default.h" +#include "components/user_prefs/pref_registry_syncable.h" +#include "content/public/browser/browser_thread.h" + +PasswordStoreService::PasswordStoreService( + scoped_refptr password_store) + : password_store_(password_store) +{ +} + +PasswordStoreService::~PasswordStoreService() +{ +} + +scoped_refptr PasswordStoreService::GetPasswordStore() +{ + return password_store_; +} + +void PasswordStoreService::Shutdown() +{ + if (password_store_) + password_store_->Shutdown(); +} + +// static +scoped_refptr PasswordStoreFactory::GetPasswordStore() +{ + PasswordStoreService* service = GetInstance()->GetService(); + if (!service) + return NULL; + return service->GetPasswordStore(); +} + +// static +PasswordStoreFactory* PasswordStoreFactory::GetInstance() +{ + return Singleton::get(); +} + +PasswordStoreFactory::PasswordStoreFactory() +{ + WebDataServiceFactory::GetInstance(); + Init(); +} + +PasswordStoreFactory::~PasswordStoreFactory() +{ +} + +void PasswordStoreFactory::Init() +{ + base::FilePath db_path; + PathService::Get(PathsEfl::WEB_DATABSE_DIR, &db_path); + +#ifndef OS_TIZEN + if(PathService::Override(base::DIR_MODULE, db_path) == false) { + LOG(ERROR)<<"Could not access login database path."; + return; + } +#endif + + base::FilePath login_db_file_path = db_path.Append(FILE_PATH_LITERAL("LoginData.db")); + LOG(ERROR) < login_db(new LoginDatabase()); + { + base::ThreadRestrictions::ScopedAllowIO allow_io; + if (!login_db->Init(login_db_file_path)) { + LOG(ERROR) << "Could not initialize login database."; + return; + } + } + + scoped_refptr main_thread_runner( + base::MessageLoopProxy::current()); + scoped_refptr db_thread_runner( + content::BrowserThread::GetMessageLoopProxyForThread( + content::BrowserThread::DB)); + + scoped_refptr ps; + + ps = new PasswordStoreDefault( + main_thread_runner, db_thread_runner, login_db.release()); + + if (!ps || !ps->Init()) { + NOTREACHED() << "Could not initialize password manager."; + return; + } + + service_ = new PasswordStoreService(ps); +} + +bool PasswordStoreFactory::ServiceIsNULLWhileTesting() const +{ + return true; +} +#endif // TIZEN_AUTOFILL_SUPPORT diff --git a/tizen_src/impl/browser/password_manager/password_store_factory.h b/tizen_src/impl/browser/password_manager/password_store_factory.h new file mode 100644 index 000000000000..222f944f7ed0 --- /dev/null +++ b/tizen_src/impl/browser/password_manager/password_store_factory.h @@ -0,0 +1,55 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef PASSWORD_STORE_FACTORY_H +#define PASSWORD_STORE_FACTORY_H + +#ifdef TIZEN_AUTOFILL_SUPPORT + +#include "base/basictypes.h" +#include "base/memory/singleton.h" + +class PasswordStore; + +// A wrapper of PasswordStore so we can use it as a profiled keyed service. +class PasswordStoreService { + public: + // |password_store| needs to be not-NULL, and the constructor expects that + // Init() was already called successfully on it. + explicit PasswordStoreService(scoped_refptr password_store); + virtual ~PasswordStoreService(); + + scoped_refptr GetPasswordStore(); + + virtual void Shutdown() OVERRIDE; + + private: + scoped_refptr password_store_; + DISALLOW_COPY_AND_ASSIGN(PasswordStoreService); +}; + +// Singleton that owns all PasswordStores and associates them with +// Profiles. +class PasswordStoreFactory { + public: + static scoped_refptr GetPasswordStore(); + + static PasswordStoreFactory* GetInstance(); + PasswordStoreService* GetService() { return service_; } + + private: + friend struct DefaultSingletonTraits; + void Init(); + PasswordStoreFactory(); + virtual ~PasswordStoreFactory(); + + virtual bool ServiceIsNULLWhileTesting() const OVERRIDE; + PasswordStoreService * service_; + + DISALLOW_COPY_AND_ASSIGN(PasswordStoreFactory); +}; + +#endif // TIZEN_AUTOFILL_SUPPORT + +#endif // PASSWORD_STORE_FACTORY_H diff --git a/tizen_src/impl/browser/webdata/web_data_service.cc b/tizen_src/impl/browser/webdata/web_data_service.cc new file mode 100644 index 000000000000..57133b04442b --- /dev/null +++ b/tizen_src/impl/browser/webdata/web_data_service.cc @@ -0,0 +1,36 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifdef TIZEN_AUTOFILL_SUPPORT + +#include "browser/webdata/web_data_service.h" + +#include "base/bind.h" +#include "base/stl_util.h" +#include "components/webdata/common/web_database_service.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_source.h" + +using base::Bind; +using base::Time; +using content::BrowserThread; + + +WebDataService::WebDataService(scoped_refptr wdbs, + const ProfileErrorCallback& callback) + : WebDataServiceBase(wdbs, callback, + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI)) { +} + +WebDataService::WebDataService() + : WebDataServiceBase(NULL, ProfileErrorCallback(), + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI)) { +} + +WebDataService::~WebDataService() { +} + +#endif // TIZEN_AUTOFILL_SUPPORT diff --git a/tizen_src/impl/browser/webdata/web_data_service.h b/tizen_src/impl/browser/webdata/web_data_service.h new file mode 100644 index 000000000000..dc544f2c329b --- /dev/null +++ b/tizen_src/impl/browser/webdata/web_data_service.h @@ -0,0 +1,68 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + + +#ifndef WEB_DATA_SERVICE_H +#define WEB_DATA_SERVICE_H + +#ifdef TIZEN_AUTOFILL_SUPPORT + +#include +#include +#include + +#include "base/callback_forward.h" +#include "base/files/file_path.h" +#include "base/location.h" +#include "base/memory/ref_counted.h" +#include "base/sequenced_task_runner_helpers.h" +#include "components/webdata/common/web_data_results.h" +#include "components/webdata/common/web_data_service_base.h" +#include "components/webdata/common/web_data_service_consumer.h" +#include "components/webdata/common/web_database.h" + +class GURL; +class WebDatabaseService; + +namespace base { +class Thread; +} + +namespace content { +class BrowserContext; +} + +//////////////////////////////////////////////////////////////////////////////// +// +// WebDataService is a generic data repository for meta data associated with +// web pages. All data is retrieved and archived in an asynchronous way. +// +// All requests return a handle. The handle can be used to cancel the request. +// +//////////////////////////////////////////////////////////////////////////////// + +typedef base::Callback(void)> ResultTask; + +class WebDataServiceConsumer; + +class WebDataService : public WebDataServiceBase { + public: + // Retrieve a WebDataService for the given context. + static scoped_refptr FromBrowserContext( + content::BrowserContext* context); + + WebDataService(scoped_refptr wdbs, + const ProfileErrorCallback& callback); + + protected: + WebDataService(); + virtual ~WebDataService(); + + private: + DISALLOW_COPY_AND_ASSIGN(WebDataService); +}; + +#endif // TIZEN_AUTOFILL_SUPPORT + +#endif // WEB_DATA_SERVICE_H diff --git a/tizen_src/impl/browser/webdata/web_data_service_factory.cc b/tizen_src/impl/browser/webdata/web_data_service_factory.cc new file mode 100644 index 000000000000..dc91677107fc --- /dev/null +++ b/tizen_src/impl/browser/webdata/web_data_service_factory.cc @@ -0,0 +1,143 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifdef TIZEN_AUTOFILL_SUPPORT + +#include "browser/webdata/web_data_service_factory.h" + +#include "eweb_view.h" +#include "base/bind.h" +#include "base/path_service.h" +#include "base/files/file_path.h" +#include "paths_efl.h" +#include "browser/webdata/web_data_service.h" +#include "components/autofill/core/browser/autofill_country.h" +#include "components/autofill/core/browser/webdata/autofill_table.h" +#include "components/autofill/core/browser/webdata/autofill_webdata_service.h" +#include "components/webdata/common/webdata_constants.h" +#include "content/public/browser/browser_thread.h" + +using autofill::AutofillWebDataService; +using content::BrowserThread; + +namespace { + +// Callback to show error dialog on profile load error. +void ProfileErrorCallback(int type, sql::InitStatus status) { + //TODO:Need to check what type of error to show +} + +void InitSyncableServicesOnDBThread( + scoped_refptr autofill_web_data, + const base::FilePath& profile_path, + const std::string& app_locale, + autofill::AutofillWebDataBackend* autofill_backend) { + //TODO:Need to check if syncable service is needed +} + +} // namespace + +WebDataServiceWrapper* WebDataServiceWrapper::GetInstance(){ + return Singleton::get(); +} + +WebDataServiceWrapper::WebDataServiceWrapper() { + base::FilePath db_path; + PathService::Get(PathsEfl::WEB_DATABSE_DIR, &db_path); +#ifndef OS_TIZEN + if(PathService::Override(base::DIR_MODULE, db_path) == false) { + LOG(ERROR)<<"Could not access web database path."; + return; + } +#endif + base::FilePath path = db_path.Append(FILE_PATH_LITERAL("FormData.db")); + + scoped_refptr ui_thread = + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI); + scoped_refptr db_thread = + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB); + web_database_ = new WebDatabaseService(path, ui_thread, db_thread); + + // All tables objects that participate in managing the database must + // be added here. + web_database_->AddTable( + scoped_ptr(new autofill::AutofillTable( + EWebView::GetPlatformLocale()))); + + web_database_->LoadDatabase(); + + autofill_web_data_ = new AutofillWebDataService( + web_database_, ui_thread, db_thread, base::Bind( + &ProfileErrorCallback, 0)); + autofill_web_data_->Init(); + + web_data_ = new WebDataService( + web_database_, base::Bind(&ProfileErrorCallback,0)); + web_data_->Init(); + + autofill_web_data_->GetAutofillBackend( + base::Bind(&InitSyncableServicesOnDBThread, + autofill_web_data_, + db_path, + EWebView::GetPlatformLocale())); +} + +WebDataServiceWrapper::~WebDataServiceWrapper() { +} + +void WebDataServiceWrapper::Shutdown() { + autofill_web_data_->ShutdownOnUIThread(); + web_data_->ShutdownOnUIThread(); + web_database_->ShutdownDatabase(); +} + +scoped_refptr +WebDataServiceWrapper::GetAutofillWebData() { + return autofill_web_data_.get(); +} + +scoped_refptr WebDataServiceWrapper::GetWebData() { + return web_data_.get(); +} + + +// static +scoped_refptr WebDataService::FromBrowserContext( + content::BrowserContext* context) { + WebDataServiceWrapper* wrapper = WebDataServiceFactory::GetDataService(); + if (wrapper) + return wrapper->GetWebData(); + // |wrapper| can be NULL in Incognito mode. + return scoped_refptr(NULL); +} + +WebDataServiceFactory::WebDataServiceFactory(){ + // WebDataServiceFactory has no dependecies. +} + +WebDataServiceFactory::~WebDataServiceFactory() {} + +// static + +WebDataServiceWrapper* WebDataServiceFactory::GetDataService() { + return WebDataServiceWrapper::GetInstance(); +} + +// static +scoped_refptr +WebDataServiceFactory::GetAutofillWebDataForProfile() { + WebDataServiceWrapper* wrapper = + WebDataServiceFactory::GetDataService(); + // |wrapper| can be NULL in Incognito mode. + return wrapper ? + wrapper->GetAutofillWebData() : + scoped_refptr(NULL); +} + +// static +WebDataServiceFactory* WebDataServiceFactory::GetInstance() { + return Singleton::get(); +} + +#endif // TIZEN_AUTOFILL_SUPPORT diff --git a/tizen_src/impl/browser/webdata/web_data_service_factory.h b/tizen_src/impl/browser/webdata/web_data_service_factory.h new file mode 100644 index 000000000000..37ac213d7b90 --- /dev/null +++ b/tizen_src/impl/browser/webdata/web_data_service_factory.h @@ -0,0 +1,66 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef WEB_DATA_SERVICE_FACTORY_H +#define WEB_DATA_SERVICE_FACTORY_H + +#ifdef TIZEN_AUTOFILL_SUPPORT + +#include "base/basictypes.h" +#include "base/memory/ref_counted.h" +#include "base/memory/singleton.h" +#include "components/webdata/common/web_database_service.h" + +class WebDataService; + +namespace autofill { +class AutofillWebDataService; +} // namespace autofill + +class WebDataServiceWrapper{ + public: + explicit WebDataServiceWrapper(); + + virtual ~WebDataServiceWrapper(); + + virtual void Shutdown() OVERRIDE; + + virtual scoped_refptr GetAutofillWebData(); + + virtual scoped_refptr GetWebData(); + + static WebDataServiceWrapper* GetInstance(); + private: + scoped_refptr web_database_; + + scoped_refptr autofill_web_data_; + scoped_refptr web_data_; + + DISALLOW_COPY_AND_ASSIGN(WebDataServiceWrapper); +}; + +// Singleton that owns all WebDataServiceWrappers +class WebDataServiceFactory { + public: + + static WebDataServiceWrapper* GetDataService(); + + static scoped_refptr + GetAutofillWebDataForProfile(); + + static WebDataServiceFactory* GetInstance(); + + private: + friend struct DefaultSingletonTraits; + + WebDataServiceFactory(); + virtual ~WebDataServiceFactory(); + + DISALLOW_COPY_AND_ASSIGN(WebDataServiceFactory); +}; + +#endif // TIZEN_AUTOFILL_SUPPORT + +#endif // WEB_DATA_SERVICE_FACTORY_H + -- 2.34.1