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.
5 #include "chrome/browser/password_manager/password_manager_delegate_impl.h"
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_service.h"
13 #include "chrome/browser/password_manager/password_form_manager.h"
14 #include "chrome/browser/password_manager/password_manager.h"
15 #include "chrome/browser/password_manager/password_manager_metrics_util.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/browser/ui/sync/one_click_signin_helper.h"
18 #include "components/autofill/content/browser/autofill_driver_impl.h"
19 #include "components/autofill/core/browser/autofill_manager.h"
20 #include "components/autofill/core/common/autofill_messages.h"
21 #include "components/autofill/core/common/password_form.h"
22 #include "content/public/browser/navigation_entry.h"
23 #include "content/public/browser/render_view_host.h"
24 #include "content/public/browser/web_contents.h"
25 #include "content/public/common/ssl_status.h"
26 #include "google_apis/gaia/gaia_urls.h"
27 #include "grit/chromium_strings.h"
28 #include "grit/generated_resources.h"
29 #include "grit/theme_resources.h"
30 #include "net/cert/cert_status_flags.h"
31 #include "ui/base/l10n/l10n_util.h"
34 // SavePasswordInfoBarDelegate ------------------------------------------------
36 // After a successful *new* login attempt, we take the PasswordFormManager in
37 // provisional_save_manager_ and move it to a SavePasswordInfoBarDelegate while
38 // the user makes up their mind with the "save password" infobar. Note if the
39 // login is one we already know about, the end of the line is
40 // provisional_save_manager_ because we just update it on success and so such
41 // forms never end up in an infobar.
42 class SavePasswordInfoBarDelegate : public ConfirmInfoBarDelegate {
44 // If we won't be showing the one-click signin infobar, creates a save
45 // password infobar delegate and adds it to the InfoBarService for
46 // |web_contents|. |uma_histogram_suffix| is empty, or one of the "group_X"
47 // suffixes used in the histogram names for infobar usage reporting; if empty,
48 // the usage is not reported, otherwise the suffix is used to choose the right
50 static void Create(content::WebContents* web_contents,
51 PasswordFormManager* form_to_save,
52 const std::string& uma_histogram_suffix);
58 NEVER_REMEMBER_PASSWORD,
63 SavePasswordInfoBarDelegate(InfoBarService* infobar_service,
64 PasswordFormManager* form_to_save,
65 const std::string& uma_histogram_suffix);
66 virtual ~SavePasswordInfoBarDelegate();
68 // ConfirmInfoBarDelegate
69 virtual int GetIconID() const OVERRIDE;
70 virtual Type GetInfoBarType() const OVERRIDE;
71 virtual string16 GetMessageText() const OVERRIDE;
72 virtual string16 GetButtonLabel(InfoBarButton button) const OVERRIDE;
73 virtual bool Accept() OVERRIDE;
74 virtual bool Cancel() OVERRIDE;
75 virtual void InfoBarDismissed() OVERRIDE;
77 virtual InfoBarAutomationType GetInfoBarAutomationType() const OVERRIDE;
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_;
83 // Used to track the results we get from the info bar.
84 ResponseType infobar_response_;
86 // Measures the "Save password?" prompt lifetime. Used to report an UMA
88 base::ElapsedTimer timer_;
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_;
94 DISALLOW_COPY_AND_ASSIGN(SavePasswordInfoBarDelegate);
98 void 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))
116 InfoBarService* infobar_service =
117 InfoBarService::FromWebContents(web_contents);
118 infobar_service->AddInfoBar(
119 scoped_ptr<InfoBarDelegate>(new SavePasswordInfoBarDelegate(
120 infobar_service, form_to_save, uma_histogram_suffix)));
123 SavePasswordInfoBarDelegate::SavePasswordInfoBarDelegate(
124 InfoBarService* infobar_service,
125 PasswordFormManager* form_to_save,
126 const std::string& uma_histogram_suffix)
127 : ConfirmInfoBarDelegate(infobar_service),
128 form_to_save_(form_to_save),
129 infobar_response_(NO_RESPONSE),
130 uma_histogram_suffix_(uma_histogram_suffix) {
131 if (!uma_histogram_suffix_.empty()) {
132 password_manager_metrics_util::LogUMAHistogramBoolean(
133 "PasswordManager.SavePasswordPromptDisplayed_" + uma_histogram_suffix_,
138 SavePasswordInfoBarDelegate::~SavePasswordInfoBarDelegate() {
139 UMA_HISTOGRAM_ENUMERATION("PasswordManager.InfoBarResponse",
140 infobar_response_, NUM_RESPONSE_TYPES);
142 // The shortest period for which the prompt needs to live, so that we don't
143 // consider it killed prematurely, as might happen, e.g., if a pre-rendered
144 // page gets swapped in (and the current WebContents is destroyed).
145 const base::TimeDelta kMinimumPromptDisplayTime =
146 base::TimeDelta::FromSeconds(1);
148 if (!uma_histogram_suffix_.empty()) {
149 password_manager_metrics_util::LogUMAHistogramEnumeration(
150 "PasswordManager.SavePasswordPromptResponse_" + uma_histogram_suffix_,
151 infobar_response_, NUM_RESPONSE_TYPES);
152 password_manager_metrics_util::LogUMAHistogramBoolean(
153 "PasswordManager.SavePasswordPromptDisappearedQuickly_" +
154 uma_histogram_suffix_,
155 timer_.Elapsed() < kMinimumPromptDisplayTime);
159 int SavePasswordInfoBarDelegate::GetIconID() const {
160 return IDR_INFOBAR_SAVE_PASSWORD;
163 InfoBarDelegate::Type SavePasswordInfoBarDelegate::GetInfoBarType() const {
164 return PAGE_ACTION_TYPE;
167 string16 SavePasswordInfoBarDelegate::GetMessageText() const {
168 return l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SAVE_PASSWORD_PROMPT);
171 string16 SavePasswordInfoBarDelegate::GetButtonLabel(
172 InfoBarButton button) const {
173 return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
174 IDS_PASSWORD_MANAGER_SAVE_BUTTON : IDS_PASSWORD_MANAGER_BLACKLIST_BUTTON);
177 bool SavePasswordInfoBarDelegate::Accept() {
178 DCHECK(form_to_save_.get());
179 form_to_save_->Save();
180 infobar_response_ = REMEMBER_PASSWORD;
184 bool SavePasswordInfoBarDelegate::Cancel() {
185 DCHECK(form_to_save_.get());
186 form_to_save_->PermanentlyBlacklist();
187 infobar_response_ = NEVER_REMEMBER_PASSWORD;
191 void SavePasswordInfoBarDelegate::InfoBarDismissed() {
192 DCHECK(form_to_save_.get());
193 infobar_response_ = INFOBAR_DISMISSED;
196 InfoBarDelegate::InfoBarAutomationType
197 SavePasswordInfoBarDelegate::GetInfoBarAutomationType() const {
198 return PASSWORD_INFOBAR;
202 // PasswordManagerDelegateImpl ------------------------------------------------
204 DEFINE_WEB_CONTENTS_USER_DATA_KEY(PasswordManagerDelegateImpl);
206 PasswordManagerDelegateImpl::PasswordManagerDelegateImpl(
207 content::WebContents* web_contents)
208 : web_contents_(web_contents) {
211 PasswordManagerDelegateImpl::~PasswordManagerDelegateImpl() {
214 void PasswordManagerDelegateImpl::FillPasswordForm(
215 const autofill::PasswordFormFillData& form_data) {
216 web_contents_->GetRenderViewHost()->Send(
217 new AutofillMsg_FillPasswordForm(
218 web_contents_->GetRenderViewHost()->GetRoutingID(),
222 void PasswordManagerDelegateImpl::AddSavePasswordInfoBarIfPermitted(
223 PasswordFormManager* form_to_save) {
224 std::string uma_histogram_suffix(
225 password_manager_metrics_util::GroupIdToString(
226 password_manager_metrics_util::MonitoredDomainGroupId(
227 form_to_save->realm(), GetProfile()->GetPrefs())));
228 SavePasswordInfoBarDelegate::Create(
229 web_contents_, form_to_save, uma_histogram_suffix);
232 Profile* PasswordManagerDelegateImpl::GetProfile() {
233 return Profile::FromBrowserContext(web_contents_->GetBrowserContext());
236 bool PasswordManagerDelegateImpl::DidLastPageLoadEncounterSSLErrors() {
237 content::NavigationEntry* entry =
238 web_contents_->GetController().GetActiveEntry();
244 return net::IsCertStatusError(entry->GetSSL().cert_status);