1 // Copyright 2013 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. 4 5 #include "components/autofill/content/renderer/password_autofill_agent.h" 6 7 #include "base/bind.h" 8 #include "base/memory/scoped_ptr.h" 9 #include "base/message_loop/message_loop.h" 10 #include "base/metrics/histogram.h" 11 #include "base/strings/utf_string_conversions.h" 12 #include "components/autofill/content/common/autofill_messages.h" 13 #include "components/autofill/content/renderer/form_autofill_util.h" 14 #include "components/autofill/content/renderer/password_form_conversion_utils.h" 15 #include "components/autofill/core/common/form_field_data.h" 16 #include "components/autofill/core/common/password_autofill_util.h" 17 #include "components/autofill/core/common/password_form.h" 18 #include "components/autofill/core/common/password_form_fill_data.h" 19 #include "content/public/renderer/render_view.h" 20 #include "third_party/WebKit/public/platform/WebVector.h" 21 #include "third_party/WebKit/public/web/WebAutofillClient.h" 22 #include "third_party/WebKit/public/web/WebDocument.h" 23 #include "third_party/WebKit/public/web/WebElement.h" 24 #include "third_party/WebKit/public/web/WebFormElement.h" 25 #include "third_party/WebKit/public/web/WebFrame.h" 26 #include "third_party/WebKit/public/web/WebInputEvent.h" 27 #include "third_party/WebKit/public/web/WebNode.h" 28 #include "third_party/WebKit/public/web/WebNodeList.h" 29 #include "third_party/WebKit/public/web/WebSecurityOrigin.h" 30 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h" 31 #include "third_party/WebKit/public/web/WebView.h" 32 #include "ui/events/keycodes/keyboard_codes.h" 33 34 namespace autofill { 35 namespace { 36 37 // The size above which we stop triggering autocomplete. 38 static const size_t kMaximumTextSizeForAutocomplete = 1000; 39 40 // Maps element names to the actual elements to simplify form filling. 41 typedef std::map<base::string16, blink::WebInputElement> 42 FormInputElementMap; 43 44 // Utility struct for form lookup and autofill. When we parse the DOM to look up 45 // a form, in addition to action and origin URL's we have to compare all 46 // necessary form elements. To avoid having to look these up again when we want 47 // to fill the form, the FindFormElements function stores the pointers 48 // in a FormElements* result, referenced to ensure they are safe to use. 49 struct FormElements { 50 blink::WebFormElement form_element; 51 FormInputElementMap input_elements; 52 }; 53 54 typedef std::vector<FormElements*> FormElementsList; 55 56 // Helper to search the given form element for the specified input elements 57 // in |data|, and add results to |result|. 58 static bool FindFormInputElements(blink::WebFormElement* fe, 59 const FormData& data, 60 FormElements* result) { 61 // Loop through the list of elements we need to find on the form in order to 62 // autofill it. If we don't find any one of them, abort processing this 63 // form; it can't be the right one. 64 for (size_t j = 0; j < data.fields.size(); j++) { 65 blink::WebVector<blink::WebNode> temp_elements; 66 fe->getNamedElements(data.fields[j].name, temp_elements); 67 68 // Match the first input element, if any. 69 // |getNamedElements| may return non-input elements where the names match, 70 // so the results are filtered for input elements. 71 // If more than one match is made, then we have ambiguity (due to misuse 72 // of "name" attribute) so is it considered not found. 73 bool found_input = false; 74 for (size_t i = 0; i < temp_elements.size(); ++i) { 75 if (temp_elements[i].to<blink::WebElement>().hasTagName("input")) { 76 // Check for a non-unique match. 77 if (found_input) { 78 found_input = false; 79 break; 80 } 81 82 // Only fill saved passwords into password fields and usernames into 83 // text fields. 84 blink::WebInputElement input_element = 85 temp_elements[i].to<blink::WebInputElement>(); 86 if (input_element.isPasswordField() != 87 (data.fields[j].form_control_type == "password")) 88 continue; 89 90 // This element matched, add it to our temporary result. It's possible 91 // there are multiple matches, but for purposes of identifying the form 92 // one suffices and if some function needs to deal with multiple 93 // matching elements it can get at them through the FormElement*. 94 // Note: This assignment adds a reference to the InputElement. 95 result->input_elements[data.fields[j].name] = input_element; 96 found_input = true; 97 } 98 } 99 100 // A required element was not found. This is not the right form. 101 // Make sure no input elements from a partially matched form in this 102 // iteration remain in the result set. 103 // Note: clear will remove a reference from each InputElement. 104 if (!found_input) { 105 result->input_elements.clear(); 106 return false; 107 } 108 } 109 return true; 110 } 111 112 // Helper to locate form elements identified by |data|. 113 void FindFormElements(blink::WebView* view, 114 const FormData& data, 115 FormElementsList* results) { 116 DCHECK(view); 117 DCHECK(results); 118 blink::WebFrame* main_frame = view->mainFrame(); 119 if (!main_frame) 120 return; 121 122 GURL::Replacements rep; 123 rep.ClearQuery(); 124 rep.ClearRef(); 125 126 // Loop through each frame. 127 for (blink::WebFrame* f = main_frame; f; f = f->traverseNext(false)) { 128 blink::WebDocument doc = f->document(); 129 if (!doc.isHTMLDocument()) 130 continue; 131 132 GURL full_origin(doc.url()); 133 if (data.origin != full_origin.ReplaceComponents(rep)) 134 continue; 135 136 blink::WebVector<blink::WebFormElement> forms; 137 doc.forms(forms); 138 139 for (size_t i = 0; i < forms.size(); ++i) { 140 blink::WebFormElement fe = forms[i]; 141 142 GURL full_action(f->document().completeURL(fe.action())); 143 if (full_action.is_empty()) { 144 // The default action URL is the form's origin. 145 full_action = full_origin; 146 } 147 148 // Action URL must match. 149 if (data.action != full_action.ReplaceComponents(rep)) 150 continue; 151 152 scoped_ptr<FormElements> curr_elements(new FormElements); 153 if (!FindFormInputElements(&fe, data, curr_elements.get())) 154 continue; 155 156 // We found the right element. 157 // Note: this assignment adds a reference to |fe|. 158 curr_elements->form_element = fe; 159 results->push_back(curr_elements.release()); 160 } 161 } 162 } 163 164 bool IsElementEditable(const blink::WebInputElement& element) { 165 return element.isEnabled() && !element.isReadOnly(); 166 } 167 168 void SetElementAutofilled(blink::WebInputElement* element, bool autofilled) { 169 if (element->isAutofilled() == autofilled) 170 return; 171 element->setAutofilled(autofilled); 172 // Notify any changeEvent listeners. 173 element->dispatchFormControlChangeEvent(); 174 } 175 176 bool DoUsernamesMatch(const base::string16& username1, 177 const base::string16& username2, 178 bool exact_match) { 179 if (exact_match) 180 return username1 == username2; 181 return StartsWith(username1, username2, true); 182 } 183 184 } // namespace 185 186 //////////////////////////////////////////////////////////////////////////////// 187 // PasswordAutofillAgent, public: 188 189 PasswordAutofillAgent::PasswordAutofillAgent(content::RenderView* render_view) 190 : content::RenderViewObserver(render_view), 191 usernames_usage_(NOTHING_TO_AUTOFILL), 192 web_view_(render_view->GetWebView()), 193 weak_ptr_factory_(this) { 194 } 195 196 PasswordAutofillAgent::~PasswordAutofillAgent() { 197 } 198 199 bool PasswordAutofillAgent::TextFieldDidEndEditing( 200 const blink::WebInputElement& element) { 201 LoginToPasswordInfoMap::const_iterator iter = 202 login_to_password_info_.find(element); 203 if (iter == login_to_password_info_.end()) 204 return false; 205 206 const PasswordFormFillData& fill_data = 207 iter->second.fill_data; 208 209 // If wait_for_username is false, we should have filled when the text changed. 210 if (!fill_data.wait_for_username) 211 return false; 212 213 blink::WebInputElement password = iter->second.password_field; 214 if (!IsElementEditable(password)) 215 return false; 216 217 blink::WebInputElement username = element; // We need a non-const. 218 219 // Do not set selection when ending an editing session, otherwise it can 220 // mess with focus. 221 FillUserNameAndPassword(&username, &password, fill_data, 222 true /* exact_username_match */, 223 false /* set_selection */); 224 return true; 225 } 226 227 bool PasswordAutofillAgent::TextDidChangeInTextField( 228 const blink::WebInputElement& element) { 229 LoginToPasswordInfoMap::const_iterator iter = 230 login_to_password_info_.find(element); 231 if (iter == login_to_password_info_.end()) 232 return false; 233 234 // The input text is being changed, so any autofilled password is now 235 // outdated. 236 blink::WebInputElement username = element; // We need a non-const. 237 blink::WebInputElement password = iter->second.password_field; 238 SetElementAutofilled(&username, false); 239 if (password.isAutofilled()) { 240 password.setValue(base::string16()); 241 SetElementAutofilled(&password, false); 242 } 243 244 // If wait_for_username is true we will fill when the username loses focus. 245 if (iter->second.fill_data.wait_for_username) 246 return false; 247 248 if (!IsElementEditable(element) || !element.isText() || 249 (!ShouldIgnoreAutocompleteOffForPasswordFields() && 250 !element.autoComplete())) { 251 return false; 252 } 253 254 // Don't inline autocomplete if the user is deleting, that would be confusing. 255 // But refresh the popup. Note, since this is ours, return true to signal 256 // no further processing is required. 257 if (iter->second.backspace_pressed_last) { 258 ShowSuggestionPopup(iter->second.fill_data, username); 259 return true; 260 } 261 262 blink::WebString name = element.nameForAutofill(); 263 if (name.isEmpty()) 264 return false; // If the field has no name, then we won't have values. 265 266 // Don't attempt to autofill with values that are too large. 267 if (element.value().length() > kMaximumTextSizeForAutocomplete) 268 return false; 269 270 // The caret position should have already been updated. 271 PerformInlineAutocomplete(element, password, iter->second.fill_data); 272 return true; 273 } 274 275 bool PasswordAutofillAgent::TextFieldHandlingKeyDown( 276 const blink::WebInputElement& element, 277 const blink::WebKeyboardEvent& event) { 278 // If using the new Autofill UI that lives in the browser, it will handle 279 // keypresses before this function. This is not currently an issue but if 280 // the keys handled there or here change, this issue may appear. 281 282 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(element); 283 if (iter == login_to_password_info_.end()) 284 return false; 285 286 int win_key_code = event.windowsKeyCode; 287 iter->second.backspace_pressed_last = 288 (win_key_code == ui::VKEY_BACK || win_key_code == ui::VKEY_DELETE); 289 return true; 290 } 291 292 bool PasswordAutofillAgent::DidAcceptAutofillSuggestion( 293 const blink::WebNode& node, 294 const blink::WebString& username) { 295 blink::WebInputElement input; 296 PasswordInfo password; 297 if (!FindLoginInfo(node, &input, &password)) 298 return false; 299 300 // Set the incoming |username| in the text field and |FillUserNameAndPassword| 301 // will do the rest. 302 input.setValue(username, true); 303 return FillUserNameAndPassword(&input, &password.password_field, 304 password.fill_data, 305 true /* exact_username_match */, 306 true /* set_selection */); 307 } 308 309 bool PasswordAutofillAgent::DidClearAutofillSelection( 310 const blink::WebNode& node) { 311 blink::WebInputElement input; 312 PasswordInfo password; 313 return FindLoginInfo(node, &input, &password); 314 } 315 316 bool PasswordAutofillAgent::ShowSuggestions( 317 const blink::WebInputElement& element) { 318 LoginToPasswordInfoMap::const_iterator iter = 319 login_to_password_info_.find(element); 320 if (iter == login_to_password_info_.end()) 321 return false; 322 323 return ShowSuggestionPopup(iter->second.fill_data, element); 324 } 325 326 bool PasswordAutofillAgent::OriginCanAccessPasswordManager( 327 const blink::WebSecurityOrigin& origin) { 328 return origin.canAccessPasswordManager(); 329 } 330 331 void PasswordAutofillAgent::OnDynamicFormsSeen(blink::WebFrame* frame) { 332 SendPasswordForms(frame, false /* only_visible */); 333 } 334 335 void PasswordAutofillAgent::SendPasswordForms(blink::WebFrame* frame, 336 bool only_visible) { 337 // Make sure that this security origin is allowed to use password manager. 338 blink::WebSecurityOrigin origin = frame->document().securityOrigin(); 339 if (!OriginCanAccessPasswordManager(origin)) 340 return; 341 342 // Checks whether the webpage is a redirect page or an empty page. 343 if (IsWebpageEmpty(frame)) 344 return; 345 346 blink::WebVector<blink::WebFormElement> forms; 347 frame->document().forms(forms); 348 349 std::vector<PasswordForm> password_forms; 350 for (size_t i = 0; i < forms.size(); ++i) { 351 const blink::WebFormElement& form = forms[i]; 352 353 // If requested, ignore non-rendered forms, e.g. those styled with 354 // display:none. 355 if (only_visible && !IsWebNodeVisible(form)) 356 continue; 357 358 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form)); 359 if (password_form.get()) 360 password_forms.push_back(*password_form); 361 } 362 363 if (password_forms.empty() && !only_visible) { 364 // We need to send the PasswordFormsRendered message regardless of whether 365 // there are any forms visible, as this is also the code path that triggers 366 // showing the infobar. 367 return; 368 } 369 370 if (only_visible) { 371 Send(new AutofillHostMsg_PasswordFormsRendered(routing_id(), 372 password_forms)); 373 } else { 374 Send(new AutofillHostMsg_PasswordFormsParsed(routing_id(), password_forms)); 375 } 376 } 377 378 bool PasswordAutofillAgent::OnMessageReceived(const IPC::Message& message) { 379 bool handled = true; 380 IPC_BEGIN_MESSAGE_MAP(PasswordAutofillAgent, message) 381 IPC_MESSAGE_HANDLER(AutofillMsg_FillPasswordForm, OnFillPasswordForm) 382 IPC_MESSAGE_UNHANDLED(handled = false) 383 IPC_END_MESSAGE_MAP() 384 return handled; 385 } 386 387 void PasswordAutofillAgent::DidStartLoading() { 388 if (usernames_usage_ != NOTHING_TO_AUTOFILL) { 389 UMA_HISTOGRAM_ENUMERATION("PasswordManager.OtherPossibleUsernamesUsage", 390 usernames_usage_, OTHER_POSSIBLE_USERNAMES_MAX); 391 usernames_usage_ = NOTHING_TO_AUTOFILL; 392 } 393 } 394 395 void PasswordAutofillAgent::DidFinishDocumentLoad(blink::WebFrame* frame) { 396 // The |frame| contents have been parsed, but not yet rendered. Let the 397 // PasswordManager know that forms are loaded, even though we can't yet tell 398 // whether they're visible. 399 SendPasswordForms(frame, false); 400 } 401 402 void PasswordAutofillAgent::DidFinishLoad(blink::WebFrame* frame) { 403 // The |frame| contents have been rendered. Let the PasswordManager know 404 // which of the loaded frames are actually visible to the user. This also 405 // triggers the "Save password?" infobar if the user just submitted a password 406 // form. 407 SendPasswordForms(frame, true); 408 } 409 410 void PasswordAutofillAgent::FrameDetached(blink::WebFrame* frame) { 411 FrameClosing(frame); 412 } 413 414 void PasswordAutofillAgent::FrameWillClose(blink::WebFrame* frame) { 415 FrameClosing(frame); 416 } 417 418 void PasswordAutofillAgent::WillSendSubmitEvent( 419 blink::WebFrame* frame, 420 const blink::WebFormElement& form) { 421 // Some login forms have onSubmit handlers that put a hash of the password 422 // into a hidden field and then clear the password (http://crbug.com/28910). 423 // This method gets called before any of those handlers run, so save away 424 // a copy of the password in case it gets lost. 425 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form)); 426 if (password_form) 427 provisionally_saved_forms_[frame].reset(password_form.release()); 428 } 429 430 void PasswordAutofillAgent::WillSubmitForm(blink::WebFrame* frame, 431 const blink::WebFormElement& form) { 432 scoped_ptr<PasswordForm> submitted_form = CreatePasswordForm(form); 433 434 // If there is a provisionally saved password, copy over the previous 435 // password value so we get the user's typed password, not the value that 436 // may have been transformed for submit. 437 // TODO(gcasto): Do we need to have this action equality check? Is it trying 438 // to prevent accidentally copying over passwords from a different form? 439 if (submitted_form) { 440 if (provisionally_saved_forms_[frame].get() && 441 submitted_form->action == provisionally_saved_forms_[frame]->action) { 442 submitted_form->password_value = 443 provisionally_saved_forms_[frame]->password_value; 444 } 445 446 // Some observers depend on sending this information now instead of when 447 // the frame starts loading. If there are redirects that cause a new 448 // RenderView to be instantiated (such as redirects to the WebStore) 449 // we will never get to finish the load. 450 Send(new AutofillHostMsg_PasswordFormSubmitted(routing_id(), 451 *submitted_form)); 452 // Remove reference since we have already submitted this form. 453 provisionally_saved_forms_.erase(frame); 454 } 455 } 456 457 blink::WebFrame* PasswordAutofillAgent::CurrentOrChildFrameWithSavedForms( 458 const blink::WebFrame* current_frame) { 459 for (FrameToPasswordFormMap::const_iterator it = 460 provisionally_saved_forms_.begin(); 461 it != provisionally_saved_forms_.end(); 462 ++it) { 463 blink::WebFrame* form_frame = it->first; 464 // The check that the returned frame is related to |current_frame| is mainly 465 // for double-checking. There should not be any unrelated frames in 466 // |provisionally_saved_forms_|, because the map is cleared after 467 // navigation. If there are reasons to remove this check in the future and 468 // keep just the first frame found, it might be a good idea to add a UMA 469 // statistic or a similar check on how many frames are here to choose from. 470 if (current_frame == form_frame || 471 current_frame->findChildByName(form_frame->uniqueName())) { 472 return form_frame; 473 } 474 } 475 return NULL; 476 } 477 478 void PasswordAutofillAgent::DidStartProvisionalLoad(blink::WebFrame* frame) { 479 if (!frame->parent()) { 480 // If the navigation is not triggered by a user gesture, e.g. by some ajax 481 // callback, then inherit the submitted password form from the previous 482 // state. This fixes the no password save issue for ajax login, tracked in 483 // [http://crbug/43219]. Note that there are still some sites that this 484 // fails for because they use some element other than a submit button to 485 // trigger submission (which means WillSendSubmitEvent will not be called). 486 blink::WebFrame* form_frame = CurrentOrChildFrameWithSavedForms(frame); 487 if (!blink::WebUserGestureIndicator::isProcessingUserGesture() && 488 provisionally_saved_forms_[form_frame].get()) { 489 Send(new AutofillHostMsg_PasswordFormSubmitted( 490 routing_id(), 491 *provisionally_saved_forms_[form_frame])); 492 provisionally_saved_forms_.erase(form_frame); 493 } 494 // Clear the whole map during main frame navigation. 495 provisionally_saved_forms_.clear(); 496 } 497 } 498 499 void PasswordAutofillAgent::OnFillPasswordForm( 500 const PasswordFormFillData& form_data) { 501 if (usernames_usage_ == NOTHING_TO_AUTOFILL) { 502 if (form_data.other_possible_usernames.size()) 503 usernames_usage_ = OTHER_POSSIBLE_USERNAMES_PRESENT; 504 else if (usernames_usage_ == NOTHING_TO_AUTOFILL) 505 usernames_usage_ = OTHER_POSSIBLE_USERNAMES_ABSENT; 506 } 507 508 FormElementsList forms; 509 // We own the FormElements* in forms. 510 FindFormElements(render_view()->GetWebView(), form_data.basic_data, &forms); 511 FormElementsList::iterator iter; 512 for (iter = forms.begin(); iter != forms.end(); ++iter) { 513 scoped_ptr<FormElements> form_elements(*iter); 514 515 // Attach autocomplete listener to enable selecting alternate logins. 516 // First, get pointers to username element. 517 blink::WebInputElement username_element = 518 form_elements->input_elements[form_data.basic_data.fields[0].name]; 519 520 // Get pointer to password element. (We currently only support single 521 // password forms). 522 blink::WebInputElement password_element = 523 form_elements->input_elements[form_data.basic_data.fields[1].name]; 524 525 // If wait_for_username is true, we don't want to initially fill the form 526 // until the user types in a valid username. 527 if (!form_data.wait_for_username) 528 FillFormOnPasswordRecieved(form_data, username_element, password_element); 529 530 // We might have already filled this form if there are two <form> elements 531 // with identical markup. 532 if (login_to_password_info_.find(username_element) != 533 login_to_password_info_.end()) 534 continue; 535 536 PasswordInfo password_info; 537 password_info.fill_data = form_data; 538 password_info.password_field = password_element; 539 login_to_password_info_[username_element] = password_info; 540 541 FormData form; 542 FormFieldData field; 543 FindFormAndFieldForInputElement( 544 username_element, &form, &field, REQUIRE_NONE); 545 Send(new AutofillHostMsg_AddPasswordFormMapping( 546 routing_id(), 547 field, 548 form_data)); 549 } 550 } 551 552 //////////////////////////////////////////////////////////////////////////////// 553 // PasswordAutofillAgent, private: 554 555 void PasswordAutofillAgent::GetSuggestions( 556 const PasswordFormFillData& fill_data, 557 const base::string16& input, 558 std::vector<base::string16>* suggestions, 559 std::vector<base::string16>* realms) { 560 if (StartsWith(fill_data.basic_data.fields[0].value, input, false)) { 561 suggestions->push_back(fill_data.basic_data.fields[0].value); 562 realms->push_back(UTF8ToUTF16(fill_data.preferred_realm)); 563 } 564 565 for (PasswordFormFillData::LoginCollection::const_iterator iter = 566 fill_data.additional_logins.begin(); 567 iter != fill_data.additional_logins.end(); ++iter) { 568 if (StartsWith(iter->first, input, false)) { 569 suggestions->push_back(iter->first); 570 realms->push_back(UTF8ToUTF16(iter->second.realm)); 571 } 572 } 573 574 for (PasswordFormFillData::UsernamesCollection::const_iterator iter = 575 fill_data.other_possible_usernames.begin(); 576 iter != fill_data.other_possible_usernames.end(); ++iter) { 577 for (size_t i = 0; i < iter->second.size(); ++i) { 578 if (StartsWith(iter->second[i], input, false)) { 579 usernames_usage_ = OTHER_POSSIBLE_USERNAME_SHOWN; 580 suggestions->push_back(iter->second[i]); 581 realms->push_back(UTF8ToUTF16(iter->first.realm)); 582 } 583 } 584 } 585 } 586 587 bool PasswordAutofillAgent::ShowSuggestionPopup( 588 const PasswordFormFillData& fill_data, 589 const blink::WebInputElement& user_input) { 590 blink::WebFrame* frame = user_input.document().frame(); 591 if (!frame) 592 return false; 593 594 blink::WebView* webview = frame->view(); 595 if (!webview) 596 return false; 597 598 std::vector<base::string16> suggestions; 599 std::vector<base::string16> realms; 600 GetSuggestions(fill_data, user_input.value(), &suggestions, &realms); 601 DCHECK_EQ(suggestions.size(), realms.size()); 602 603 FormData form; 604 FormFieldData field; 605 FindFormAndFieldForInputElement( 606 user_input, &form, &field, REQUIRE_NONE); 607 608 blink::WebInputElement selected_element = user_input; 609 gfx::Rect bounding_box(selected_element.boundsInViewportSpace()); 610 611 float scale = web_view_->pageScaleFactor(); 612 gfx::RectF bounding_box_scaled(bounding_box.x() * scale, 613 bounding_box.y() * scale, 614 bounding_box.width() * scale, 615 bounding_box.height() * scale); 616 Send(new AutofillHostMsg_ShowPasswordSuggestions(routing_id(), 617 field, 618 bounding_box_scaled, 619 suggestions, 620 realms)); 621 return !suggestions.empty(); 622 } 623 624 void PasswordAutofillAgent::FillFormOnPasswordRecieved( 625 const PasswordFormFillData& fill_data, 626 blink::WebInputElement username_element, 627 blink::WebInputElement password_element) { 628 // Do not fill if the password field is in an iframe. 629 DCHECK(password_element.document().frame()); 630 if (password_element.document().frame()->parent()) 631 return; 632 633 if (!ShouldIgnoreAutocompleteOffForPasswordFields() && 634 !username_element.form().autoComplete()) 635 return; 636 637 // If we can't modify the password, don't try to set the username 638 if (!IsElementEditable(password_element) || 639 (!ShouldIgnoreAutocompleteOffForPasswordFields() && 640 !password_element.autoComplete())) 641 return; 642 643 // Try to set the username to the preferred name, but only if the field 644 // can be set and isn't prefilled. 645 if (IsElementEditable(username_element) && 646 (ShouldIgnoreAutocompleteOffForPasswordFields() || 647 username_element.autoComplete()) && 648 username_element.value().isEmpty()) { 649 // TODO(tkent): Check maxlength and pattern. 650 username_element.setValue(fill_data.basic_data.fields[0].value); 651 } 652 653 // Fill if we have an exact match for the username. Note that this sets 654 // username to autofilled. 655 FillUserNameAndPassword(&username_element, &password_element, fill_data, 656 true /* exact_username_match */, 657 false /* set_selection */); 658 } 659 660 bool PasswordAutofillAgent::FillUserNameAndPassword( 661 blink::WebInputElement* username_element, 662 blink::WebInputElement* password_element, 663 const PasswordFormFillData& fill_data, 664 bool exact_username_match, 665 bool set_selection) { 666 base::string16 current_username = username_element->value(); 667 // username and password will contain the match found if any. 668 base::string16 username; 669 base::string16 password; 670 671 // Look for any suitable matches to current field text. 672 if (DoUsernamesMatch(fill_data.basic_data.fields[0].value, current_username, 673 exact_username_match)) { 674 username = fill_data.basic_data.fields[0].value; 675 password = fill_data.basic_data.fields[1].value; 676 } else { 677 // Scan additional logins for a match. 678 PasswordFormFillData::LoginCollection::const_iterator iter; 679 for (iter = fill_data.additional_logins.begin(); 680 iter != fill_data.additional_logins.end(); ++iter) { 681 if (DoUsernamesMatch(iter->first, current_username, 682 exact_username_match)) { 683 username = iter->first; 684 password = iter->second.password; 685 break; 686 } 687 } 688 689 // Check possible usernames. 690 if (username.empty() && password.empty()) { 691 for (PasswordFormFillData::UsernamesCollection::const_iterator iter = 692 fill_data.other_possible_usernames.begin(); 693 iter != fill_data.other_possible_usernames.end(); ++iter) { 694 for (size_t i = 0; i < iter->second.size(); ++i) { 695 if (DoUsernamesMatch(iter->second[i], current_username, 696 exact_username_match)) { 697 usernames_usage_ = OTHER_POSSIBLE_USERNAME_SELECTED; 698 username = iter->second[i]; 699 password = iter->first.password; 700 break; 701 } 702 } 703 if (!username.empty() && !password.empty()) 704 break; 705 } 706 } 707 } 708 if (password.empty()) 709 return false; // No match was found. 710 711 // TODO(tkent): Check maxlength and pattern for both username and password 712 // fields. 713 714 // Don't fill username if password can't be set. 715 if (!IsElementEditable(*password_element) || 716 (!ShouldIgnoreAutocompleteOffForPasswordFields() && 717 !password_element->autoComplete())) { 718 return false; 719 } 720 721 // Input matches the username, fill in required values. 722 if (IsElementEditable(*username_element) && 723 (ShouldIgnoreAutocompleteOffForPasswordFields() || 724 username_element->autoComplete())) { 725 username_element->setValue(username); 726 SetElementAutofilled(username_element, true); 727 728 if (set_selection) { 729 username_element->setSelectionRange(current_username.length(), 730 username.length()); 731 } 732 } else if (current_username != username) { 733 // If the username can't be filled and it doesn't match a saved password 734 // as is, don't autofill a password. 735 return false; 736 } 737 738 password_element->setValue(password); 739 SetElementAutofilled(password_element, true); 740 return true; 741 } 742 743 void PasswordAutofillAgent::PerformInlineAutocomplete( 744 const blink::WebInputElement& username_input, 745 const blink::WebInputElement& password_input, 746 const PasswordFormFillData& fill_data) { 747 DCHECK(!fill_data.wait_for_username); 748 749 // We need non-const versions of the username and password inputs. 750 blink::WebInputElement username = username_input; 751 blink::WebInputElement password = password_input; 752 753 // Don't inline autocomplete if the caret is not at the end. 754 // TODO(jcivelli): is there a better way to test the caret location? 755 if (username.selectionStart() != username.selectionEnd() || 756 username.selectionEnd() != static_cast<int>(username.value().length())) { 757 return; 758 } 759 760 // Show the popup with the list of available usernames. 761 ShowSuggestionPopup(fill_data, username); 762 763 764 #if !defined(OS_ANDROID) 765 // Fill the user and password field with the most relevant match. Android 766 // only fills in the fields after the user clicks on the suggestion popup. 767 FillUserNameAndPassword(&username, &password, fill_data, 768 false /* exact_username_match */, 769 true /* set_selection */); 770 #endif 771 } 772 773 void PasswordAutofillAgent::FrameClosing(const blink::WebFrame* frame) { 774 for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin(); 775 iter != login_to_password_info_.end();) { 776 if (iter->first.document().frame() == frame) 777 login_to_password_info_.erase(iter++); 778 else 779 ++iter; 780 } 781 for (FrameToPasswordFormMap::iterator iter = 782 provisionally_saved_forms_.begin(); 783 iter != provisionally_saved_forms_.end();) { 784 if (iter->first == frame) 785 provisionally_saved_forms_.erase(iter++); 786 else 787 ++iter; 788 } 789 } 790 791 bool PasswordAutofillAgent::FindLoginInfo(const blink::WebNode& node, 792 blink::WebInputElement* found_input, 793 PasswordInfo* found_password) { 794 if (!node.isElementNode()) 795 return false; 796 797 blink::WebElement element = node.toConst<blink::WebElement>(); 798 if (!element.hasTagName("input")) 799 return false; 800 801 blink::WebInputElement input = element.to<blink::WebInputElement>(); 802 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(input); 803 if (iter == login_to_password_info_.end()) 804 return false; 805 806 *found_input = input; 807 *found_password = iter->second; 808 return true; 809 } 810 811 } // namespace autofill 812