Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(404)

Side by Side Diff: chrome/browser/password_manager/password_form_manager.cc

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

Powered by Google App Engine
This is Rietveld 408576698