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/content/renderer/renderer_save_password_progress_logger.h" 16 #include "components/autofill/core/common/form_field_data.h" 17 #include "components/autofill/core/common/password_autofill_util.h" 18 #include "components/autofill/core/common/password_form.h" 19 #include "components/autofill/core/common/password_form_fill_data.h" 20 #include "content/public/renderer/document_state.h" 21 #include "content/public/renderer/navigation_state.h" 22 #include "content/public/renderer/render_view.h" 23 #include "third_party/WebKit/public/platform/WebVector.h" 24 #include "third_party/WebKit/public/web/WebAutofillClient.h" 25 #include "third_party/WebKit/public/web/WebDocument.h" 26 #include "third_party/WebKit/public/web/WebElement.h" 27 #include "third_party/WebKit/public/web/WebFormElement.h" 28 #include "third_party/WebKit/public/web/WebInputEvent.h" 29 #include "third_party/WebKit/public/web/WebLocalFrame.h" 30 #include "third_party/WebKit/public/web/WebNode.h" 31 #include "third_party/WebKit/public/web/WebNodeList.h" 32 #include "third_party/WebKit/public/web/WebSecurityOrigin.h" 33 #include "third_party/WebKit/public/web/WebUserGestureIndicator.h" 34 #include "third_party/WebKit/public/web/WebView.h" 35 #include "ui/base/page_transition_types.h" 36 #include "ui/events/keycodes/keyboard_codes.h" 37 #include "url/gurl.h" 38 39 namespace autofill { 40 namespace { 41 42 // The size above which we stop triggering autocomplete. 43 static const size_t kMaximumTextSizeForAutocomplete = 1000; 44 45 // Maps element names to the actual elements to simplify form filling. 46 typedef std::map<base::string16, blink::WebInputElement> FormInputElementMap; 47 48 // Use the shorter name when referencing SavePasswordProgressLogger::StringID 49 // values to spare line breaks. The code provides enough context for that 50 // already. 51 typedef SavePasswordProgressLogger Logger; 52 53 // Utility struct for form lookup and autofill. When we parse the DOM to look up 54 // a form, in addition to action and origin URL's we have to compare all 55 // necessary form elements. To avoid having to look these up again when we want 56 // to fill the form, the FindFormElements function stores the pointers 57 // in a FormElements* result, referenced to ensure they are safe to use. 58 struct FormElements { 59 blink::WebFormElement form_element; 60 FormInputElementMap input_elements; 61 }; 62 63 typedef std::vector<FormElements*> FormElementsList; 64 65 // Helper to search the given form element for the specified input elements 66 // in |data|, and add results to |result|. 67 static bool FindFormInputElements(blink::WebFormElement* fe, 68 const FormData& data, 69 FormElements* result) { 70 const bool username_is_present = !data.fields[0].name.empty(); 71 72 // Loop through the list of elements we need to find on the form in order to 73 // autofill it. If we don't find any one of them, abort processing this 74 // form; it can't be the right one. 75 // First field is the username, skip it if not present. 76 for (size_t j = (username_is_present ? 0 : 1); j < data.fields.size(); ++j) { 77 blink::WebVector<blink::WebNode> temp_elements; 78 fe->getNamedElements(data.fields[j].name, temp_elements); 79 80 // Match the first input element, if any. 81 // |getNamedElements| may return non-input elements where the names match, 82 // so the results are filtered for input elements. 83 // If more than one match is made, then we have ambiguity (due to misuse 84 // of "name" attribute) so is it considered not found. 85 bool found_input = false; 86 for (size_t i = 0; i < temp_elements.size(); ++i) { 87 if (temp_elements[i].to<blink::WebElement>().hasHTMLTagName("input")) { 88 // Check for a non-unique match. 89 if (found_input) { 90 found_input = false; 91 break; 92 } 93 94 // Only fill saved passwords into password fields and usernames into 95 // text fields. 96 blink::WebInputElement input_element = 97 temp_elements[i].to<blink::WebInputElement>(); 98 if (input_element.isPasswordField() != 99 (data.fields[j].form_control_type == "password")) 100 continue; 101 102 // This element matched, add it to our temporary result. It's possible 103 // there are multiple matches, but for purposes of identifying the form 104 // one suffices and if some function needs to deal with multiple 105 // matching elements it can get at them through the FormElement*. 106 // Note: This assignment adds a reference to the InputElement. 107 result->input_elements[data.fields[j].name] = input_element; 108 found_input = true; 109 } 110 } 111 112 // A required element was not found. This is not the right form. 113 // Make sure no input elements from a partially matched form in this 114 // iteration remain in the result set. 115 // Note: clear will remove a reference from each InputElement. 116 if (!found_input) { 117 result->input_elements.clear(); 118 return false; 119 } 120 } 121 return true; 122 } 123 124 // Helper to locate form elements identified by |data|. 125 void FindFormElements(blink::WebView* view, 126 const FormData& data, 127 FormElementsList* results) { 128 DCHECK(view); 129 DCHECK(results); 130 blink::WebFrame* main_frame = view->mainFrame(); 131 if (!main_frame) 132 return; 133 134 GURL::Replacements rep; 135 rep.ClearQuery(); 136 rep.ClearRef(); 137 138 // Loop through each frame. 139 for (blink::WebFrame* f = main_frame; f; f = f->traverseNext(false)) { 140 blink::WebDocument doc = f->document(); 141 if (!doc.isHTMLDocument()) 142 continue; 143 144 GURL full_origin(doc.url()); 145 if (data.origin != full_origin.ReplaceComponents(rep)) 146 continue; 147 148 blink::WebVector<blink::WebFormElement> forms; 149 doc.forms(forms); 150 151 for (size_t i = 0; i < forms.size(); ++i) { 152 blink::WebFormElement fe = forms[i]; 153 154 GURL full_action(f->document().completeURL(fe.action())); 155 if (full_action.is_empty()) { 156 // The default action URL is the form's origin. 157 full_action = full_origin; 158 } 159 160 // Action URL must match. 161 if (data.action != full_action.ReplaceComponents(rep)) 162 continue; 163 164 scoped_ptr<FormElements> curr_elements(new FormElements); 165 if (!FindFormInputElements(&fe, data, curr_elements.get())) 166 continue; 167 168 // We found the right element. 169 // Note: this assignment adds a reference to |fe|. 170 curr_elements->form_element = fe; 171 results->push_back(curr_elements.release()); 172 } 173 } 174 } 175 176 bool IsElementEditable(const blink::WebInputElement& element) { 177 return element.isEnabled() && !element.isReadOnly(); 178 } 179 180 bool DoUsernamesMatch(const base::string16& username1, 181 const base::string16& username2, 182 bool exact_match) { 183 if (exact_match) 184 return username1 == username2; 185 return StartsWith(username1, username2, true); 186 } 187 188 // Returns |true| if the given element is both editable and has permission to be 189 // autocompleted. The latter can be either because there is no 190 // autocomplete='off' set for the element, or because the flag is set to ignore 191 // autocomplete='off'. Otherwise, returns |false|. 192 bool IsElementAutocompletable(const blink::WebInputElement& element) { 193 return IsElementEditable(element) && 194 (ShouldIgnoreAutocompleteOffForPasswordFields() || 195 element.autoComplete()); 196 } 197 198 // Returns true if the password specified in |form| is a default value. 199 bool PasswordValueIsDefault(const PasswordForm& form, 200 blink::WebFormElement form_element) { 201 blink::WebVector<blink::WebNode> temp_elements; 202 form_element.getNamedElements(form.password_element, temp_elements); 203 204 // We are loose in our definition here and will return true if any of the 205 // appropriately named elements match the element to be saved. Currently 206 // we ignore filling passwords where naming is ambigious anyway. 207 for (size_t i = 0; i < temp_elements.size(); ++i) { 208 if (temp_elements[i].to<blink::WebElement>().getAttribute("value") == 209 form.password_value) 210 return true; 211 } 212 return false; 213 } 214 215 // Log a message including the name, method and action of |form|. 216 void LogHTMLForm(SavePasswordProgressLogger* logger, 217 SavePasswordProgressLogger::StringID message_id, 218 const blink::WebFormElement& form) { 219 logger->LogHTMLForm(message_id, 220 form.name().utf8(), 221 GURL(form.action().utf8())); 222 } 223 224 bool FillDataContainsUsername(const PasswordFormFillData& fill_data) { 225 return !fill_data.basic_data.fields[0].name.empty(); 226 } 227 228 } // namespace 229 230 //////////////////////////////////////////////////////////////////////////////// 231 // PasswordAutofillAgent, public: 232 233 PasswordAutofillAgent::PasswordAutofillAgent(content::RenderView* render_view) 234 : content::RenderViewObserver(render_view), 235 usernames_usage_(NOTHING_TO_AUTOFILL), 236 web_view_(render_view->GetWebView()), 237 logging_state_active_(false), 238 was_username_autofilled_(false), 239 was_password_autofilled_(false), 240 username_selection_start_(0), 241 did_stop_loading_(false), 242 weak_ptr_factory_(this) { 243 Send(new AutofillHostMsg_PasswordAutofillAgentConstructed(routing_id())); 244 } 245 246 PasswordAutofillAgent::~PasswordAutofillAgent() { 247 } 248 249 PasswordAutofillAgent::PasswordValueGatekeeper::PasswordValueGatekeeper() 250 : was_user_gesture_seen_(false) { 251 } 252 253 PasswordAutofillAgent::PasswordValueGatekeeper::~PasswordValueGatekeeper() { 254 } 255 256 void PasswordAutofillAgent::PasswordValueGatekeeper::RegisterElement( 257 blink::WebInputElement* element) { 258 if (was_user_gesture_seen_) 259 ShowValue(element); 260 else 261 elements_.push_back(*element); 262 } 263 264 void PasswordAutofillAgent::PasswordValueGatekeeper::OnUserGesture() { 265 was_user_gesture_seen_ = true; 266 267 for (std::vector<blink::WebInputElement>::iterator it = elements_.begin(); 268 it != elements_.end(); 269 ++it) { 270 ShowValue(&(*it)); 271 } 272 273 elements_.clear(); 274 } 275 276 void PasswordAutofillAgent::PasswordValueGatekeeper::Reset() { 277 was_user_gesture_seen_ = false; 278 elements_.clear(); 279 } 280 281 void PasswordAutofillAgent::PasswordValueGatekeeper::ShowValue( 282 blink::WebInputElement* element) { 283 if (!element->isNull() && !element->suggestedValue().isEmpty()) 284 element->setValue(element->suggestedValue(), true); 285 } 286 287 bool PasswordAutofillAgent::TextFieldDidEndEditing( 288 const blink::WebInputElement& element) { 289 LoginToPasswordInfoMap::const_iterator iter = 290 login_to_password_info_.find(element); 291 if (iter == login_to_password_info_.end()) 292 return false; 293 294 const PasswordInfo& password_info = iter->second; 295 // Don't let autofill overwrite an explicit change made by the user. 296 if (password_info.password_was_edited_last) 297 return false; 298 299 const PasswordFormFillData& fill_data = password_info.fill_data; 300 301 // If wait_for_username is false, we should have filled when the text changed. 302 if (!fill_data.wait_for_username) 303 return false; 304 305 blink::WebInputElement password = password_info.password_field; 306 if (!IsElementEditable(password)) 307 return false; 308 309 blink::WebInputElement username = element; // We need a non-const. 310 311 // Do not set selection when ending an editing session, otherwise it can 312 // mess with focus. 313 FillUserNameAndPassword(&username, 314 &password, 315 fill_data, 316 true /* exact_username_match */, 317 false /* set_selection */); 318 return true; 319 } 320 321 bool PasswordAutofillAgent::TextDidChangeInTextField( 322 const blink::WebInputElement& element) { 323 // TODO(vabr): Get a mutable argument instead. http://crbug.com/397083 324 blink::WebInputElement mutable_element = element; // We need a non-const. 325 326 if (element.isPasswordField()) { 327 // Some login forms have event handlers that put a hash of the password into 328 // a hidden field and then clear the password (http://crbug.com/28910, 329 // http://crbug.com/391693). This method gets called before any of those 330 // handlers run, so save away a copy of the password in case it gets lost. 331 // To honor the user having explicitly cleared the password, even an empty 332 // password will be saved here. 333 ProvisionallySavePassword( 334 element.document().frame(), element.form(), RESTRICTION_NONE); 335 336 PasswordToLoginMap::iterator iter = password_to_username_.find(element); 337 if (iter != password_to_username_.end()) { 338 login_to_password_info_[iter->second].password_was_edited_last = true; 339 // Note that the suggested value of |mutable_element| was reset when its 340 // value changed. 341 mutable_element.setAutofilled(false); 342 } 343 return false; 344 } 345 346 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(element); 347 if (iter == login_to_password_info_.end()) 348 return false; 349 350 // The input text is being changed, so any autofilled password is now 351 // outdated. 352 mutable_element.setAutofilled(false); 353 iter->second.password_was_edited_last = false; 354 355 blink::WebInputElement password = iter->second.password_field; 356 if (password.isAutofilled()) { 357 password.setValue(base::string16(), true); 358 password.setAutofilled(false); 359 } 360 361 // If wait_for_username is true we will fill when the username loses focus. 362 if (iter->second.fill_data.wait_for_username) 363 return false; 364 365 if (!element.isText() || !IsElementAutocompletable(element) || 366 !IsElementAutocompletable(password)) { 367 return false; 368 } 369 370 // Don't inline autocomplete if the user is deleting, that would be confusing. 371 // But refresh the popup. Note, since this is ours, return true to signal 372 // no further processing is required. 373 if (iter->second.backspace_pressed_last) { 374 ShowSuggestionPopup(iter->second.fill_data, element, false); 375 return true; 376 } 377 378 blink::WebString name = element.nameForAutofill(); 379 if (name.isEmpty()) 380 return false; // If the field has no name, then we won't have values. 381 382 // Don't attempt to autofill with values that are too large. 383 if (element.value().length() > kMaximumTextSizeForAutocomplete) 384 return false; 385 386 // The caret position should have already been updated. 387 PerformInlineAutocomplete(element, password, iter->second.fill_data); 388 return true; 389 } 390 391 bool PasswordAutofillAgent::TextFieldHandlingKeyDown( 392 const blink::WebInputElement& element, 393 const blink::WebKeyboardEvent& event) { 394 // If using the new Autofill UI that lives in the browser, it will handle 395 // keypresses before this function. This is not currently an issue but if 396 // the keys handled there or here change, this issue may appear. 397 398 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(element); 399 if (iter == login_to_password_info_.end()) 400 return false; 401 402 int win_key_code = event.windowsKeyCode; 403 iter->second.backspace_pressed_last = 404 (win_key_code == ui::VKEY_BACK || win_key_code == ui::VKEY_DELETE); 405 return true; 406 } 407 408 bool PasswordAutofillAgent::FillSuggestion( 409 const blink::WebNode& node, 410 const blink::WebString& username, 411 const blink::WebString& password) { 412 blink::WebInputElement username_element; 413 PasswordInfo* password_info; 414 415 if (!FindLoginInfo(node, &username_element, &password_info) || 416 !IsElementAutocompletable(username_element) || 417 !IsElementAutocompletable(password_info->password_field)) { 418 return false; 419 } 420 421 password_info->password_was_edited_last = false; 422 username_element.setValue(username, true); 423 username_element.setAutofilled(true); 424 username_element.setSelectionRange(username.length(), username.length()); 425 426 password_info->password_field.setValue(password, true); 427 password_info->password_field.setAutofilled(true); 428 429 return true; 430 } 431 432 bool PasswordAutofillAgent::PreviewSuggestion( 433 const blink::WebNode& node, 434 const blink::WebString& username, 435 const blink::WebString& password) { 436 blink::WebInputElement username_element; 437 PasswordInfo* password_info; 438 439 if (!FindLoginInfo(node, &username_element, &password_info) || 440 !IsElementAutocompletable(username_element) || 441 !IsElementAutocompletable(password_info->password_field)) { 442 return false; 443 } 444 445 was_username_autofilled_ = username_element.isAutofilled(); 446 username_selection_start_ = username_element.selectionStart(); 447 username_element.setSuggestedValue(username); 448 username_element.setAutofilled(true); 449 username_element.setSelectionRange( 450 username_selection_start_, 451 username_element.suggestedValue().length()); 452 453 was_password_autofilled_ = password_info->password_field.isAutofilled(); 454 password_info->password_field.setSuggestedValue(password); 455 password_info->password_field.setAutofilled(true); 456 457 return true; 458 } 459 460 bool PasswordAutofillAgent::DidClearAutofillSelection( 461 const blink::WebNode& node) { 462 blink::WebInputElement username_element; 463 PasswordInfo* password_info; 464 if (!FindLoginInfo(node, &username_element, &password_info)) 465 return false; 466 467 ClearPreview(&username_element, &password_info->password_field); 468 return true; 469 } 470 471 bool PasswordAutofillAgent::ShowSuggestions( 472 const blink::WebInputElement& element, 473 bool show_all) { 474 LoginToPasswordInfoMap::const_iterator iter = 475 login_to_password_info_.find(element); 476 if (iter == login_to_password_info_.end()) 477 return false; 478 479 // If autocomplete='off' is set on the form elements, no suggestion dialog 480 // should be shown. However, return |true| to indicate that this is a known 481 // password form and that the request to show suggestions has been handled (as 482 // a no-op). 483 if (!IsElementAutocompletable(element) || 484 !IsElementAutocompletable(iter->second.password_field)) 485 return true; 486 487 return ShowSuggestionPopup(iter->second.fill_data, element, show_all); 488 } 489 490 bool PasswordAutofillAgent::OriginCanAccessPasswordManager( 491 const blink::WebSecurityOrigin& origin) { 492 return origin.canAccessPasswordManager(); 493 } 494 495 void PasswordAutofillAgent::OnDynamicFormsSeen(blink::WebFrame* frame) { 496 SendPasswordForms(frame, false /* only_visible */); 497 } 498 499 void PasswordAutofillAgent::FirstUserGestureObserved() { 500 gatekeeper_.OnUserGesture(); 501 } 502 503 void PasswordAutofillAgent::SendPasswordForms(blink::WebFrame* frame, 504 bool only_visible) { 505 scoped_ptr<RendererSavePasswordProgressLogger> logger; 506 if (logging_state_active_) { 507 logger.reset(new RendererSavePasswordProgressLogger(this, routing_id())); 508 logger->LogMessage(Logger::STRING_SEND_PASSWORD_FORMS_METHOD); 509 logger->LogBoolean(Logger::STRING_ONLY_VISIBLE, only_visible); 510 } 511 512 // Make sure that this security origin is allowed to use password manager. 513 blink::WebSecurityOrigin origin = frame->document().securityOrigin(); 514 if (logger) { 515 logger->LogURL(Logger::STRING_SECURITY_ORIGIN, 516 GURL(origin.toString().utf8())); 517 } 518 if (!OriginCanAccessPasswordManager(origin)) { 519 if (logger) { 520 logger->LogMessage(Logger::STRING_SECURITY_ORIGIN_FAILURE); 521 logger->LogMessage(Logger::STRING_DECISION_DROP); 522 } 523 return; 524 } 525 526 // Checks whether the webpage is a redirect page or an empty page. 527 if (IsWebpageEmpty(frame)) { 528 if (logger) { 529 logger->LogMessage(Logger::STRING_WEBPAGE_EMPTY); 530 logger->LogMessage(Logger::STRING_DECISION_DROP); 531 } 532 return; 533 } 534 535 blink::WebVector<blink::WebFormElement> forms; 536 frame->document().forms(forms); 537 if (logger) 538 logger->LogNumber(Logger::STRING_NUMBER_OF_ALL_FORMS, forms.size()); 539 540 std::vector<PasswordForm> password_forms; 541 for (size_t i = 0; i < forms.size(); ++i) { 542 const blink::WebFormElement& form = forms[i]; 543 bool is_form_visible = IsWebNodeVisible(form); 544 if (logger) { 545 LogHTMLForm(logger.get(), Logger::STRING_FORM_FOUND_ON_PAGE, form); 546 logger->LogBoolean(Logger::STRING_FORM_IS_VISIBLE, is_form_visible); 547 } 548 549 // If requested, ignore non-rendered forms, e.g. those styled with 550 // display:none. 551 if (only_visible && !is_form_visible) 552 continue; 553 554 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form)); 555 if (password_form.get()) { 556 if (logger) { 557 logger->LogPasswordForm(Logger::STRING_FORM_IS_PASSWORD, 558 *password_form); 559 } 560 password_forms.push_back(*password_form); 561 } 562 } 563 564 if (password_forms.empty() && !only_visible) { 565 // We need to send the PasswordFormsRendered message regardless of whether 566 // there are any forms visible, as this is also the code path that triggers 567 // showing the infobar. 568 return; 569 } 570 571 if (only_visible) { 572 Send(new AutofillHostMsg_PasswordFormsRendered(routing_id(), 573 password_forms, 574 did_stop_loading_)); 575 } else { 576 Send(new AutofillHostMsg_PasswordFormsParsed(routing_id(), password_forms)); 577 } 578 } 579 580 bool PasswordAutofillAgent::OnMessageReceived(const IPC::Message& message) { 581 bool handled = true; 582 IPC_BEGIN_MESSAGE_MAP(PasswordAutofillAgent, message) 583 IPC_MESSAGE_HANDLER(AutofillMsg_FillPasswordForm, OnFillPasswordForm) 584 IPC_MESSAGE_HANDLER(AutofillMsg_SetLoggingState, OnSetLoggingState) 585 IPC_MESSAGE_UNHANDLED(handled = false) 586 IPC_END_MESSAGE_MAP() 587 return handled; 588 } 589 590 void PasswordAutofillAgent::DidStartLoading() { 591 did_stop_loading_ = false; 592 if (usernames_usage_ != NOTHING_TO_AUTOFILL) { 593 UMA_HISTOGRAM_ENUMERATION("PasswordManager.OtherPossibleUsernamesUsage", 594 usernames_usage_, 595 OTHER_POSSIBLE_USERNAMES_MAX); 596 usernames_usage_ = NOTHING_TO_AUTOFILL; 597 } 598 } 599 600 void PasswordAutofillAgent::DidFinishDocumentLoad(blink::WebLocalFrame* frame) { 601 // The |frame| contents have been parsed, but not yet rendered. Let the 602 // PasswordManager know that forms are loaded, even though we can't yet tell 603 // whether they're visible. 604 SendPasswordForms(frame, false); 605 } 606 607 void PasswordAutofillAgent::DidFinishLoad(blink::WebLocalFrame* frame) { 608 // The |frame| contents have been rendered. Let the PasswordManager know 609 // which of the loaded frames are actually visible to the user. This also 610 // triggers the "Save password?" infobar if the user just submitted a password 611 // form. 612 SendPasswordForms(frame, true); 613 } 614 615 void PasswordAutofillAgent::DidStopLoading() { 616 did_stop_loading_ = true; 617 } 618 619 void PasswordAutofillAgent::FrameDetached(blink::WebFrame* frame) { 620 FrameClosing(frame); 621 } 622 623 void PasswordAutofillAgent::FrameWillClose(blink::WebFrame* frame) { 624 FrameClosing(frame); 625 } 626 627 void PasswordAutofillAgent::WillSendSubmitEvent( 628 blink::WebLocalFrame* frame, 629 const blink::WebFormElement& form) { 630 // Forms submitted via XHR are not seen by WillSubmitForm if the default 631 // onsubmit handler is overridden. Such submission first gets detected in 632 // DidStartProvisionalLoad, which no longer knows about the particular form, 633 // and uses the candidate stored in |provisionally_saved_forms_|. 634 // 635 // User-typed password will get stored to |provisionally_saved_forms_| in 636 // TextDidChangeInTextField. Autofilled or JavaScript-copied passwords need to 637 // be saved here. 638 // 639 // Only non-empty passwords are saved here. Empty passwords were likely 640 // cleared by some scripts (http://crbug.com/28910, http://crbug.com/391693). 641 // Had the user cleared the password, |provisionally_saved_forms_| would 642 // already have been updated in TextDidChangeInTextField. 643 ProvisionallySavePassword(frame, form, RESTRICTION_NON_EMPTY_PASSWORD); 644 } 645 646 void PasswordAutofillAgent::WillSubmitForm(blink::WebLocalFrame* frame, 647 const blink::WebFormElement& form) { 648 scoped_ptr<RendererSavePasswordProgressLogger> logger; 649 if (logging_state_active_) { 650 logger.reset(new RendererSavePasswordProgressLogger(this, routing_id())); 651 logger->LogMessage(Logger::STRING_WILL_SUBMIT_FORM_METHOD); 652 LogHTMLForm(logger.get(), Logger::STRING_HTML_FORM_FOR_SUBMIT, form); 653 } 654 655 scoped_ptr<PasswordForm> submitted_form = CreatePasswordForm(form); 656 657 // If there is a provisionally saved password, copy over the previous 658 // password value so we get the user's typed password, not the value that 659 // may have been transformed for submit. 660 // TODO(gcasto): Do we need to have this action equality check? Is it trying 661 // to prevent accidentally copying over passwords from a different form? 662 if (submitted_form) { 663 if (logger) { 664 logger->LogPasswordForm(Logger::STRING_CREATED_PASSWORD_FORM, 665 *submitted_form); 666 } 667 if (provisionally_saved_forms_[frame].get() && 668 submitted_form->action == provisionally_saved_forms_[frame]->action) { 669 if (logger) 670 logger->LogMessage(Logger::STRING_SUBMITTED_PASSWORD_REPLACED); 671 submitted_form->password_value = 672 provisionally_saved_forms_[frame]->password_value; 673 submitted_form->new_password_value = 674 provisionally_saved_forms_[frame]->new_password_value; 675 } 676 677 // Some observers depend on sending this information now instead of when 678 // the frame starts loading. If there are redirects that cause a new 679 // RenderView to be instantiated (such as redirects to the WebStore) 680 // we will never get to finish the load. 681 Send(new AutofillHostMsg_PasswordFormSubmitted(routing_id(), 682 *submitted_form)); 683 // Remove reference since we have already submitted this form. 684 provisionally_saved_forms_.erase(frame); 685 } else if (logger) { 686 logger->LogMessage(Logger::STRING_DECISION_DROP); 687 } 688 } 689 690 blink::WebFrame* PasswordAutofillAgent::CurrentOrChildFrameWithSavedForms( 691 const blink::WebFrame* current_frame) { 692 for (FrameToPasswordFormMap::const_iterator it = 693 provisionally_saved_forms_.begin(); 694 it != provisionally_saved_forms_.end(); 695 ++it) { 696 blink::WebFrame* form_frame = it->first; 697 // The check that the returned frame is related to |current_frame| is mainly 698 // for double-checking. There should not be any unrelated frames in 699 // |provisionally_saved_forms_|, because the map is cleared after 700 // navigation. If there are reasons to remove this check in the future and 701 // keep just the first frame found, it might be a good idea to add a UMA 702 // statistic or a similar check on how many frames are here to choose from. 703 if (current_frame == form_frame || 704 current_frame->findChildByName(form_frame->assignedName())) { 705 return form_frame; 706 } 707 } 708 return NULL; 709 } 710 711 void PasswordAutofillAgent::DidStartProvisionalLoad( 712 blink::WebLocalFrame* frame) { 713 scoped_ptr<RendererSavePasswordProgressLogger> logger; 714 if (logging_state_active_) { 715 logger.reset(new RendererSavePasswordProgressLogger(this, routing_id())); 716 logger->LogMessage(Logger::STRING_DID_START_PROVISIONAL_LOAD_METHOD); 717 } 718 719 if (!frame->parent()) { 720 // If the navigation is not triggered by a user gesture, e.g. by some ajax 721 // callback, then inherit the submitted password form from the previous 722 // state. This fixes the no password save issue for ajax login, tracked in 723 // [http://crbug/43219]. Note that this still fails for sites that use 724 // synchonous XHR as isProcessingUserGesture() will return true. 725 blink::WebFrame* form_frame = CurrentOrChildFrameWithSavedForms(frame); 726 if (logger) { 727 logger->LogBoolean(Logger::STRING_FORM_FRAME_EQ_FRAME, 728 form_frame == frame); 729 } 730 // Bug fix for crbug.com/368690. isProcessingUserGesture() is false when 731 // the user is performing actions outside the page (e.g. typed url, 732 // history navigation). We don't want to trigger saving in these cases. 733 content::DocumentState* document_state = 734 content::DocumentState::FromDataSource( 735 frame->provisionalDataSource()); 736 content::NavigationState* navigation_state = 737 document_state->navigation_state(); 738 if (ui::PageTransitionIsWebTriggerable( 739 navigation_state->transition_type()) && 740 !blink::WebUserGestureIndicator::isProcessingUserGesture()) { 741 // If onsubmit has been called, try and save that form. 742 if (provisionally_saved_forms_[form_frame].get()) { 743 if (logger) { 744 logger->LogPasswordForm( 745 Logger::STRING_PROVISIONALLY_SAVED_FORM_FOR_FRAME, 746 *provisionally_saved_forms_[form_frame]); 747 } 748 Send(new AutofillHostMsg_PasswordFormSubmitted( 749 routing_id(), *provisionally_saved_forms_[form_frame])); 750 provisionally_saved_forms_.erase(form_frame); 751 } else { 752 // Loop through the forms on the page looking for one that has been 753 // filled out. If one exists, try and save the credentials. 754 blink::WebVector<blink::WebFormElement> forms; 755 frame->document().forms(forms); 756 757 bool password_forms_found = false; 758 for (size_t i = 0; i < forms.size(); ++i) { 759 blink::WebFormElement form_element = forms[i]; 760 if (logger) { 761 LogHTMLForm( 762 logger.get(), Logger::STRING_FORM_FOUND_ON_PAGE, form_element); 763 } 764 scoped_ptr<PasswordForm> password_form( 765 CreatePasswordForm(form_element)); 766 if (password_form.get() && !password_form->username_value.empty() && 767 !password_form->password_value.empty() && 768 !PasswordValueIsDefault(*password_form, form_element)) { 769 password_forms_found = true; 770 if (logger) { 771 logger->LogPasswordForm( 772 Logger::STRING_PASSWORD_FORM_FOUND_ON_PAGE, *password_form); 773 } 774 Send(new AutofillHostMsg_PasswordFormSubmitted(routing_id(), 775 *password_form)); 776 } 777 } 778 if (!password_forms_found && logger) { 779 logger->LogMessage(Logger::STRING_DECISION_DROP); 780 } 781 } 782 } 783 // Clear the whole map during main frame navigation. 784 provisionally_saved_forms_.clear(); 785 786 // This is a new navigation, so require a new user gesture before filling in 787 // passwords. 788 gatekeeper_.Reset(); 789 } else { 790 if (logger) 791 logger->LogMessage(Logger::STRING_DECISION_DROP); 792 } 793 } 794 795 void PasswordAutofillAgent::OnFillPasswordForm( 796 const PasswordFormFillData& form_data) { 797 if (usernames_usage_ == NOTHING_TO_AUTOFILL) { 798 if (form_data.other_possible_usernames.size()) 799 usernames_usage_ = OTHER_POSSIBLE_USERNAMES_PRESENT; 800 else if (usernames_usage_ == NOTHING_TO_AUTOFILL) 801 usernames_usage_ = OTHER_POSSIBLE_USERNAMES_ABSENT; 802 } 803 804 FormElementsList forms; 805 // We own the FormElements* in forms. 806 FindFormElements(render_view()->GetWebView(), form_data.basic_data, &forms); 807 FormElementsList::iterator iter; 808 for (iter = forms.begin(); iter != forms.end(); ++iter) { 809 scoped_ptr<FormElements> form_elements(*iter); 810 811 // Attach autocomplete listener to enable selecting alternate logins. 812 blink::WebInputElement username_element, password_element; 813 814 // Check whether the password form has a username input field. 815 bool form_contains_username_field = FillDataContainsUsername(form_data); 816 if (form_contains_username_field) { 817 username_element = 818 form_elements->input_elements[form_data.basic_data.fields[0].name]; 819 } 820 821 // No password field, bail out. 822 if (form_data.basic_data.fields[1].name.empty()) 823 break; 824 825 // Get pointer to password element. (We currently only support single 826 // password forms). 827 password_element = 828 form_elements->input_elements[form_data.basic_data.fields[1].name]; 829 830 // If wait_for_username is true, we don't want to initially fill the form 831 // until the user types in a valid username. 832 if (!form_data.wait_for_username) 833 FillFormOnPasswordRecieved(form_data, username_element, password_element); 834 835 // We might have already filled this form if there are two <form> elements 836 // with identical markup. 837 if (login_to_password_info_.find(username_element) != 838 login_to_password_info_.end()) 839 continue; 840 841 PasswordInfo password_info; 842 password_info.fill_data = form_data; 843 password_info.password_field = password_element; 844 login_to_password_info_[username_element] = password_info; 845 password_to_username_[password_element] = username_element; 846 847 FormData form; 848 FormFieldData field; 849 if (form_contains_username_field) { 850 FindFormAndFieldForFormControlElement( 851 username_element, &form, &field, REQUIRE_NONE); 852 } 853 854 Send(new AutofillHostMsg_AddPasswordFormMapping( 855 routing_id(), field, form_data)); 856 } 857 } 858 859 void PasswordAutofillAgent::OnSetLoggingState(bool active) { 860 logging_state_active_ = active; 861 } 862 863 //////////////////////////////////////////////////////////////////////////////// 864 // PasswordAutofillAgent, private: 865 866 PasswordAutofillAgent::PasswordInfo::PasswordInfo() 867 : backspace_pressed_last(false), password_was_edited_last(false) { 868 } 869 870 void PasswordAutofillAgent::GetSuggestions( 871 const PasswordFormFillData& fill_data, 872 const base::string16& input, 873 std::vector<base::string16>* suggestions, 874 std::vector<base::string16>* realms, 875 bool show_all) { 876 if (show_all || 877 StartsWith(fill_data.basic_data.fields[0].value, input, false)) { 878 suggestions->push_back(fill_data.basic_data.fields[0].value); 879 realms->push_back(base::UTF8ToUTF16(fill_data.preferred_realm)); 880 } 881 882 for (PasswordFormFillData::LoginCollection::const_iterator iter = 883 fill_data.additional_logins.begin(); 884 iter != fill_data.additional_logins.end(); 885 ++iter) { 886 if (show_all || StartsWith(iter->first, input, false)) { 887 suggestions->push_back(iter->first); 888 realms->push_back(base::UTF8ToUTF16(iter->second.realm)); 889 } 890 } 891 892 for (PasswordFormFillData::UsernamesCollection::const_iterator iter = 893 fill_data.other_possible_usernames.begin(); 894 iter != fill_data.other_possible_usernames.end(); 895 ++iter) { 896 for (size_t i = 0; i < iter->second.size(); ++i) { 897 if (show_all || StartsWith(iter->second[i], input, false)) { 898 usernames_usage_ = OTHER_POSSIBLE_USERNAME_SHOWN; 899 suggestions->push_back(iter->second[i]); 900 realms->push_back(base::UTF8ToUTF16(iter->first.realm)); 901 } 902 } 903 } 904 } 905 906 bool PasswordAutofillAgent::ShowSuggestionPopup( 907 const PasswordFormFillData& fill_data, 908 const blink::WebInputElement& user_input, 909 bool show_all) { 910 blink::WebFrame* frame = user_input.document().frame(); 911 if (!frame) 912 return false; 913 914 blink::WebView* webview = frame->view(); 915 if (!webview) 916 return false; 917 918 std::vector<base::string16> suggestions; 919 std::vector<base::string16> realms; 920 GetSuggestions( 921 fill_data, user_input.value(), &suggestions, &realms, show_all); 922 DCHECK_EQ(suggestions.size(), realms.size()); 923 924 FormData form; 925 FormFieldData field; 926 FindFormAndFieldForFormControlElement( 927 user_input, &form, &field, REQUIRE_NONE); 928 929 blink::WebInputElement selected_element = user_input; 930 gfx::Rect bounding_box(selected_element.boundsInViewportSpace()); 931 932 float scale = web_view_->pageScaleFactor(); 933 gfx::RectF bounding_box_scaled(bounding_box.x() * scale, 934 bounding_box.y() * scale, 935 bounding_box.width() * scale, 936 bounding_box.height() * scale); 937 Send(new AutofillHostMsg_ShowPasswordSuggestions( 938 routing_id(), field, bounding_box_scaled, suggestions, realms)); 939 return !suggestions.empty(); 940 } 941 942 void PasswordAutofillAgent::FillFormOnPasswordRecieved( 943 const PasswordFormFillData& fill_data, 944 blink::WebInputElement username_element, 945 blink::WebInputElement password_element) { 946 // Do not fill if the password field is in an iframe. 947 DCHECK(password_element.document().frame()); 948 if (password_element.document().frame()->parent()) 949 return; 950 951 bool form_contains_username_field = FillDataContainsUsername(fill_data); 952 if (!ShouldIgnoreAutocompleteOffForPasswordFields() && 953 form_contains_username_field && !username_element.form().autoComplete()) 954 return; 955 956 // If we can't modify the password, don't try to set the username 957 if (!IsElementAutocompletable(password_element)) 958 return; 959 960 // Try to set the username to the preferred name, but only if the field 961 // can be set and isn't prefilled. 962 if (form_contains_username_field && 963 IsElementAutocompletable(username_element) && 964 username_element.value().isEmpty()) { 965 // TODO(tkent): Check maxlength and pattern. 966 username_element.setValue(fill_data.basic_data.fields[0].value, true); 967 } 968 969 // Fill if we have an exact match for the username. Note that this sets 970 // username to autofilled. 971 FillUserNameAndPassword(&username_element, 972 &password_element, 973 fill_data, 974 true /* exact_username_match */, 975 false /* set_selection */); 976 } 977 978 bool PasswordAutofillAgent::FillUserNameAndPassword( 979 blink::WebInputElement* username_element, 980 blink::WebInputElement* password_element, 981 const PasswordFormFillData& fill_data, 982 bool exact_username_match, 983 bool set_selection) { 984 // Don't fill username if password can't be set. 985 if (!IsElementAutocompletable(*password_element)) 986 return false; 987 988 base::string16 current_username; 989 if (!username_element->isNull()) { 990 current_username = username_element->value(); 991 } 992 993 // username and password will contain the match found if any. 994 base::string16 username; 995 base::string16 password; 996 997 // Look for any suitable matches to current field text. 998 if (DoUsernamesMatch(fill_data.basic_data.fields[0].value, 999 current_username, 1000 exact_username_match)) { 1001 username = fill_data.basic_data.fields[0].value; 1002 password = fill_data.basic_data.fields[1].value; 1003 } else { 1004 // Scan additional logins for a match. 1005 PasswordFormFillData::LoginCollection::const_iterator iter; 1006 for (iter = fill_data.additional_logins.begin(); 1007 iter != fill_data.additional_logins.end(); 1008 ++iter) { 1009 if (DoUsernamesMatch( 1010 iter->first, current_username, exact_username_match)) { 1011 username = iter->first; 1012 password = iter->second.password; 1013 break; 1014 } 1015 } 1016 1017 // Check possible usernames. 1018 if (username.empty() && password.empty()) { 1019 for (PasswordFormFillData::UsernamesCollection::const_iterator iter = 1020 fill_data.other_possible_usernames.begin(); 1021 iter != fill_data.other_possible_usernames.end(); 1022 ++iter) { 1023 for (size_t i = 0; i < iter->second.size(); ++i) { 1024 if (DoUsernamesMatch( 1025 iter->second[i], current_username, exact_username_match)) { 1026 usernames_usage_ = OTHER_POSSIBLE_USERNAME_SELECTED; 1027 username = iter->second[i]; 1028 password = iter->first.password; 1029 break; 1030 } 1031 } 1032 if (!username.empty() && !password.empty()) 1033 break; 1034 } 1035 } 1036 } 1037 if (password.empty()) 1038 return false; // No match was found. 1039 1040 // TODO(tkent): Check maxlength and pattern for both username and password 1041 // fields. 1042 1043 // Input matches the username, fill in required values. 1044 if (!username_element->isNull() && 1045 IsElementAutocompletable(*username_element)) { 1046 username_element->setValue(username, true); 1047 username_element->setAutofilled(true); 1048 1049 if (set_selection) { 1050 username_element->setSelectionRange(current_username.length(), 1051 username.length()); 1052 } 1053 } else if (current_username != username) { 1054 // If the username can't be filled and it doesn't match a saved password 1055 // as is, don't autofill a password. 1056 return false; 1057 } 1058 1059 // Wait to fill in the password until a user gesture occurs. This is to make 1060 // sure that we do not fill in the DOM with a password until we believe the 1061 // user is intentionally interacting with the page. 1062 password_element->setSuggestedValue(password); 1063 gatekeeper_.RegisterElement(password_element); 1064 1065 password_element->setAutofilled(true); 1066 return true; 1067 } 1068 1069 void PasswordAutofillAgent::PerformInlineAutocomplete( 1070 const blink::WebInputElement& username_input, 1071 const blink::WebInputElement& password_input, 1072 const PasswordFormFillData& fill_data) { 1073 DCHECK(!fill_data.wait_for_username); 1074 1075 // We need non-const versions of the username and password inputs. 1076 blink::WebInputElement username = username_input; 1077 blink::WebInputElement password = password_input; 1078 1079 // Don't inline autocomplete if the caret is not at the end. 1080 // TODO(jcivelli): is there a better way to test the caret location? 1081 if (username.selectionStart() != username.selectionEnd() || 1082 username.selectionEnd() != static_cast<int>(username.value().length())) { 1083 return; 1084 } 1085 1086 // Show the popup with the list of available usernames. 1087 ShowSuggestionPopup(fill_data, username, false); 1088 1089 #if !defined(OS_ANDROID) 1090 // Fill the user and password field with the most relevant match. Android 1091 // only fills in the fields after the user clicks on the suggestion popup. 1092 FillUserNameAndPassword(&username, 1093 &password, 1094 fill_data, 1095 false /* exact_username_match */, 1096 true /* set_selection */); 1097 #endif 1098 } 1099 1100 void PasswordAutofillAgent::FrameClosing(const blink::WebFrame* frame) { 1101 for (LoginToPasswordInfoMap::iterator iter = login_to_password_info_.begin(); 1102 iter != login_to_password_info_.end();) { 1103 // There may not be a username field, so get the frame from the password 1104 // field. 1105 if (iter->second.password_field.document().frame() == frame) { 1106 password_to_username_.erase(iter->second.password_field); 1107 login_to_password_info_.erase(iter++); 1108 } else { 1109 ++iter; 1110 } 1111 } 1112 for (FrameToPasswordFormMap::iterator iter = 1113 provisionally_saved_forms_.begin(); 1114 iter != provisionally_saved_forms_.end();) { 1115 if (iter->first == frame) 1116 provisionally_saved_forms_.erase(iter++); 1117 else 1118 ++iter; 1119 } 1120 } 1121 1122 bool PasswordAutofillAgent::FindLoginInfo(const blink::WebNode& node, 1123 blink::WebInputElement* found_input, 1124 PasswordInfo** found_password) { 1125 if (!node.isElementNode()) 1126 return false; 1127 1128 blink::WebElement element = node.toConst<blink::WebElement>(); 1129 if (!element.hasHTMLTagName("input")) 1130 return false; 1131 1132 blink::WebInputElement input = element.to<blink::WebInputElement>(); 1133 LoginToPasswordInfoMap::iterator iter = login_to_password_info_.find(input); 1134 if (iter == login_to_password_info_.end()) 1135 return false; 1136 1137 *found_input = input; 1138 *found_password = &iter->second; 1139 return true; 1140 } 1141 1142 void PasswordAutofillAgent::ClearPreview( 1143 blink::WebInputElement* username, 1144 blink::WebInputElement* password) { 1145 if (!username->suggestedValue().isEmpty()) { 1146 username->setSuggestedValue(blink::WebString()); 1147 username->setAutofilled(was_username_autofilled_); 1148 username->setSelectionRange(username_selection_start_, 1149 username->value().length()); 1150 } 1151 if (!password->suggestedValue().isEmpty()) { 1152 password->setSuggestedValue(blink::WebString()); 1153 password->setAutofilled(was_password_autofilled_); 1154 } 1155 } 1156 1157 void PasswordAutofillAgent::ProvisionallySavePassword( 1158 blink::WebLocalFrame* frame, 1159 const blink::WebFormElement& form, 1160 ProvisionallySaveRestriction restriction) { 1161 DCHECK(frame); 1162 scoped_ptr<PasswordForm> password_form(CreatePasswordForm(form)); 1163 if (!password_form || (restriction == RESTRICTION_NON_EMPTY_PASSWORD && 1164 password_form->password_value.empty() && 1165 password_form->new_password_value.empty())) { 1166 return; 1167 } 1168 provisionally_saved_forms_[frame].reset(password_form.release()); 1169 } 1170 1171 } // namespace autofill 1172