OLD | NEW |
1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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_form_manager.h" | 5 #include "chrome/browser/password_manager/password_form_manager.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/string_util.h" | 9 #include "base/string_util.h" |
10 #include "chrome/browser/password_manager/password_manager.h" | 10 #include "chrome/browser/password_manager/password_manager.h" |
11 #include "chrome/browser/profile.h" | 11 #include "chrome/browser/profile.h" |
12 #include "webkit/glue/password_form_dom_manager.h" | 12 #include "webkit/glue/password_form_dom_manager.h" |
13 | 13 |
14 using base::Time; | 14 using base::Time; |
15 | 15 |
16 PasswordFormManager::PasswordFormManager(Profile* profile, | 16 PasswordFormManager::PasswordFormManager(Profile* profile, |
17 PasswordManager* password_manager, | 17 PasswordManager* password_manager, |
18 const PasswordForm& observed_form, | 18 const PasswordForm& observed_form, |
19 bool ssl_valid) | 19 bool ssl_valid) |
20 : best_matches_deleter_(&best_matches_), | 20 : best_matches_deleter_(&best_matches_), |
21 observed_form_(observed_form), | 21 observed_form_(observed_form), |
22 is_new_login_(true), | 22 is_new_login_(true), |
23 password_manager_(password_manager), | 23 password_manager_(password_manager), |
24 pending_login_query_(0), | 24 pending_login_query_(NULL), |
25 preferred_match_(NULL), | 25 preferred_match_(NULL), |
26 state_(PRE_MATCHING_PHASE), | 26 state_(PRE_MATCHING_PHASE), |
27 profile_(profile) { | 27 profile_(profile) { |
28 DCHECK(profile_); | 28 DCHECK(profile_); |
29 if (observed_form_.origin.is_valid()) | 29 if (observed_form_.origin.is_valid()) |
30 SplitString(observed_form_.origin.path(), '/', &form_path_tokens_); | 30 SplitString(observed_form_.origin.path(), '/', &form_path_tokens_); |
31 observed_form_.ssl_valid = ssl_valid; | 31 observed_form_.ssl_valid = ssl_valid; |
32 } | 32 } |
33 | 33 |
34 PasswordFormManager::~PasswordFormManager() { | 34 PasswordFormManager::~PasswordFormManager() { |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
161 if (IsNewLogin()) | 161 if (IsNewLogin()) |
162 SaveAsNewLogin(); | 162 SaveAsNewLogin(); |
163 else | 163 else |
164 UpdateLogin(); | 164 UpdateLogin(); |
165 } | 165 } |
166 | 166 |
167 void PasswordFormManager::FetchMatchingLoginsFromWebDatabase() { | 167 void PasswordFormManager::FetchMatchingLoginsFromWebDatabase() { |
168 DCHECK_EQ(state_, PRE_MATCHING_PHASE); | 168 DCHECK_EQ(state_, PRE_MATCHING_PHASE); |
169 DCHECK(!pending_login_query_); | 169 DCHECK(!pending_login_query_); |
170 state_ = MATCHING_PHASE; | 170 state_ = MATCHING_PHASE; |
171 PasswordStore* password_store = | 171 WebDataService* web_data_service = |
172 profile_->GetPasswordStore(Profile::EXPLICIT_ACCESS); | 172 profile_->GetWebDataService(Profile::EXPLICIT_ACCESS); |
173 if (!password_store) { | 173 if (!web_data_service) { |
174 NOTREACHED(); | 174 NOTREACHED(); |
175 return; | 175 return; |
176 } | 176 } |
177 pending_login_query_ = password_store->GetLogins(observed_form_, this); | 177 pending_login_query_ = web_data_service->GetLogins(observed_form_, this); |
178 } | 178 } |
179 | 179 |
180 bool PasswordFormManager::HasCompletedMatching() { | 180 bool PasswordFormManager::HasCompletedMatching() { |
181 return state_ == POST_MATCHING_PHASE; | 181 return state_ == POST_MATCHING_PHASE; |
182 } | 182 } |
183 | 183 |
184 void PasswordFormManager::OnRequestDone(int handle, | 184 void PasswordFormManager::OnRequestDone(WebDataService::Handle h, |
185 const std::vector<PasswordForm*>& logins_result) { | 185 const WDTypedResult* result) { |
| 186 // Get the result from the database into a usable form. |
| 187 const WDResult<std::vector<PasswordForm*> >* r = |
| 188 static_cast<const WDResult<std::vector<PasswordForm*> >*>(result); |
| 189 std::vector<PasswordForm*> logins_result = r->GetValue(); |
186 // Note that the result gets deleted after this call completes, but we own | 190 // Note that the result gets deleted after this call completes, but we own |
187 // the PasswordForm objects pointed to by the result vector, thus we keep | 191 // the PasswordForm objects pointed to by the result vector, thus we keep |
188 // copies to a minimum here. | 192 // copies to a minimum here. |
189 | 193 |
190 int best_score = 0; | 194 int best_score = 0; |
191 std::vector<PasswordForm> empties; // Empty-path matches in result set. | 195 std::vector<PasswordForm> empties; // Empty-path matches in result set. |
192 for (size_t i = 0; i < logins_result.size(); i++) { | 196 for (size_t i = 0; i < logins_result.size(); i++) { |
193 if (IgnoreResult(*logins_result[i])) { | 197 if (IgnoreResult(*logins_result[i])) { |
194 delete logins_result[i]; | 198 delete logins_result[i]; |
195 continue; | 199 continue; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
228 best_matches_.clear(); | 232 best_matches_.clear(); |
229 preferred_match_ = NULL; // Don't delete, its owned by best_matches_. | 233 preferred_match_ = NULL; // Don't delete, its owned by best_matches_. |
230 best_matches_[logins_result[i]->username_value] = logins_result[i]; | 234 best_matches_[logins_result[i]->username_value] = logins_result[i]; |
231 } | 235 } |
232 preferred_match_ = logins_result[i]->preferred ? logins_result[i] | 236 preferred_match_ = logins_result[i]->preferred ? logins_result[i] |
233 : preferred_match_; | 237 : preferred_match_; |
234 } | 238 } |
235 // We're done matching now. | 239 // We're done matching now. |
236 state_ = POST_MATCHING_PHASE; | 240 state_ = POST_MATCHING_PHASE; |
237 | 241 |
| 242 if (best_score <= 0) { |
| 243 #if defined(OS_WIN) |
| 244 state_ = PRE_MATCHING_PHASE; |
| 245 FetchMatchingIE7LoginFromWebDatabase(); |
| 246 #endif |
| 247 return; |
| 248 } |
| 249 |
238 for (std::vector<PasswordForm>::const_iterator it = empties.begin(); | 250 for (std::vector<PasswordForm>::const_iterator it = empties.begin(); |
239 it != empties.end(); ++it) { | 251 it != empties.end(); ++it) { |
240 // If we don't already have a result with the same username, add the | 252 // If we don't already have a result with the same username, add the |
241 // lower-scored empty-path match (if it had equal score it would already be | 253 // lower-scored empty-path match (if it had equal score it would already be |
242 // in best_matches_). | 254 // in best_matches_). |
243 if (best_matches_.find(it->username_value) == best_matches_.end()) | 255 if (best_matches_.find(it->username_value) == best_matches_.end()) |
244 best_matches_[it->username_value] = new PasswordForm(*it); | 256 best_matches_[it->username_value] = new PasswordForm(*it); |
245 } | 257 } |
246 | 258 |
247 // Its possible we have at least one match but have no preferred_match_, | 259 // Its possible we have at least one match but have no preferred_match_, |
248 // because a user may have chosen to 'Forget' the preferred match. So we | 260 // because a user may have chosen to 'Forget' the preferred match. So we |
249 // just pick the first one and whichever the user selects for submit will | 261 // just pick the first one and whichever the user selects for submit will |
250 // be saved as preferred. | 262 // be saved as preferred. |
251 DCHECK(!best_matches_.empty()); | 263 DCHECK(!best_matches_.empty()); |
252 if (!preferred_match_) | 264 if (!preferred_match_) |
253 preferred_match_ = best_matches_.begin()->second; | 265 preferred_match_ = best_matches_.begin()->second; |
254 | 266 |
255 // Now we determine if the user told us to ignore this site in the past. | 267 // Now we determine if the user told us to ignore this site in the past. |
256 // If they haven't, we proceed to auto-fill. | 268 // If they haven't, we proceed to auto-fill. |
257 if (!preferred_match_->blacklisted_by_user) { | 269 if (!preferred_match_->blacklisted_by_user) { |
258 password_manager_->Autofill(observed_form_, best_matches_, | 270 password_manager_->Autofill(observed_form_, best_matches_, |
259 preferred_match_); | 271 preferred_match_); |
260 } | 272 } |
261 } | 273 } |
262 | 274 |
263 void PasswordFormManager::OnPasswordStoreRequestDone( | 275 void PasswordFormManager::OnWebDataServiceRequestDone(WebDataService::Handle h, |
264 int handle, const std::vector<PasswordForm*>& result) { | 276 const WDTypedResult* result) { |
265 DCHECK_EQ(state_, MATCHING_PHASE); | 277 DCHECK_EQ(state_, MATCHING_PHASE); |
266 DCHECK_EQ(pending_login_query_, handle); | 278 DCHECK_EQ(pending_login_query_, h); |
| 279 DCHECK(result); |
| 280 pending_login_query_ = NULL; |
267 | 281 |
268 if (result.empty()) { | 282 if (!result) |
269 state_ = POST_MATCHING_PHASE; | |
270 return; | 283 return; |
| 284 |
| 285 switch (result->GetType()) { |
| 286 case PASSWORD_RESULT: { |
| 287 OnRequestDone(h, result); |
| 288 break; |
| 289 } |
| 290 #if defined(OS_WIN) |
| 291 case PASSWORD_IE7_RESULT: { |
| 292 OnIE7RequestDone(h, result); |
| 293 break; |
| 294 } |
| 295 #endif |
| 296 default: |
| 297 NOTREACHED(); |
271 } | 298 } |
272 | |
273 OnRequestDone(handle, result); | |
274 } | 299 } |
275 | 300 |
276 bool PasswordFormManager::IgnoreResult(const PasswordForm& form) const { | 301 bool PasswordFormManager::IgnoreResult(const PasswordForm& form) const { |
277 // Ignore change password forms until we have some change password | 302 // Ignore change password forms until we have some change password |
278 // functionality | 303 // functionality |
279 if (observed_form_.old_password_element.length() != 0) { | 304 if (observed_form_.old_password_element.length() != 0) { |
280 return true; | 305 return true; |
281 } | 306 } |
282 // Don't match an invalid SSL form with one saved under secure | 307 // Don't match an invalid SSL form with one saved under secure |
283 // circumstances. | 308 // circumstances. |
284 if (form.ssl_valid && !observed_form_.ssl_valid) { | 309 if (form.ssl_valid && !observed_form_.ssl_valid) { |
285 return true; | 310 return true; |
286 } | 311 } |
287 return false; | 312 return false; |
288 } | 313 } |
289 | 314 |
290 void PasswordFormManager::SaveAsNewLogin() { | 315 void PasswordFormManager::SaveAsNewLogin() { |
291 DCHECK_EQ(state_, POST_MATCHING_PHASE); | 316 DCHECK_EQ(state_, POST_MATCHING_PHASE); |
292 DCHECK(IsNewLogin()); | 317 DCHECK(IsNewLogin()); |
293 // The new_form is being used to sign in, so it is preferred. | 318 // The new_form is being used to sign in, so it is preferred. |
294 DCHECK(pending_credentials_.preferred); | 319 DCHECK(pending_credentials_.preferred); |
295 // new_form contains the same basic data as observed_form_ (because its the | 320 // new_form contains the same basic data as observed_form_ (because its the |
296 // same form), but with the newly added credentials. | 321 // same form), but with the newly added credentials. |
297 | 322 |
298 DCHECK(!profile_->IsOffTheRecord()); | 323 DCHECK(!profile_->IsOffTheRecord()); |
299 | 324 |
300 PasswordStore* password_store = | 325 WebDataService* web_data_service = |
301 profile_->GetPasswordStore(Profile::IMPLICIT_ACCESS); | 326 profile_->GetWebDataService(Profile::IMPLICIT_ACCESS); |
302 if (!password_store) { | 327 if (!web_data_service) { |
303 NOTREACHED(); | 328 NOTREACHED(); |
304 return; | 329 return; |
305 } | 330 } |
306 | |
307 pending_credentials_.date_created = Time::Now(); | 331 pending_credentials_.date_created = Time::Now(); |
308 password_store->AddLogin(pending_credentials_); | 332 web_data_service->AddLogin(pending_credentials_); |
309 } | 333 } |
310 | 334 |
311 void PasswordFormManager::UpdateLogin() { | 335 void PasswordFormManager::UpdateLogin() { |
312 DCHECK_EQ(state_, POST_MATCHING_PHASE); | 336 DCHECK_EQ(state_, POST_MATCHING_PHASE); |
313 DCHECK(preferred_match_); | 337 DCHECK(preferred_match_); |
314 // If we're doing an Update, its because we autofilled a form and the user | 338 // If we're doing an Update, its because we autofilled a form and the user |
315 // submitted it with a possibly new password value, page security, or selected | 339 // submitted it with a possibly new password value, page security, or selected |
316 // one of the non-preferred matches, thus requiring a swap of preferred bits. | 340 // one of the non-preferred matches, thus requiring a swap of preferred bits. |
317 DCHECK(!IsNewLogin() && pending_credentials_.preferred); | 341 DCHECK(!IsNewLogin() && pending_credentials_.preferred); |
318 DCHECK(!profile_->IsOffTheRecord()); | 342 DCHECK(!profile_->IsOffTheRecord()); |
319 | 343 |
320 PasswordStore* password_store = | 344 WebDataService* web_data_service = |
321 profile_->GetPasswordStore(Profile::IMPLICIT_ACCESS); | 345 profile_->GetWebDataService(Profile::IMPLICIT_ACCESS); |
322 if (!password_store) { | 346 if (!web_data_service) { |
323 NOTREACHED(); | 347 NOTREACHED(); |
324 return; | 348 return; |
325 } | 349 } |
326 | 350 |
327 // Update all matches to reflect new preferred status. | 351 // Update all matches to reflect new preferred status. |
328 PasswordFormMap::iterator iter; | 352 PasswordFormMap::iterator iter; |
329 for (iter = best_matches_.begin(); iter != best_matches_.end(); iter++) { | 353 for (iter = best_matches_.begin(); iter != best_matches_.end(); iter++) { |
330 if ((iter->second->username_value != pending_credentials_.username_value) && | 354 if ((iter->second->username_value != pending_credentials_.username_value) && |
331 iter->second->preferred) { | 355 iter->second->preferred) { |
332 // This wasn't the selected login but it used to be preferred. | 356 // This wasn't the selected login but it used to be preferred. |
333 iter->second->preferred = false; | 357 iter->second->preferred = false; |
334 password_store->UpdateLogin(*iter->second); | 358 web_data_service->UpdateLogin(*iter->second); |
335 } | 359 } |
336 } | 360 } |
337 // Update the new preferred login. | 361 // Update the new preferred login. |
338 // Note origin.spec().length > signon_realm.length implies the origin has a | 362 // Note origin.spec().length > signon_realm.length implies the origin has a |
339 // path, since signon_realm is a prefix of origin for HTML password forms. | 363 // path, since signon_realm is a prefix of origin for HTML password forms. |
340 if ((observed_form_.scheme == PasswordForm::SCHEME_HTML) && | 364 if ((observed_form_.scheme == PasswordForm::SCHEME_HTML) && |
341 (observed_form_.origin.spec().length() > | 365 (observed_form_.origin.spec().length() > |
342 observed_form_.signon_realm.length()) && | 366 observed_form_.signon_realm.length()) && |
343 (observed_form_.signon_realm == pending_credentials_.origin.spec())) { | 367 (observed_form_.signon_realm == pending_credentials_.origin.spec())) { |
344 // The user logged in successfully with one of our autofilled logins on a | 368 // The user logged in successfully with one of our autofilled logins on a |
345 // page with non-empty path, but the autofilled entry was initially saved/ | 369 // page with non-empty path, but the autofilled entry was initially saved/ |
346 // imported with an empty path. Rather than just mark this entry preferred, | 370 // imported with an empty path. Rather than just mark this entry preferred, |
347 // we create a more specific copy for this exact page and leave the "master" | 371 // we create a more specific copy for this exact page and leave the "master" |
348 // unchanged. This is to prevent the case where that master login is used | 372 // unchanged. This is to prevent the case where that master login is used |
349 // on several sites (e.g site.com/a and site.com/b) but the user actually | 373 // on several sites (e.g site.com/a and site.com/b) but the user actually |
350 // has a different preference on each site. For example, on /a, he wants the | 374 // has a different preference on each site. For example, on /a, he wants the |
351 // general empty-path login so it is flagged as preferred, but on /b he logs | 375 // general empty-path login so it is flagged as preferred, but on /b he logs |
352 // in with a different saved entry - we don't want to remove the preferred | 376 // in with a different saved entry - we don't want to remove the preferred |
353 // status of the former because upon return to /a it won't be the default- | 377 // status of the former because upon return to /a it won't be the default- |
354 // fill match. | 378 // fill match. |
355 // TODO(timsteele): Bug 1188626 - expire the master copies. | 379 // TODO(timsteele): Bug 1188626 - expire the master copies. |
356 PasswordForm copy(pending_credentials_); | 380 PasswordForm copy(pending_credentials_); |
357 copy.origin = observed_form_.origin; | 381 copy.origin = observed_form_.origin; |
358 copy.action = observed_form_.action; | 382 copy.action = observed_form_.action; |
359 password_store->AddLogin(copy); | 383 web_data_service->AddLogin(copy); |
360 } else { | 384 } else { |
361 password_store->UpdateLogin(pending_credentials_); | 385 web_data_service->UpdateLogin(pending_credentials_); |
362 } | 386 } |
363 } | 387 } |
364 | 388 |
365 void PasswordFormManager::CancelLoginsQuery() { | 389 void PasswordFormManager::CancelLoginsQuery() { |
366 PasswordStore* password_store = | 390 if (!pending_login_query_) |
367 profile_->GetPasswordStore(Profile::IMPLICIT_ACCESS); | 391 return; |
368 if (!password_store) { | 392 WebDataService* web_data_service = |
369 // Can be NULL in unit tests. | 393 profile_->GetWebDataService(Profile::EXPLICIT_ACCESS); |
| 394 if (!web_data_service) { |
| 395 NOTREACHED(); |
370 return; | 396 return; |
371 } | 397 } |
372 password_store->CancelLoginsQuery(pending_login_query_); | 398 web_data_service->CancelRequest(pending_login_query_); |
| 399 pending_login_query_ = NULL; |
373 } | 400 } |
374 | 401 |
375 int PasswordFormManager::ScoreResult(const PasswordForm& candidate) const { | 402 int PasswordFormManager::ScoreResult(const PasswordForm& candidate) const { |
376 DCHECK_EQ(state_, MATCHING_PHASE); | 403 DCHECK_EQ(state_, MATCHING_PHASE); |
377 // For scoring of candidate login data: | 404 // For scoring of candidate login data: |
378 // The most important element that should match is the origin, followed by | 405 // The most important element that should match is the origin, followed by |
379 // the action, the password name, the submit button name, and finally the | 406 // the action, the password name, the submit button name, and finally the |
380 // username input field name. | 407 // username input field name. |
381 // Exact origin match gives an addition of 32 (1 << 5) + # of matching url | 408 // Exact origin match gives an addition of 32 (1 << 5) + # of matching url |
382 // dirs. | 409 // dirs. |
(...skipping 30 matching lines...) Expand all Loading... |
413 if (candidate.password_element == observed_form_.password_element) | 440 if (candidate.password_element == observed_form_.password_element) |
414 score += 1 << 2; | 441 score += 1 << 2; |
415 if (candidate.submit_element == observed_form_.submit_element) | 442 if (candidate.submit_element == observed_form_.submit_element) |
416 score += 1 << 1; | 443 score += 1 << 1; |
417 if (candidate.username_element == observed_form_.username_element) | 444 if (candidate.username_element == observed_form_.username_element) |
418 score += 1 << 0; | 445 score += 1 << 0; |
419 } | 446 } |
420 | 447 |
421 return score; | 448 return score; |
422 } | 449 } |
OLD | NEW |