OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 <vector> | |
8 | |
9 #include "base/stl_util.h" | |
10 #include "base/threading/platform_thread.h" | 7 #include "base/threading/platform_thread.h" |
11 #include "base/utf_string_conversions.h" | 8 #include "base/utf_string_conversions.h" |
12 #include "chrome/browser/password_manager/password_form_manager.h" | 9 #include "chrome/browser/password_manager/password_form_manager.h" |
13 #include "chrome/browser/password_manager/password_manager_delegate.h" | 10 #include "chrome/browser/password_manager/password_manager_delegate.h" |
14 #include "chrome/browser/prefs/pref_service.h" | 11 #include "chrome/browser/prefs/pref_service.h" |
15 #include "chrome/browser/profiles/profile.h" | 12 #include "chrome/browser/profiles/profile.h" |
16 #include "chrome/common/autofill_messages.h" | 13 #include "chrome/common/autofill_messages.h" |
17 #include "chrome/common/pref_names.h" | 14 #include "chrome/common/pref_names.h" |
18 #include "content/public/browser/user_metrics.h" | 15 #include "content/public/browser/user_metrics.h" |
19 #include "content/public/common/frame_navigate_params.h" | 16 #include "content/public/common/frame_navigate_params.h" |
20 #include "grit/generated_resources.h" | 17 #include "grit/generated_resources.h" |
21 | 18 |
22 using content::UserMetricsAction; | 19 using content::UserMetricsAction; |
23 using content::WebContents; | 20 using content::WebContents; |
24 using webkit::forms::PasswordForm; | 21 using webkit::forms::PasswordForm; |
25 using webkit::forms::PasswordFormMap; | 22 using webkit::forms::PasswordFormMap; |
26 | 23 |
27 // static | 24 namespace { |
28 void PasswordManager::RegisterUserPrefs(PrefService* prefs) { | |
29 prefs->RegisterBooleanPref(prefs::kPasswordManagerEnabled, | |
30 true, | |
31 PrefService::SYNCABLE_PREF); | |
32 prefs->RegisterBooleanPref(prefs::kPasswordManagerAllowShowPasswords, | |
33 true, | |
34 PrefService::UNSYNCABLE_PREF); | |
35 } | |
36 | 25 |
37 // This routine is called when PasswordManagers are constructed. | 26 // This routine is called when PasswordManagers are constructed. |
38 // | 27 // |
39 // Currently we report metrics only once at startup. We require | 28 // Currently we report metrics only once at startup. We require |
40 // that this is only ever called from a single thread in order to | 29 // that this is only ever called from a single thread in order to |
41 // avoid needing to lock (a static boolean flag is then sufficient to | 30 // avoid needing to lock (a static boolean flag is then sufficient to |
42 // guarantee running only once). | 31 // guarantee running only once). |
43 static void ReportMetrics(bool password_manager_enabled) { | 32 void ReportMetrics(bool password_manager_enabled) { |
44 static base::PlatformThreadId initial_thread_id = | 33 static base::PlatformThreadId initial_thread_id = |
45 base::PlatformThread::CurrentId(); | 34 base::PlatformThread::CurrentId(); |
46 DCHECK(initial_thread_id == base::PlatformThread::CurrentId()); | 35 DCHECK(initial_thread_id == base::PlatformThread::CurrentId()); |
47 | 36 |
48 static bool ran_once = false; | 37 static bool ran_once = false; |
49 if (ran_once) | 38 if (ran_once) |
50 return; | 39 return; |
51 ran_once = true; | 40 ran_once = true; |
52 | 41 |
42 // TODO(isherman): This does not actually measure a user action. It should be | |
43 // a boolean histogram. | |
53 if (password_manager_enabled) | 44 if (password_manager_enabled) |
54 content::RecordAction(UserMetricsAction("PasswordManager_Enabled")); | 45 content::RecordAction(UserMetricsAction("PasswordManager_Enabled")); |
55 else | 46 else |
56 content::RecordAction(UserMetricsAction("PasswordManager_Disabled")); | 47 content::RecordAction(UserMetricsAction("PasswordManager_Disabled")); |
57 } | 48 } |
58 | 49 |
50 } // anonymous namespace | |
51 | |
52 // static | |
53 void PasswordManager::RegisterUserPrefs(PrefService* prefs) { | |
54 prefs->RegisterBooleanPref(prefs::kPasswordManagerEnabled, | |
55 true, | |
56 PrefService::SYNCABLE_PREF); | |
57 prefs->RegisterBooleanPref(prefs::kPasswordManagerAllowShowPasswords, | |
58 true, | |
59 PrefService::UNSYNCABLE_PREF); | |
60 } | |
61 | |
59 PasswordManager::PasswordManager(WebContents* web_contents, | 62 PasswordManager::PasswordManager(WebContents* web_contents, |
60 PasswordManagerDelegate* delegate) | 63 PasswordManagerDelegate* delegate) |
61 : content::WebContentsObserver(web_contents), | 64 : content::WebContentsObserver(web_contents), |
62 login_managers_deleter_(&pending_login_managers_), | |
63 delegate_(delegate), | 65 delegate_(delegate), |
64 observer_(NULL) { | 66 observer_(NULL) { |
65 DCHECK(delegate_); | 67 DCHECK(delegate_); |
66 password_manager_enabled_.Init(prefs::kPasswordManagerEnabled, | 68 password_manager_enabled_.Init(prefs::kPasswordManagerEnabled, |
67 delegate_->GetProfileForPasswordManager()->GetPrefs(), NULL); | 69 delegate_->GetProfileForPasswordManager()->GetPrefs(), NULL); |
68 | 70 |
69 ReportMetrics(*password_manager_enabled_); | 71 ReportMetrics(*password_manager_enabled_); |
70 } | 72 } |
71 | 73 |
72 PasswordManager::~PasswordManager() { | 74 PasswordManager::~PasswordManager() { |
73 } | 75 } |
74 | 76 |
75 void PasswordManager::ProvisionallySavePassword(PasswordForm form) { | 77 void PasswordManager::ProvisionallySavePassword(const PasswordForm& form) { |
76 if (!delegate_->GetProfileForPasswordManager() || | 78 if (!IsEnabled()) |
77 delegate_->GetProfileForPasswordManager()->IsOffTheRecord() || | |
78 !*password_manager_enabled_) | |
79 return; | 79 return; |
80 | 80 |
81 // No password to save? Then don't. | 81 // No password to save? Then don't. |
82 if (form.password_value.empty()) | 82 if (form.password_value.empty()) |
83 return; | 83 return; |
84 | 84 |
85 LoginManagers::iterator iter; | |
86 PasswordFormManager* manager = NULL; | 85 PasswordFormManager* manager = NULL; |
87 for (iter = pending_login_managers_.begin(); | 86 for (ScopedVector<PasswordFormManager>::iterator iter = |
88 iter != pending_login_managers_.end(); iter++) { | 87 pending_login_managers_.begin(); |
88 iter != pending_login_managers_.end(); ++iter) { | |
89 if ((*iter)->DoesManage(form)) { | 89 if ((*iter)->DoesManage(form)) { |
90 manager = *iter; | 90 manager = *iter; |
91 pending_login_managers_.weak_erase(iter); | |
91 break; | 92 break; |
92 } | 93 } |
93 } | 94 } |
94 // If we didn't find a manager, this means a form was submitted without | 95 // If we didn't find a manager, this means a form was submitted without |
95 // first loading the page containing the form. Don't offer to save | 96 // first loading the page containing the form. Don't offer to save |
96 // passwords in this case. | 97 // passwords in this case. |
97 if (!manager) | 98 if (!manager) |
98 return; | 99 return; |
99 | 100 |
100 // If we found a manager but it didn't finish matching yet, the user has | 101 // If we found a manager but it didn't finish matching yet, the user has |
101 // tried to submit credentials before we had time to even find matching | 102 // tried to submit credentials before we had time to even find matching |
102 // results for the given form and autofill. If this is the case, we just | 103 // results for the given form and autofill. If this is the case, we just |
103 // give up. | 104 // give up. |
104 if (!manager->HasCompletedMatching()) | 105 if (!manager->HasCompletedMatching()) |
105 return; | 106 return; |
106 | 107 |
107 // Also get out of here if the user told us to 'never remember' passwords for | 108 // Also get out of here if the user told us to 'never remember' passwords for |
108 // this form. | 109 // this form. |
109 if (manager->IsBlacklisted()) | 110 if (manager->IsBlacklisted()) |
110 return; | 111 return; |
111 | 112 |
112 form.ssl_valid = form.origin.SchemeIsSecure() && | 113 PasswordForm provisionally_saved_form(form); |
114 provisionally_saved_form.ssl_valid = form.origin.SchemeIsSecure() && | |
113 !delegate_->DidLastPageLoadEncounterSSLErrors(); | 115 !delegate_->DidLastPageLoadEncounterSSLErrors(); |
114 form.preferred = true; | 116 provisionally_saved_form.preferred = true; |
115 manager->ProvisionallySave(form); | 117 manager->ProvisionallySave(provisionally_saved_form); |
116 provisional_save_manager_.reset(manager); | 118 provisional_save_manager_.reset(manager); |
Mike Mammarella
2012/03/01 08:23:51
Do we want to clear pending_login_managers_ here,
Ilya Sherman
2012/03/01 08:39:18
AFAICT, this is only ever called from DidNavigateA
| |
117 pending_login_managers_.erase(iter); | |
118 // We don't care about the rest of the forms on the page now that one | |
119 // was selected. | |
120 STLDeleteElements(&pending_login_managers_); | |
121 } | |
122 | |
123 void PasswordManager::DidNavigate() { | |
124 // As long as this navigation isn't due to a currently pending | |
125 // password form submit, we're ready to reset and move on. | |
126 if (!provisional_save_manager_.get() && !pending_login_managers_.empty()) | |
127 STLDeleteElements(&pending_login_managers_); | |
128 } | |
129 | |
130 void PasswordManager::ClearProvisionalSave() { | |
131 provisional_save_manager_.reset(); | |
132 } | 119 } |
133 | 120 |
134 void PasswordManager::SetObserver(LoginModelObserver* observer) { | 121 void PasswordManager::SetObserver(LoginModelObserver* observer) { |
135 observer_ = observer; | 122 observer_ = observer; |
136 } | 123 } |
137 | 124 |
138 void PasswordManager::DidStopLoading() { | 125 void PasswordManager::DidStopLoading() { |
139 if (!provisional_save_manager_.get()) | 126 if (!provisional_save_manager_.get()) |
140 return; | 127 return; |
141 | 128 |
142 DCHECK(!delegate_->GetProfileForPasswordManager()->IsOffTheRecord()); | 129 DCHECK(IsEnabled()); |
143 DCHECK(!provisional_save_manager_->IsBlacklisted()); | |
144 | 130 |
145 if (!delegate_->GetProfileForPasswordManager()) | |
146 return; | |
147 // Form is not completely valid - we do not support it. | 131 // Form is not completely valid - we do not support it. |
148 if (!provisional_save_manager_->HasValidPasswordForm()) | 132 if (!provisional_save_manager_->HasValidPasswordForm()) |
149 return; | 133 return; |
150 | 134 |
151 provisional_save_manager_->SubmitPassed(); | 135 provisional_save_manager_->SubmitPassed(); |
152 if (provisional_save_manager_->IsNewLogin()) { | 136 if (provisional_save_manager_->IsNewLogin()) { |
153 delegate_->AddSavePasswordInfoBar(provisional_save_manager_.release()); | 137 delegate_->AddSavePasswordInfoBar(provisional_save_manager_.release()); |
154 } else { | 138 } else { |
155 // If the save is not a new username entry, then we just want to save this | 139 // If the save is not a new username entry, then we just want to save this |
156 // data (since the user already has related data saved), so don't prompt. | 140 // data (since the user already has related data saved), so don't prompt. |
157 provisional_save_manager_->Save(); | 141 provisional_save_manager_->Save(); |
158 provisional_save_manager_.reset(); | 142 provisional_save_manager_.reset(); |
159 } | 143 } |
160 } | 144 } |
161 | 145 |
162 void PasswordManager::DidNavigateAnyFrame( | 146 void PasswordManager::DidNavigateAnyFrame( |
163 const content::LoadCommittedDetails& details, | 147 const content::LoadCommittedDetails& details, |
164 const content::FrameNavigateParams& params) { | 148 const content::FrameNavigateParams& params) { |
165 if (params.password_form.origin.is_valid()) | 149 if (params.password_form.origin.is_valid()) |
166 ProvisionallySavePassword(params.password_form); | 150 ProvisionallySavePassword(params.password_form); |
151 | |
152 // Other than possibly holding on to provisionally saved password data, | |
153 // we're ready to reset and move on. | |
154 pending_login_managers_.reset(); | |
tim (not reviewing)
2012/03/01 17:57:52
So, two things. One, yeah, DidNavigate (then in W
Mike Mammarella
2012/03/01 19:02:04
That sounds both plausible and eminently testable.
Ilya Sherman
2012/03/02 01:07:15
Ah, that's a really good catch -- I hadn't really
| |
167 } | 155 } |
168 | 156 |
169 bool PasswordManager::OnMessageReceived(const IPC::Message& message) { | 157 bool PasswordManager::OnMessageReceived(const IPC::Message& message) { |
170 bool handled = true; | 158 bool handled = true; |
171 IPC_BEGIN_MESSAGE_MAP(PasswordManager, message) | 159 IPC_BEGIN_MESSAGE_MAP(PasswordManager, message) |
172 IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormsFound, | 160 IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormsFound, |
173 OnPasswordFormsFound) | 161 OnPasswordFormsFound) |
174 IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormsVisible, | 162 IPC_MESSAGE_HANDLER(AutofillHostMsg_PasswordFormsVisible, |
175 OnPasswordFormsVisible) | 163 OnPasswordFormsVisible) |
176 IPC_MESSAGE_UNHANDLED(handled = false) | 164 IPC_MESSAGE_UNHANDLED(handled = false) |
177 IPC_END_MESSAGE_MAP() | 165 IPC_END_MESSAGE_MAP() |
178 return handled; | 166 return handled; |
179 } | 167 } |
180 | 168 |
181 void PasswordManager::OnPasswordFormsFound( | 169 void PasswordManager::OnPasswordFormsFound( |
182 const std::vector<PasswordForm>& forms) { | 170 const std::vector<PasswordForm>& forms) { |
183 if (!delegate_->GetProfileForPasswordManager()) | 171 if (!IsEnabled()) |
184 return; | |
185 if (!*password_manager_enabled_) | |
186 return; | 172 return; |
187 | 173 |
188 // Ask the SSLManager for current security. | 174 // Ask the SSLManager for current security. |
189 bool had_ssl_error = delegate_->DidLastPageLoadEncounterSSLErrors(); | 175 bool had_ssl_error = delegate_->DidLastPageLoadEncounterSSLErrors(); |
190 | 176 |
191 std::vector<PasswordForm>::const_iterator iter; | 177 for (std::vector<PasswordForm>::const_iterator iter = forms.begin(); |
192 for (iter = forms.begin(); iter != forms.end(); iter++) { | 178 iter != forms.end(); ++iter) { |
193 bool ssl_valid = iter->origin.SchemeIsSecure() && !had_ssl_error; | 179 bool ssl_valid = iter->origin.SchemeIsSecure() && !had_ssl_error; |
194 PasswordFormManager* manager = | 180 PasswordFormManager* manager = |
195 new PasswordFormManager(delegate_->GetProfileForPasswordManager(), | 181 new PasswordFormManager(delegate_->GetProfileForPasswordManager(), |
196 this, *iter, ssl_valid); | 182 this, *iter, ssl_valid); |
197 pending_login_managers_.push_back(manager); | 183 pending_login_managers_.push_back(manager); |
198 manager->FetchMatchingLoginsFromPasswordStore(); | 184 manager->FetchMatchingLoginsFromPasswordStore(); |
199 } | 185 } |
200 } | 186 } |
201 | 187 |
202 void PasswordManager::OnPasswordFormsVisible( | 188 void PasswordManager::OnPasswordFormsVisible( |
203 const std::vector<PasswordForm>& visible_forms) { | 189 const std::vector<PasswordForm>& visible_forms) { |
204 if (!provisional_save_manager_.get()) | 190 if (!provisional_save_manager_.get()) |
205 return; | 191 return; |
206 std::vector<PasswordForm>::const_iterator iter; | 192 |
207 for (iter = visible_forms.begin(); iter != visible_forms.end(); iter++) { | 193 for (std::vector<PasswordForm>::const_iterator iter = visible_forms.begin(); |
194 iter != visible_forms.end(); ++iter) { | |
208 if (provisional_save_manager_->DoesManage(*iter)) { | 195 if (provisional_save_manager_->DoesManage(*iter)) { |
209 // The form trying to be saved has immediately re-appeared. Assume login | 196 // The form trying to be saved has immediately re-appeared. Assume login |
210 // failure and abort this save, by clearing provisional_save_manager_. | 197 // failure and abort this save, by clearing provisional_save_manager_. |
211 // Don't delete the login managers since the user may try again | 198 // Don't delete the login managers since the user may try again |
212 // and we want to be able to save in that case. | 199 // and we want to be able to save in that case. |
213 provisional_save_manager_->SubmitFailed(); | 200 provisional_save_manager_->SubmitFailed(); |
214 ClearProvisionalSave(); | 201 provisional_save_manager_.reset(); |
215 break; | 202 break; |
216 } | 203 } |
217 } | 204 } |
218 } | 205 } |
219 | 206 |
220 void PasswordManager::Autofill( | 207 void PasswordManager::Autofill( |
221 const PasswordForm& form_for_autofill, | 208 const PasswordForm& form_for_autofill, |
222 const PasswordFormMap& best_matches, | 209 const PasswordFormMap& best_matches, |
223 const PasswordForm* const preferred_match, | 210 const PasswordForm& preferred_match, |
224 bool wait_for_username) const { | 211 bool wait_for_username) const { |
225 DCHECK(preferred_match); | |
226 switch (form_for_autofill.scheme) { | 212 switch (form_for_autofill.scheme) { |
227 case PasswordForm::SCHEME_HTML: { | 213 case PasswordForm::SCHEME_HTML: { |
228 // Note the check above is required because the observer_ for a non-HTML | 214 // Note the check above is required because the observer_ for a non-HTML |
229 // schemed password form may have been freed, so we need to distinguish. | 215 // schemed password form may have been freed, so we need to distinguish. |
230 webkit::forms::PasswordFormFillData fill_data; | 216 webkit::forms::PasswordFormFillData fill_data; |
231 webkit::forms::PasswordFormDomManager::InitFillData(form_for_autofill, | 217 webkit::forms::PasswordFormDomManager::InitFillData(form_for_autofill, |
232 best_matches, | 218 best_matches, |
233 preferred_match, | 219 &preferred_match, |
234 wait_for_username, | 220 wait_for_username, |
235 &fill_data); | 221 &fill_data); |
236 delegate_->FillPasswordForm(fill_data); | 222 delegate_->FillPasswordForm(fill_data); |
237 return; | 223 return; |
238 } | 224 } |
239 default: | 225 default: |
240 if (observer_) { | 226 if (observer_) { |
241 observer_->OnAutofillDataAvailable(preferred_match->username_value, | 227 observer_->OnAutofillDataAvailable(preferred_match.username_value, |
242 preferred_match->password_value); | 228 preferred_match.password_value); |
243 } | 229 } |
244 } | 230 } |
245 } | 231 } |
232 | |
233 bool PasswordManager::IsEnabled() const { | |
234 const Profile* profile = delegate_->GetProfileForPasswordManager(); | |
235 return profile && !profile->IsOffTheRecord() && *password_manager_enabled_; | |
236 } | |
OLD | NEW |