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.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_details.h"
24 #include "content/public/browser/navigation_entry.h"
25 #include "content/public/browser/render_view_host.h"
26 #include "content/public/browser/web_contents.h"
27 #include "content/public/common/page_transition_types.h"
28 #include "content/public/common/ssl_status.h"
29 #include "google_apis/gaia/gaia_urls.h"
30 #include "grit/chromium_strings.h"
31 #include "grit/generated_resources.h"
32 #include "grit/theme_resources.h"
33 #include "net/cert/cert_status_flags.h"
34 #include "ui/base/l10n/l10n_util.h"
37 // SavePasswordInfoBarDelegate ------------------------------------------------
39 // After a successful *new* login attempt, we take the PasswordFormManager in
40 // provisional_save_manager_ and move it to a SavePasswordInfoBarDelegate while
41 // the user makes up their mind with the "save password" infobar. Note if the
42 // login is one we already know about, the end of the line is
43 // provisional_save_manager_ because we just update it on success and so such
44 // forms never end up in an infobar.
45 class SavePasswordInfoBarDelegate
: public ConfirmInfoBarDelegate
{
47 // If we won't be showing the one-click signin infobar, creates a save
48 // password infobar and delegate and adds the infobar to the InfoBarService
49 // for |web_contents|. |uma_histogram_suffix| is empty, or one of the
50 // "group_X" suffixes used in the histogram names for infobar usage reporting;
51 // if empty, the usage is not reported, otherwise the suffix is used to choose
52 // the right histogram.
53 static void Create(content::WebContents
* web_contents
,
54 PasswordFormManager
* form_to_save
,
55 const std::string
& uma_histogram_suffix
);
61 NEVER_REMEMBER_PASSWORD
,
66 SavePasswordInfoBarDelegate(PasswordFormManager
* form_to_save
,
67 const std::string
& uma_histogram_suffix
);
68 virtual ~SavePasswordInfoBarDelegate();
71 virtual bool ShouldExpire(const content::LoadCommittedDetails
& details
)
74 // ConfirmInfoBarDelegate
75 virtual int GetIconID() const OVERRIDE
;
76 virtual Type
GetInfoBarType() const OVERRIDE
;
77 virtual base::string16
GetMessageText() const OVERRIDE
;
78 virtual base::string16
GetButtonLabel(InfoBarButton button
) const OVERRIDE
;
79 virtual bool Accept() OVERRIDE
;
80 virtual bool Cancel() OVERRIDE
;
81 virtual void InfoBarDismissed() OVERRIDE
;
83 virtual InfoBarAutomationType
GetInfoBarAutomationType() const OVERRIDE
;
85 // The PasswordFormManager managing the form we're asking the user about,
86 // and should update as per her decision.
87 scoped_ptr
<PasswordFormManager
> form_to_save_
;
89 // Used to track the results we get from the info bar.
90 ResponseType infobar_response_
;
92 // Measures the "Save password?" prompt lifetime. Used to report an UMA
94 base::ElapsedTimer timer_
;
96 // The group name corresponding to the domain name of |form_to_save_| if the
97 // form is on a monitored domain. Otherwise, an empty string.
98 const std::string uma_histogram_suffix_
;
100 DISALLOW_COPY_AND_ASSIGN(SavePasswordInfoBarDelegate
);
104 void SavePasswordInfoBarDelegate::Create(
105 content::WebContents
* web_contents
,
106 PasswordFormManager
* form_to_save
,
107 const std::string
& uma_histogram_suffix
) {
108 #if defined(ENABLE_ONE_CLICK_SIGNIN)
109 // Don't show the password manager infobar if this form is for a google
110 // account and we are going to show the one-click signin infobar.
111 GURL
realm(form_to_save
->realm());
112 // TODO(mathp): Checking only against associated_username() causes a bug
113 // referenced here: crbug.com/133275
114 if (((realm
== GaiaUrls::GetInstance()->gaia_login_form_realm()) ||
115 (realm
== GURL("https://www.google.com/"))) &&
116 OneClickSigninHelper::CanOffer(
117 web_contents
, OneClickSigninHelper::CAN_OFFER_FOR_INTERSTITAL_ONLY
,
118 base::UTF16ToUTF8(form_to_save
->associated_username()), NULL
))
122 InfoBarService::FromWebContents(web_contents
)->AddInfoBar(
123 ConfirmInfoBarDelegate::CreateInfoBar(scoped_ptr
<ConfirmInfoBarDelegate
>(
124 new SavePasswordInfoBarDelegate(form_to_save
,
125 uma_histogram_suffix
))));
128 SavePasswordInfoBarDelegate::SavePasswordInfoBarDelegate(
129 PasswordFormManager
* form_to_save
,
130 const std::string
& uma_histogram_suffix
)
131 : ConfirmInfoBarDelegate(),
132 form_to_save_(form_to_save
),
133 infobar_response_(NO_RESPONSE
),
134 uma_histogram_suffix_(uma_histogram_suffix
) {
135 if (!uma_histogram_suffix_
.empty()) {
136 password_manager_metrics_util::LogUMAHistogramBoolean(
137 "PasswordManager.SavePasswordPromptDisplayed_" + uma_histogram_suffix_
,
142 SavePasswordInfoBarDelegate::~SavePasswordInfoBarDelegate() {
143 UMA_HISTOGRAM_ENUMERATION("PasswordManager.InfoBarResponse",
144 infobar_response_
, NUM_RESPONSE_TYPES
);
146 // The shortest period for which the prompt needs to live, so that we don't
147 // consider it killed prematurely, as might happen, e.g., if a pre-rendered
148 // page gets swapped in (and the current WebContents is destroyed).
149 const base::TimeDelta kMinimumPromptDisplayTime
=
150 base::TimeDelta::FromSeconds(1);
152 if (!uma_histogram_suffix_
.empty()) {
153 password_manager_metrics_util::LogUMAHistogramEnumeration(
154 "PasswordManager.SavePasswordPromptResponse_" + uma_histogram_suffix_
,
155 infobar_response_
, NUM_RESPONSE_TYPES
);
156 password_manager_metrics_util::LogUMAHistogramBoolean(
157 "PasswordManager.SavePasswordPromptDisappearedQuickly_" +
158 uma_histogram_suffix_
,
159 timer_
.Elapsed() < kMinimumPromptDisplayTime
);
163 bool SavePasswordInfoBarDelegate::ShouldExpire(
164 const content::LoadCommittedDetails
& details
) const {
165 bool is_not_redirect
= !(details
.entry
->GetTransitionType() &
166 content::PAGE_TRANSITION_IS_REDIRECT_MASK
);
167 return is_not_redirect
&& InfoBarDelegate::ShouldExpire(details
);
170 int SavePasswordInfoBarDelegate::GetIconID() const {
171 return IDR_INFOBAR_SAVE_PASSWORD
;
174 InfoBarDelegate::Type
SavePasswordInfoBarDelegate::GetInfoBarType() const {
175 return PAGE_ACTION_TYPE
;
178 base::string16
SavePasswordInfoBarDelegate::GetMessageText() const {
179 return l10n_util::GetStringUTF16(IDS_PASSWORD_MANAGER_SAVE_PASSWORD_PROMPT
);
182 base::string16
SavePasswordInfoBarDelegate::GetButtonLabel(
183 InfoBarButton button
) const {
184 return l10n_util::GetStringUTF16((button
== BUTTON_OK
) ?
185 IDS_PASSWORD_MANAGER_SAVE_BUTTON
: IDS_PASSWORD_MANAGER_BLACKLIST_BUTTON
);
188 bool SavePasswordInfoBarDelegate::Accept() {
189 DCHECK(form_to_save_
.get());
190 form_to_save_
->Save();
191 infobar_response_
= REMEMBER_PASSWORD
;
195 bool SavePasswordInfoBarDelegate::Cancel() {
196 DCHECK(form_to_save_
.get());
197 form_to_save_
->PermanentlyBlacklist();
198 infobar_response_
= NEVER_REMEMBER_PASSWORD
;
202 void SavePasswordInfoBarDelegate::InfoBarDismissed() {
203 DCHECK(form_to_save_
.get());
204 infobar_response_
= INFOBAR_DISMISSED
;
207 InfoBarDelegate::InfoBarAutomationType
208 SavePasswordInfoBarDelegate::GetInfoBarAutomationType() const {
209 return PASSWORD_INFOBAR
;
213 // PasswordManagerDelegateImpl ------------------------------------------------
215 DEFINE_WEB_CONTENTS_USER_DATA_KEY(PasswordManagerDelegateImpl
);
217 PasswordManagerDelegateImpl::PasswordManagerDelegateImpl(
218 content::WebContents
* web_contents
)
219 : web_contents_(web_contents
) {
222 PasswordManagerDelegateImpl::~PasswordManagerDelegateImpl() {
225 void PasswordManagerDelegateImpl::FillPasswordForm(
226 const autofill::PasswordFormFillData
& form_data
) {
227 web_contents_
->GetRenderViewHost()->Send(
228 new AutofillMsg_FillPasswordForm(
229 web_contents_
->GetRenderViewHost()->GetRoutingID(),
233 void PasswordManagerDelegateImpl::AddSavePasswordInfoBarIfPermitted(
234 PasswordFormManager
* form_to_save
) {
235 std::string
uma_histogram_suffix(
236 password_manager_metrics_util::GroupIdToString(
237 password_manager_metrics_util::MonitoredDomainGroupId(
238 form_to_save
->realm(), GetProfile()->GetPrefs())));
239 SavePasswordInfoBarDelegate::Create(
240 web_contents_
, form_to_save
, uma_histogram_suffix
);
243 Profile
* PasswordManagerDelegateImpl::GetProfile() {
244 return Profile::FromBrowserContext(web_contents_
->GetBrowserContext());
247 bool PasswordManagerDelegateImpl::DidLastPageLoadEncounterSSLErrors() {
248 content::NavigationEntry
* entry
=
249 web_contents_
->GetController().GetActiveEntry();
255 return net::IsCertStatusError(entry
->GetSSL().cert_status
);