OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/password_manager/password_manager.h" | 5 #include "chrome/browser/password_manager/password_manager.h" |
6 | 6 |
7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
8 #include "base/metrics/field_trial.h" | 8 #include "base/metrics/field_trial.h" |
9 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
10 #include "base/prefs/pref_service.h" | 10 #include "base/prefs/pref_service.h" |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
55 ran_once = true; | 55 ran_once = true; |
56 | 56 |
57 // TODO(isherman): This does not actually measure a user action. It should be | 57 // TODO(isherman): This does not actually measure a user action. It should be |
58 // a boolean histogram. | 58 // a boolean histogram. |
59 if (password_manager_enabled) | 59 if (password_manager_enabled) |
60 content::RecordAction(UserMetricsAction("PasswordManager_Enabled")); | 60 content::RecordAction(UserMetricsAction("PasswordManager_Enabled")); |
61 else | 61 else |
62 content::RecordAction(UserMetricsAction("PasswordManager_Disabled")); | 62 content::RecordAction(UserMetricsAction("PasswordManager_Disabled")); |
63 } | 63 } |
64 | 64 |
65 void ReportSavePasswordInfoBarFailure( | |
66 const enum PasswordManager::PotentialInfoBarErrorReasons reason_id, | |
67 const GURL& url) { | |
68 std::string domain_name = url.host(); | |
69 | |
70 if (domain_name.size()) | |
71 domain_name.insert(0, "_"); | |
vabr (Chromium)
2013/08/14 14:39:58
We may not append any domain name, only one of a c
Garrett Casto
2013/08/14 23:02:47
I didn't even realize you could send any identifia
vabr (Chromium)
2013/08/16 09:02:14
Yeah, we have to be careful. Logging the domain fo
| |
72 | |
73 UMA_HISTOGRAM_BOOLEAN("PasswordManager.InfobarDisplayed" + domain_name, | |
Garrett Casto
2013/08/14 23:02:47
I'm not sure if this is necessary as if this is ne
vabr (Chromium)
2013/08/16 09:02:14
That's a good point.
Jordy, when you are back, le
| |
74 false); | |
75 UMA_HISTOGRAM_ENUMERATION( | |
76 "PasswordManager.PotentialInfoBarErrorReasons" + domain_name, reason_id, | |
77 PasswordManager::NUM_ERROR_TYPES); | |
78 } | |
79 | |
65 } // namespace | 80 } // namespace |
66 | 81 |
67 // static | 82 // static |
68 void PasswordManager::RegisterProfilePrefs( | 83 void PasswordManager::RegisterProfilePrefs( |
69 user_prefs::PrefRegistrySyncable* registry) { | 84 user_prefs::PrefRegistrySyncable* registry) { |
70 registry->RegisterBooleanPref( | 85 registry->RegisterBooleanPref( |
71 prefs::kPasswordManagerEnabled, | 86 prefs::kPasswordManagerEnabled, |
72 true, | 87 true, |
73 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); | 88 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF); |
74 registry->RegisterBooleanPref( | 89 registry->RegisterBooleanPref( |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
130 manager->SetHasGeneratedPassword(); | 145 manager->SetHasGeneratedPassword(); |
131 // TODO(gcasto): Add UMA stats to track this. | 146 // TODO(gcasto): Add UMA stats to track this. |
132 } | 147 } |
133 | 148 |
134 bool PasswordManager::IsSavingEnabled() const { | 149 bool PasswordManager::IsSavingEnabled() const { |
135 return *password_manager_enabled_ && | 150 return *password_manager_enabled_ && |
136 !delegate_->GetProfile()->IsOffTheRecord(); | 151 !delegate_->GetProfile()->IsOffTheRecord(); |
137 } | 152 } |
138 | 153 |
139 void PasswordManager::ProvisionallySavePassword(const PasswordForm& form) { | 154 void PasswordManager::ProvisionallySavePassword(const PasswordForm& form) { |
140 if (!IsSavingEnabled()) | 155 if (!IsSavingEnabled()) { |
Garrett Casto
2013/08/14 23:02:47
I actually just submitted a CL (https://codereview
| |
156 ReportSavePasswordInfoBarFailure(SAVE_PASSWORD_DISABLE, form.origin); | |
141 return; | 157 return; |
158 } | |
142 | 159 |
143 // No password to save? Then don't. | 160 // No password to save? Then don't. |
144 if (form.password_value.empty()) | 161 if (form.password_value.empty()) { |
162 ReportSavePasswordInfoBarFailure(EMPTY_PASSWORD, form.origin); | |
145 return; | 163 return; |
164 } | |
146 | 165 |
147 scoped_ptr<PasswordFormManager> manager; | 166 scoped_ptr<PasswordFormManager> manager; |
148 ScopedVector<PasswordFormManager>::iterator matched_manager_it = | 167 ScopedVector<PasswordFormManager>::iterator matched_manager_it = |
149 pending_login_managers_.end(); | 168 pending_login_managers_.end(); |
150 for (ScopedVector<PasswordFormManager>::iterator iter = | 169 for (ScopedVector<PasswordFormManager>::iterator iter = |
151 pending_login_managers_.begin(); | 170 pending_login_managers_.begin(); |
152 iter != pending_login_managers_.end(); ++iter) { | 171 iter != pending_login_managers_.end(); ++iter) { |
153 // If we find a manager that exactly matches the submitted form including | 172 // If we find a manager that exactly matches the submitted form including |
154 // the action URL, exit the loop. | 173 // the action URL, exit the loop. |
155 if ((*iter)->DoesManage( | 174 if ((*iter)->DoesManage( |
(...skipping 10 matching lines...) Expand all Loading... | |
166 } | 185 } |
167 // If we didn't find a manager, this means a form was submitted without | 186 // If we didn't find a manager, this means a form was submitted without |
168 // first loading the page containing the form. Don't offer to save | 187 // first loading the page containing the form. Don't offer to save |
169 // passwords in this case. | 188 // passwords in this case. |
170 if (matched_manager_it != pending_login_managers_.end()) { | 189 if (matched_manager_it != pending_login_managers_.end()) { |
171 // Transfer ownership of the manager from |pending_login_managers_| to | 190 // Transfer ownership of the manager from |pending_login_managers_| to |
172 // |manager|. | 191 // |manager|. |
173 manager.reset(*matched_manager_it); | 192 manager.reset(*matched_manager_it); |
174 pending_login_managers_.weak_erase(matched_manager_it); | 193 pending_login_managers_.weak_erase(matched_manager_it); |
175 } else { | 194 } else { |
195 ReportSavePasswordInfoBarFailure(FIRST_PAGE_NOT_LOADED, form.origin); | |
176 return; | 196 return; |
177 } | 197 } |
178 | 198 |
179 // If we found a manager but it didn't finish matching yet, the user has | 199 // If we found a manager but it didn't finish matching yet, the user has |
180 // tried to submit credentials before we had time to even find matching | 200 // tried to submit credentials before we had time to even find matching |
181 // results for the given form and autofill. If this is the case, we just | 201 // results for the given form and autofill. If this is the case, we just |
182 // give up. | 202 // give up. |
183 if (!manager->HasCompletedMatching()) | 203 if (!manager->HasCompletedMatching()) { |
204 ReportSavePasswordInfoBarFailure(MATCHING_ONGOING, form.origin); | |
184 return; | 205 return; |
206 } | |
185 | 207 |
186 // Also get out of here if the user told us to 'never remember' passwords for | 208 // Also get out of here if the user told us to 'never remember' passwords for |
187 // this form. | 209 // this form. |
188 if (manager->IsBlacklisted()) | 210 if (manager->IsBlacklisted()) { |
211 ReportSavePasswordInfoBarFailure(NEVER_REMEMBER, form.origin); | |
189 return; | 212 return; |
213 } | |
190 | 214 |
191 // Bail if we're missing any of the necessary form components. | 215 // Bail if we're missing any of the necessary form components. |
192 if (!manager->HasValidPasswordForm()) | 216 if (!manager->HasValidPasswordForm()) { |
217 ReportSavePasswordInfoBarFailure(INVALID_FORM, form.origin); | |
193 return; | 218 return; |
219 } | |
194 | 220 |
195 // Always save generated passwords, as the user expresses explicit intent for | 221 // Always save generated passwords, as the user expresses explicit intent for |
196 // Chrome to manage such passwords. For other passwords, respect the | 222 // Chrome to manage such passwords. For other passwords, respect the |
197 // autocomplete attribute. | 223 // autocomplete attribute. |
198 if (!manager->HasGeneratedPassword() && !form.password_autocomplete_set) | 224 if (!manager->HasGeneratedPassword() && !form.password_autocomplete_set) { |
225 ReportSavePasswordInfoBarFailure(PASSWORD_GENERATED_OR_AUTOCOMPLETED, | |
226 form.origin); | |
199 return; | 227 return; |
228 } | |
200 | 229 |
201 PasswordForm provisionally_saved_form(form); | 230 PasswordForm provisionally_saved_form(form); |
202 provisionally_saved_form.ssl_valid = form.origin.SchemeIsSecure() && | 231 provisionally_saved_form.ssl_valid = form.origin.SchemeIsSecure() && |
203 !delegate_->DidLastPageLoadEncounterSSLErrors(); | 232 !delegate_->DidLastPageLoadEncounterSSLErrors(); |
204 provisionally_saved_form.preferred = true; | 233 provisionally_saved_form.preferred = true; |
205 PasswordFormManager::OtherPossibleUsernamesAction action = | 234 PasswordFormManager::OtherPossibleUsernamesAction action = |
206 PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES; | 235 PasswordFormManager::IGNORE_OTHER_POSSIBLE_USERNAMES; |
207 if (OtherPossibleUsernamesEnabled()) | 236 if (OtherPossibleUsernamesEnabled()) |
208 action = PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES; | 237 action = PasswordFormManager::ALLOW_OTHER_POSSIBLE_USERNAMES; |
209 manager->ProvisionallySave(provisionally_saved_form, action); | 238 manager->ProvisionallySave(provisionally_saved_form, action); |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
263 new PasswordFormManager(delegate_->GetProfile(), | 292 new PasswordFormManager(delegate_->GetProfile(), |
264 this, | 293 this, |
265 web_contents(), | 294 web_contents(), |
266 *iter, | 295 *iter, |
267 ssl_valid); | 296 ssl_valid); |
268 pending_login_managers_.push_back(manager); | 297 pending_login_managers_.push_back(manager); |
269 manager->FetchMatchingLoginsFromPasswordStore(); | 298 manager->FetchMatchingLoginsFromPasswordStore(); |
270 } | 299 } |
271 } | 300 } |
272 | 301 |
273 bool PasswordManager::ShouldShowSavePasswordInfoBar() const { | 302 bool PasswordManager::ShouldShowSavePasswordInfoBar() const { |
Garrett Casto
2013/08/14 23:02:47
I don't think that this function does what you thi
| |
274 return provisional_save_manager_->IsNewLogin() && | 303 |
275 !provisional_save_manager_->HasGeneratedPassword() && | 304 // All functions are tested on by one in order to send the appropriate |
vabr (Chromium)
2013/08/14 14:39:58
on by one -> one by one
| |
276 !provisional_save_manager_->IsPendingCredentialsPublicSuffixMatch(); | 305 // UMA signal with the ReportSavePasswordInfoBarFailure function. |
306 if (!provisional_save_manager_->IsNewLogin()) { | |
307 ReportSavePasswordInfoBarFailure(LOGIN_ALREADY_KNEW, | |
308 GURL(provisional_save_manager_->realm())); | |
309 return false; | |
310 } | |
311 if (provisional_save_manager_->HasGeneratedPassword()) { | |
312 ReportSavePasswordInfoBarFailure(PASSWORD_GENERATED, | |
313 GURL(provisional_save_manager_->realm())); | |
314 return false; | |
315 } | |
316 if (provisional_save_manager_->IsPendingCredentialsPublicSuffixMatch()) { | |
317 ReportSavePasswordInfoBarFailure(ORIGIN_MATCHING_OF_PUBLIC_SUFFIX, | |
318 GURL(provisional_save_manager_->realm())); | |
319 return false; | |
320 } | |
321 return true; | |
277 } | 322 } |
278 | 323 |
279 void PasswordManager::OnPasswordFormsRendered( | 324 void PasswordManager::OnPasswordFormsRendered( |
280 const std::vector<PasswordForm>& visible_forms) { | 325 const std::vector<PasswordForm>& visible_forms) { |
281 if (!provisional_save_manager_.get()) | 326 if (!provisional_save_manager_.get()) { |
327 ReportSavePasswordInfoBarFailure(CANNOT_GET_THE_PROVIOSIONAL_PASSWORD, | |
328 visible_forms[0].origin); | |
Garrett Casto
2013/08/14 23:02:47
Not sure if any of the reporting in this function
| |
282 return; | 329 return; |
330 } | |
283 | 331 |
284 DCHECK(IsSavingEnabled()); | 332 DCHECK(IsSavingEnabled()); |
285 | 333 |
286 // First, check for a failed login attempt. | 334 // First, check for a failed login attempt. |
287 for (std::vector<PasswordForm>::const_iterator iter = visible_forms.begin(); | 335 for (std::vector<PasswordForm>::const_iterator iter = visible_forms.begin(); |
288 iter != visible_forms.end(); ++iter) { | 336 iter != visible_forms.end(); ++iter) { |
289 if (provisional_save_manager_->DoesManage( | 337 if (provisional_save_manager_->DoesManage( |
290 *iter, PasswordFormManager::ACTION_MATCH_REQUIRED)) { | 338 *iter, PasswordFormManager::ACTION_MATCH_REQUIRED)) { |
291 // The form trying to be saved has immediately re-appeared. Assume login | 339 // The form trying to be saved has immediately re-appeared. Assume login |
292 // failure and abort this save, by clearing provisional_save_manager_. | 340 // failure and abort this save, by clearing provisional_save_manager_. |
341 ReportSavePasswordInfoBarFailure( | |
342 FORM_REAPPEARED, GURL(provisional_save_manager_->realm())); | |
Garrett Casto
2013/08/14 23:02:47
We already keep track of this stat in the provisio
| |
293 provisional_save_manager_->SubmitFailed(); | 343 provisional_save_manager_->SubmitFailed(); |
294 provisional_save_manager_.reset(); | 344 provisional_save_manager_.reset(); |
295 return; | 345 return; |
296 } | 346 } |
297 } | 347 } |
298 | 348 |
299 if (!provisional_save_manager_->HasValidPasswordForm()) { | 349 if (!provisional_save_manager_->HasValidPasswordForm()) { |
300 // Form is not completely valid - we do not support it. | 350 // Form is not completely valid - we do not support it. |
301 NOTREACHED(); | 351 NOTREACHED(); |
352 ReportSavePasswordInfoBarFailure(INVALID_FORM, | |
353 GURL(provisional_save_manager_->realm())); | |
302 provisional_save_manager_.reset(); | 354 provisional_save_manager_.reset(); |
303 return; | 355 return; |
304 } | 356 } |
305 | 357 |
306 // Looks like a successful login attempt. Either show an infobar or | 358 // Looks like a successful login attempt. Either show an infobar or |
307 // automatically save the login data. We prompt when the user hasn't already | 359 // automatically save the login data. We prompt when the user hasn't already |
308 // given consent, either through previously accepting the infobar or by having | 360 // given consent, either through previously accepting the infobar or by having |
309 // the browser generate the password. | 361 // the browser generate the password. |
310 provisional_save_manager_->SubmitPassed(); | 362 provisional_save_manager_->SubmitPassed(); |
311 if (provisional_save_manager_->HasGeneratedPassword()) | 363 if (provisional_save_manager_->HasGeneratedPassword()) |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
386 return; | 438 return; |
387 } | 439 } |
388 default: | 440 default: |
389 FOR_EACH_OBSERVER( | 441 FOR_EACH_OBSERVER( |
390 LoginModelObserver, | 442 LoginModelObserver, |
391 observers_, | 443 observers_, |
392 OnAutofillDataAvailable(preferred_match.username_value, | 444 OnAutofillDataAvailable(preferred_match.username_value, |
393 preferred_match.password_value)); | 445 preferred_match.password_value)); |
394 } | 446 } |
395 } | 447 } |
OLD | NEW |