1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/password_manager/password_manager_delegate_impl.h" 6 7#include "base/memory/singleton.h" 8#include "base/metrics/histogram.h" 9#include "base/strings/utf_string_conversions.h" 10#include "base/timer/elapsed_timer.h" 11#include "chrome/browser/infobars/confirm_infobar_delegate.h" 12#include "chrome/browser/infobars/infobar.h" 13#include "chrome/browser/infobars/infobar_service.h" 14#include "chrome/browser/password_manager/password_form_manager.h" 15#include "chrome/browser/password_manager/password_manager.h" 16#include "chrome/browser/password_manager/password_manager_metrics_util.h" 17#include "chrome/browser/profiles/profile.h" 18#include "chrome/browser/ui/sync/one_click_signin_helper.h" 19#include "components/autofill/content/browser/autofill_driver_impl.h" 20#include "components/autofill/content/common/autofill_messages.h" 21#include "components/autofill/core/browser/autofill_manager.h" 22#include "components/autofill/core/common/password_form.h" 23#include "content/public/browser/navigation_entry.h" 24#include "content/public/browser/render_view_host.h" 25#include "content/public/browser/web_contents.h" 26#include "content/public/common/ssl_status.h" 27#include "google_apis/gaia/gaia_urls.h" 28#include "grit/chromium_strings.h" 29#include "grit/generated_resources.h" 30#include "grit/theme_resources.h" 31#include "net/cert/cert_status_flags.h" 32#include "ui/base/l10n/l10n_util.h" 33 34 35// SavePasswordInfoBarDelegate ------------------------------------------------ 36 37// After a successful *new* login attempt, we take the PasswordFormManager in 38// provisional_save_manager_ and move it to a SavePasswordInfoBarDelegate while 39// the user makes up their mind with the "save password" infobar. Note if the 40// login is one we already know about, the end of the line is 41// provisional_save_manager_ because we just update it on success and so such 42// forms never end up in an infobar. 43class SavePasswordInfoBarDelegate : public ConfirmInfoBarDelegate { 44 public: 45 // If we won't be showing the one-click signin infobar, creates a save 46 // password infobar and delegate and adds the infobar to the InfoBarService 47 // for |web_contents|. |uma_histogram_suffix| is empty, or one of the 48 // "group_X" suffixes used in the histogram names for infobar usage reporting; 49 // if empty, the usage is not reported, otherwise the suffix is used to choose 50 // the right histogram. 51 static void Create(content::WebContents* web_contents, 52 PasswordFormManager* form_to_save, 53 const std::string& uma_histogram_suffix); 54 55 private: 56 enum ResponseType { 57 NO_RESPONSE = 0, 58 REMEMBER_PASSWORD, 59 NEVER_REMEMBER_PASSWORD, 60 INFOBAR_DISMISSED, 61 NUM_RESPONSE_TYPES, 62 }; 63 64 SavePasswordInfoBarDelegate(PasswordFormManager* form_to_save, 65 const std::string& uma_histogram_suffix); 66 virtual ~SavePasswordInfoBarDelegate(); 67 68 // ConfirmInfoBarDelegate 69 virtual int GetIconID() const OVERRIDE; 70 virtual Type GetInfoBarType() const OVERRIDE; 71 virtual base::string16 GetMessageText() const OVERRIDE; 72 virtual base::string16 GetButtonLabel(InfoBarButton button) const OVERRIDE; 73 virtual bool Accept() OVERRIDE; 74 virtual bool Cancel() OVERRIDE; 75 virtual void InfoBarDismissed() OVERRIDE; 76 77 virtual InfoBarAutomationType GetInfoBarAutomationType() const OVERRIDE; 78 79 // The PasswordFormManager managing the form we're asking the user about, 80 // and should update as per her decision. 81 scoped_ptr<PasswordFormManager> form_to_save_; 82 83 // Used to track the results we get from the info bar. 84 ResponseType infobar_response_; 85 86 // Measures the "Save password?" prompt lifetime. Used to report an UMA 87 // signal. 88 base::ElapsedTimer timer_; 89 90 // The group name corresponding to the domain name of |form_to_save_| if the 91 // form is on a monitored domain. Otherwise, an empty string. 92 const std::string uma_histogram_suffix_; 93 94 DISALLOW_COPY_AND_ASSIGN(SavePasswordInfoBarDelegate); 95}; 96 97// static 98void SavePasswordInfoBarDelegate::Create( 99 content::WebContents* web_contents, 100 PasswordFormManager* form_to_save, 101 const std::string& uma_histogram_suffix) { 102#if defined(ENABLE_ONE_CLICK_SIGNIN) 103 // Don't show the password manager infobar if this form is for a google 104 // account and we are going to show the one-click signin infobar. 105 GURL realm(form_to_save->realm()); 106 // TODO(mathp): Checking only against associated_username() causes a bug 107 // referenced here: crbug.com/133275 108 if (((realm == GaiaUrls::GetInstance()->gaia_login_form_realm()) || 109 (realm == GURL("https://www.google.com/"))) && 110 OneClickSigninHelper::CanOffer( 111 web_contents, OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY, 112 UTF16ToUTF8(form_to_save->associated_username()), NULL)) 113 return; 114#endif 115 116 InfoBarService::FromWebContents(web_contents)->AddInfoBar( 117 ConfirmInfoBarDelegate::CreateInfoBar(scoped_ptr<ConfirmInfoBarDelegate>( 118 new SavePasswordInfoBarDelegate(form_to_save, 119 uma_histogram_suffix)))); 120} 121 122SavePasswordInfoBarDelegate::SavePasswordInfoBarDelegate( 123 PasswordFormManager* form_to_save, 124 const std::string& uma_histogram_suffix) 125 : ConfirmInfoBarDelegate(), 126 form_to_save_(form_to_save), 127 infobar_response_(NO_RESPONSE), 128 uma_histogram_suffix_(uma_histogram_suffix) { 129 if (!uma_histogram_suffix_.empty()) { 130 password_manager_metrics_util::LogUMAHistogramBoolean( 131 "PasswordManager.SavePasswordPromptDisplayed_" + uma_histogram_suffix_, 132 true); 133 } 134} 135 136SavePasswordInfoBarDelegate::~SavePasswordInfoBarDelegate() { 137 UMA_HISTOGRAM_ENUMERATION("PasswordManager.InfoBarResponse", 138 infobar_response_, NUM_RESPONSE_TYPES); 139 140 // The shortest period for which the prompt needs to live, so that we don't 141 // consider it killed prematurely, as might happen, e.g., if a pre-rendered 142 // page gets swapped in (and the current WebContents is destroyed). 143 const base::TimeDelta kMinimumPromptDisplayTime = 144 base::TimeDelta::FromSeconds(1); 145 146 if (!uma_histogram_suffix_.empty()) { 147 password_manager_metrics_util::LogUMAHistogramEnumeration( 148 "PasswordManager.SavePasswordPromptResponse_" + uma_histogram_suffix_, 149 infobar_response_, NUM_RESPONSE_TYPES); 150 password_manager_metrics_util::LogUMAHistogramBoolean( 151 "PasswordManager.SavePasswordPromptDisappearedQuickly_" + 152 uma_histogram_suffix_, 153 timer_.Elapsed() < kMinimumPromptDisplayTime); 154 } 155} 156 157int SavePasswordInfoBarDelegate::GetIconID() const { 158 return IDR_INFOBAR_SAVE_PASSWORD; 159} 160 161InfoBarDelegate::Type SavePasswordInfoBarDelegate::GetInfoBarType() const { 162 return PAGE_ACTION_TYPE; 163} 164 165base::string16 SavePasswordInfoBarDelegate::GetMessageText() const { 166 return l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SAVE_PASSWORD_PROMPT); 167} 168 169base::string16 SavePasswordInfoBarDelegate::GetButtonLabel( 170 InfoBarButton button) const { 171 return l10n_util::GetStringUTF16((button == BUTTON_OK) ? 172 IDS_PASSWORD_MANAGER_SAVE_BUTTON : IDS_PASSWORD_MANAGER_BLACKLIST_BUTTON); 173} 174 175bool SavePasswordInfoBarDelegate::Accept() { 176 DCHECK(form_to_save_.get()); 177 form_to_save_->Save(); 178 infobar_response_ = REMEMBER_PASSWORD; 179 return true; 180} 181 182bool SavePasswordInfoBarDelegate::Cancel() { 183 DCHECK(form_to_save_.get()); 184 form_to_save_->PermanentlyBlacklist(); 185 infobar_response_ = NEVER_REMEMBER_PASSWORD; 186 return true; 187} 188 189void SavePasswordInfoBarDelegate::InfoBarDismissed() { 190 DCHECK(form_to_save_.get()); 191 infobar_response_ = INFOBAR_DISMISSED; 192} 193 194InfoBarDelegate::InfoBarAutomationType 195 SavePasswordInfoBarDelegate::GetInfoBarAutomationType() const { 196 return PASSWORD_INFOBAR; 197} 198 199 200// PasswordManagerDelegateImpl ------------------------------------------------ 201 202DEFINE_WEB_CONTENTS_USER_DATA_KEY(PasswordManagerDelegateImpl); 203 204PasswordManagerDelegateImpl::PasswordManagerDelegateImpl( 205 content::WebContents* web_contents) 206 : web_contents_(web_contents) { 207} 208 209PasswordManagerDelegateImpl::~PasswordManagerDelegateImpl() { 210} 211 212void PasswordManagerDelegateImpl::FillPasswordForm( 213 const autofill::PasswordFormFillData& form_data) { 214 web_contents_->GetRenderViewHost()->Send( 215 new AutofillMsg_FillPasswordForm( 216 web_contents_->GetRenderViewHost()->GetRoutingID(), 217 form_data)); 218} 219 220void PasswordManagerDelegateImpl::AddSavePasswordInfoBarIfPermitted( 221 PasswordFormManager* form_to_save) { 222 std::string uma_histogram_suffix( 223 password_manager_metrics_util::GroupIdToString( 224 password_manager_metrics_util::MonitoredDomainGroupId( 225 form_to_save->realm(), GetProfile()->GetPrefs()))); 226 SavePasswordInfoBarDelegate::Create( 227 web_contents_, form_to_save, uma_histogram_suffix); 228} 229 230Profile* PasswordManagerDelegateImpl::GetProfile() { 231 return Profile::FromBrowserContext(web_contents_->GetBrowserContext()); 232} 233 234bool PasswordManagerDelegateImpl::DidLastPageLoadEncounterSSLErrors() { 235 content::NavigationEntry* entry = 236 web_contents_->GetController().GetActiveEntry(); 237 if (!entry) { 238 NOTREACHED(); 239 return false; 240 } 241 242 return net::IsCertStatusError(entry->GetSSL().cert_status); 243} 244