Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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 "components/autofill/content/renderer/password_autofill_agent.h" | 5 #include "components/autofill/content/renderer/password_autofill_agent.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/command_line.h" | 8 #include "base/command_line.h" |
| 9 #include "base/i18n/case_conversion.h" | 9 #include "base/i18n/case_conversion.h" |
| 10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 77 const std::vector<blink::WebFormControlElement>& control_elements, | 77 const std::vector<blink::WebFormControlElement>& control_elements, |
| 78 const base::string16& name) { | 78 const base::string16& name) { |
| 79 for (size_t i = 0; i < control_elements.size(); ++i) { | 79 for (size_t i = 0; i < control_elements.size(); ++i) { |
| 80 if (control_elements[i].nameForAutofill() == name) { | 80 if (control_elements[i].nameForAutofill() == name) { |
| 81 return IsWebNodeVisible(control_elements[i]); | 81 return IsWebNodeVisible(control_elements[i]); |
| 82 } | 82 } |
| 83 } | 83 } |
| 84 return false; | 84 return false; |
| 85 } | 85 } |
| 86 | 86 |
| 87 // Returns true if password form has username and password fields with either | |
| 88 // same or no name and id attributes supplied. | |
| 89 bool PasswordFormWithAmbiguousOrNoNameAndIdAttribute( | |
| 90 const PasswordFormFillData& fill_data) { | |
| 91 // TODO(pritam.nikam): Extend below logic once patch lands for storing the | |
| 92 // password forms having name or id attributes missing from the fields. | |
| 93 // http://crbug.com/497630 | |
|
dvadym
2015/09/07 15:26:00
Please rebase on the top of save patch and impleme
Pritam Nikam
2015/09/08 15:56:19
Done.
| |
| 94 return fill_data.username_field.name == fill_data.password_field.name; | |
| 95 } | |
| 96 | |
| 97 bool IsPasswordField(const FormFieldData& field) { | |
| 98 return (field.form_control_type == "password"); | |
| 99 } | |
| 100 | |
| 101 // Returns the |field|'s autofillable name. If no name or id attribute is | |
| 102 // specified returns a dummy name. | |
| 103 base::string16 FieldName(const FormFieldData& field, | |
| 104 bool ambiguous_or_no_name_and_id_attribute) { | |
| 105 return ambiguous_or_no_name_and_id_attribute | |
|
dvadym
2015/09/07 15:26:00
Is the case of no-username field considered here?
Pritam Nikam
2015/09/08 15:56:19
For the case of no-username field, |ambiguous_or_n
dvadym
2015/09/11 14:15:34
Acknowledged
| |
| 106 ? IsPasswordField(field) ? base::ASCIIToUTF16("anonymous_password") | |
| 107 : base::ASCIIToUTF16("anonymous_username") | |
| 108 : field.name; | |
| 109 } | |
| 110 | |
| 87 // Utility function to find the unique entry of |control_elements| for the | 111 // Utility function to find the unique entry of |control_elements| for the |
| 88 // specified input |field|. On successful find, adds it to |result| and returns | 112 // specified input |field|. On successful find, adds it to |result| and returns |
| 89 // |true|. Otherwise clears the references from each |HTMLInputElement| from | 113 // |true|. Otherwise clears the references from each |HTMLInputElement| from |
| 90 // |result| and returns |false|. | 114 // |result| and returns |false|. |
| 91 bool FindFormInputElement( | 115 bool FindFormInputElement( |
| 92 const std::vector<blink::WebFormControlElement>& control_elements, | 116 const std::vector<blink::WebFormControlElement>& control_elements, |
| 93 const FormFieldData& field, | 117 const FormFieldData& field, |
| 118 bool ambiguous_or_no_name_and_id_attribute, | |
| 94 FormInputElementMap* result) { | 119 FormInputElementMap* result) { |
| 95 // Match the first input element, if any. | 120 // Match the first input element, if any. |
| 96 // If more than one match is made, then we have ambiguity (due to misuse | |
| 97 // of "name" attribute) so is it considered not found. | |
| 98 bool found_input = false; | 121 bool found_input = false; |
| 122 base::string16 field_name = | |
| 123 FieldName(field, ambiguous_or_no_name_and_id_attribute); | |
| 99 for (size_t i = 0; i < control_elements.size(); ++i) { | 124 for (size_t i = 0; i < control_elements.size(); ++i) { |
| 100 if (control_elements[i].nameForAutofill() != field.name) | 125 DCHECK(control_elements[i].hasHTMLTagName("input")); |
| 101 continue; | |
| 102 | 126 |
| 103 if (!control_elements[i].hasHTMLTagName("input")) | 127 // Only fill saved passwords into password fields and usernames into text |
| 128 // fields. | |
| 129 const blink::WebInputElement input_element = | |
| 130 control_elements[i].toConst<blink::WebInputElement>(); | |
| 131 if (input_element.isPasswordField() != IsPasswordField(field)) | |
| 104 continue; | 132 continue; |
| 105 | 133 |
| 106 // Check for a non-unique match. | 134 // Check for a non-unique match. |
| 107 if (found_input) { | 135 if (found_input) { |
|
dvadym
2015/09/07 15:26:00
Could you please allow case when there are more th
Pritam Nikam
2015/09/08 15:56:19
Done.
| |
| 108 found_input = false; | 136 found_input = false; |
| 109 break; | 137 break; |
| 110 } | 138 } |
| 111 | 139 |
| 112 // Only fill saved passwords into password fields and usernames into | 140 (*result)[field_name] = input_element; |
| 113 // text fields. | |
| 114 const blink::WebInputElement input_element = | |
| 115 control_elements[i].toConst<blink::WebInputElement>(); | |
| 116 if (input_element.isPasswordField() != | |
| 117 (field.form_control_type == "password")) | |
| 118 continue; | |
| 119 | |
| 120 (*result)[field.name] = input_element; | |
| 121 found_input = true; | 141 found_input = true; |
| 122 } | 142 } |
| 123 | 143 |
| 124 // A required element was not found. This is not the right form. | 144 // A required element was not found. This is not the right form. |
| 125 // Make sure no input elements from a partially matched form in this | 145 // Make sure no input elements from a partially matched form in this |
| 126 // iteration remain in the result set. | 146 // iteration remain in the result set. |
| 127 // Note: clear will remove a reference from each InputElement. | 147 // Note: clear will remove a reference from each InputElement. |
| 128 if (!found_input) { | 148 if (!found_input) { |
| 129 result->clear(); | 149 result->clear(); |
| 130 return false; | 150 return false; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 172 | 192 |
| 173 return group_name != | 193 return group_name != |
| 174 kFillOnAccountSelectFieldTrialEnabledWithNoHighlightGroup; | 194 kFillOnAccountSelectFieldTrialEnabledWithNoHighlightGroup; |
| 175 } | 195 } |
| 176 | 196 |
| 177 // Helper to search through |control_elements| for the specified input elements | 197 // Helper to search through |control_elements| for the specified input elements |
| 178 // in |data|, and add results to |result|. | 198 // in |data|, and add results to |result|. |
| 179 bool FindFormInputElements( | 199 bool FindFormInputElements( |
| 180 const std::vector<blink::WebFormControlElement>& control_elements, | 200 const std::vector<blink::WebFormControlElement>& control_elements, |
| 181 const PasswordFormFillData& data, | 201 const PasswordFormFillData& data, |
| 202 bool ambiguous_or_no_name_and_id_attribute, | |
| 182 FormInputElementMap* result) { | 203 FormInputElementMap* result) { |
| 183 return FindFormInputElement(control_elements, data.password_field, result) && | 204 return FindFormInputElement(control_elements, data.password_field, |
| 184 (!FillDataContainsFillableUsername(data) || | 205 ambiguous_or_no_name_and_id_attribute, result) && |
| 185 FindFormInputElement(control_elements, data.username_field, result)); | 206 (!(ambiguous_or_no_name_and_id_attribute || |
| 207 FillDataContainsFillableUsername(data)) || | |
| 208 FindFormInputElement(control_elements, data.username_field, | |
| 209 ambiguous_or_no_name_and_id_attribute, result)); | |
| 186 } | 210 } |
| 187 | 211 |
| 188 // Helper to locate form elements identified by |data|. | 212 // Helper to locate form elements identified by |data|. |
| 189 void FindFormElements(content::RenderFrame* render_frame, | 213 void FindFormElements(content::RenderFrame* render_frame, |
| 190 const PasswordFormFillData& data, | 214 const PasswordFormFillData& data, |
| 215 bool ambiguous_or_no_name_and_id_attribute, | |
| 191 FormElementsList* results) { | 216 FormElementsList* results) { |
| 192 DCHECK(results); | 217 DCHECK(results); |
| 193 | 218 |
| 194 blink::WebDocument doc = render_frame->GetWebFrame()->document(); | 219 blink::WebDocument doc = render_frame->GetWebFrame()->document(); |
| 195 if (!doc.isHTMLDocument()) | 220 if (!doc.isHTMLDocument()) |
| 196 return; | 221 return; |
| 197 | 222 |
| 198 if (data.origin != GetCanonicalOriginForDocument(doc)) | 223 if (data.origin != GetCanonicalOriginForDocument(doc)) |
| 199 return; | 224 return; |
| 200 | 225 |
| 201 blink::WebVector<blink::WebFormElement> forms; | 226 blink::WebVector<blink::WebFormElement> forms; |
| 202 doc.forms(forms); | 227 doc.forms(forms); |
| 203 | 228 |
| 204 for (size_t i = 0; i < forms.size(); ++i) { | 229 for (size_t i = 0; i < forms.size(); ++i) { |
| 205 blink::WebFormElement fe = forms[i]; | 230 blink::WebFormElement fe = forms[i]; |
| 206 | 231 |
| 207 // Action URL must match. | 232 // Action URL must match. |
| 208 if (data.action != GetCanonicalActionForForm(fe)) | 233 if (data.action != GetCanonicalActionForForm(fe)) |
| 209 continue; | 234 continue; |
| 210 | 235 |
| 211 std::vector<blink::WebFormControlElement> control_elements = | 236 std::vector<blink::WebFormControlElement> control_elements = |
| 212 ExtractAutofillableElementsInForm(fe); | 237 ExtractAutofillableElementsInForm(fe); |
| 213 FormInputElementMap cur_map; | 238 FormInputElementMap cur_map; |
| 214 if (FindFormInputElements(control_elements, data, &cur_map)) | 239 if (FindFormInputElements(control_elements, data, |
| 240 ambiguous_or_no_name_and_id_attribute, &cur_map)) | |
| 215 results->push_back(cur_map); | 241 results->push_back(cur_map); |
| 216 } | 242 } |
| 217 // If the element to be filled are not in a <form> element, the "action" and | 243 // If the element to be filled are not in a <form> element, the "action" and |
| 218 // origin should be the same. | 244 // origin should be the same. |
| 219 if (data.action != data.origin) | 245 if (data.action != data.origin) |
| 220 return; | 246 return; |
| 221 | 247 |
| 222 std::vector<blink::WebFormControlElement> control_elements = | 248 std::vector<blink::WebFormControlElement> control_elements = |
| 223 GetUnownedAutofillableFormFieldElements(doc.all(), nullptr); | 249 GetUnownedAutofillableFormFieldElements(doc.all(), nullptr); |
| 224 FormInputElementMap unowned_elements_map; | 250 FormInputElementMap unowned_elements_map; |
| 225 if (FindFormInputElements(control_elements, data, &unowned_elements_map)) | 251 if (FindFormInputElements(control_elements, data, |
| 252 ambiguous_or_no_name_and_id_attribute, | |
| 253 &unowned_elements_map)) | |
| 226 results->push_back(unowned_elements_map); | 254 results->push_back(unowned_elements_map); |
| 227 } | 255 } |
| 228 | 256 |
| 229 bool IsElementEditable(const blink::WebInputElement& element) { | 257 bool IsElementEditable(const blink::WebInputElement& element) { |
| 230 return element.isEnabled() && !element.isReadOnly(); | 258 return element.isEnabled() && !element.isReadOnly(); |
| 231 } | 259 } |
| 232 | 260 |
| 233 bool DoUsernamesMatch(const base::string16& username1, | 261 bool DoUsernamesMatch(const base::string16& username1, |
| 234 const base::string16& username2, | 262 const base::string16& username2, |
| 235 bool exact_match) { | 263 bool exact_match) { |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 444 while (cur_frame->parent()) { | 472 while (cur_frame->parent()) { |
| 445 cur_frame = cur_frame->parent(); | 473 cur_frame = cur_frame->parent(); |
| 446 if (!bottom_frame_origin.equals(cur_frame->securityOrigin().toString())) | 474 if (!bottom_frame_origin.equals(cur_frame->securityOrigin().toString())) |
| 447 return false; | 475 return false; |
| 448 } | 476 } |
| 449 | 477 |
| 450 // If we can't modify the password, don't try to set the username | 478 // If we can't modify the password, don't try to set the username |
| 451 if (!IsElementAutocompletable(password_element)) | 479 if (!IsElementAutocompletable(password_element)) |
| 452 return false; | 480 return false; |
| 453 | 481 |
| 454 bool form_contains_fillable_username_field = | 482 base::string16 username_field_name = |
| 455 FillDataContainsFillableUsername(fill_data); | 483 FieldName(fill_data.username_field, |
| 484 PasswordFormWithAmbiguousOrNoNameAndIdAttribute(fill_data)); | |
| 456 // If the form contains an autocompletable username field, try to set the | 485 // If the form contains an autocompletable username field, try to set the |
| 457 // username to the preferred name, but only if: | 486 // username to the preferred name, but only if: |
| 458 // (a) The fill-on-account-select flag is not set, and | 487 // (a) The fill-on-account-select flag is not set, and |
| 459 // (b) The username element isn't prefilled | 488 // (b) The username element isn't prefilled |
| 460 // | 489 // |
| 461 // If (a) is false, then just mark the username element as autofilled if the | 490 // If (a) is false, then just mark the username element as autofilled if the |
| 462 // user is not in the "no highlighting" group and return so the fill step is | 491 // user is not in the "no highlighting" group and return so the fill step is |
| 463 // skipped. | 492 // skipped. |
| 464 // | 493 // |
| 465 // If there is no autocompletable username field, and (a) is false, then the | 494 // If there is no autocompletable username field, and (a) is false, then the |
| 466 // username element cannot be autofilled, but the user should still be able to | 495 // username element cannot be autofilled, but the user should still be able to |
| 467 // select to fill the password element, so the password element must be marked | 496 // select to fill the password element, so the password element must be marked |
| 468 // as autofilled and the fill step should also be skipped if the user is not | 497 // as autofilled and the fill step should also be skipped if the user is not |
| 469 // in the "no highlighting" group. | 498 // in the "no highlighting" group. |
| 470 // | 499 // |
| 471 // In all other cases, do nothing. | 500 // In all other cases, do nothing. |
| 472 bool form_has_fillable_username = form_contains_fillable_username_field && | 501 bool form_has_fillable_username = !username_field_name.empty() && |
| 473 IsElementAutocompletable(username_element); | 502 IsElementAutocompletable(username_element); |
| 474 | 503 |
| 475 if (ShouldFillOnAccountSelect()) { | 504 if (ShouldFillOnAccountSelect()) { |
| 476 if (!ShouldHighlightFields()) { | 505 if (!ShouldHighlightFields()) { |
| 477 return false; | 506 return false; |
| 478 } | 507 } |
| 479 | 508 |
| 480 if (form_has_fillable_username) { | 509 if (form_has_fillable_username) { |
| 481 username_element.setAutofilled(true); | 510 username_element.setAutofilled(true); |
| 482 } else if (username_element.isNull() || | 511 } else if (username_element.isNull() || |
| (...skipping 713 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1196 } | 1225 } |
| 1197 | 1226 |
| 1198 // This is a new navigation, so require a new user gesture before filling in | 1227 // This is a new navigation, so require a new user gesture before filling in |
| 1199 // passwords. | 1228 // passwords. |
| 1200 gatekeeper_.Reset(); | 1229 gatekeeper_.Reset(); |
| 1201 } | 1230 } |
| 1202 | 1231 |
| 1203 void PasswordAutofillAgent::OnFillPasswordForm( | 1232 void PasswordAutofillAgent::OnFillPasswordForm( |
| 1204 int key, | 1233 int key, |
| 1205 const PasswordFormFillData& form_data) { | 1234 const PasswordFormFillData& form_data) { |
| 1206 | 1235 bool ambiguous_or_no_name_and_id_attribute = |
| 1236 PasswordFormWithAmbiguousOrNoNameAndIdAttribute(form_data); | |
| 1207 FormElementsList forms; | 1237 FormElementsList forms; |
| 1208 FindFormElements(render_frame(), form_data, &forms); | 1238 FindFormElements(render_frame(), form_data, |
| 1239 ambiguous_or_no_name_and_id_attribute, &forms); | |
| 1209 FormElementsList::iterator iter; | 1240 FormElementsList::iterator iter; |
| 1210 for (iter = forms.begin(); iter != forms.end(); ++iter) { | 1241 for (iter = forms.begin(); iter != forms.end(); ++iter) { |
| 1211 // Attach autocomplete listener to enable selecting alternate logins. | 1242 // Attach autocomplete listener to enable selecting alternate logins. |
| 1212 blink::WebInputElement username_element, password_element; | 1243 blink::WebInputElement username_element, password_element; |
| 1213 | 1244 |
| 1245 base::string16 username_field_name = FieldName( | |
| 1246 form_data.username_field, ambiguous_or_no_name_and_id_attribute); | |
| 1247 base::string16 password_field_name = FieldName( | |
| 1248 form_data.password_field, ambiguous_or_no_name_and_id_attribute); | |
| 1249 | |
| 1214 // Check whether the password form has a username input field. | 1250 // Check whether the password form has a username input field. |
| 1215 bool form_contains_fillable_username_field = | 1251 if (!username_field_name.empty()) { |
| 1216 FillDataContainsFillableUsername(form_data); | 1252 username_element = (*iter)[username_field_name]; |
| 1217 if (form_contains_fillable_username_field) { | |
| 1218 username_element = | |
| 1219 (*iter)[form_data.username_field.name]; | |
| 1220 } | 1253 } |
| 1221 | 1254 |
| 1222 // No password field, bail out. | 1255 // No password field, bail out. |
| 1223 if (form_data.password_field.name.empty()) | 1256 if (password_field_name.empty()) |
| 1224 break; | 1257 break; |
| 1225 | 1258 |
| 1226 // We might have already filled this form if there are two <form> elements | 1259 // We might have already filled this form if there are two <form> elements |
| 1227 // with identical markup. | 1260 // with identical markup. |
| 1228 if (login_to_password_info_.find(username_element) != | 1261 if (login_to_password_info_.find(username_element) != |
| 1229 login_to_password_info_.end()) | 1262 login_to_password_info_.end()) |
| 1230 continue; | 1263 continue; |
| 1231 | 1264 |
| 1232 // Get pointer to password element. (We currently only support single | 1265 // Get pointer to password element. (We currently only support single |
| 1233 // password forms). | 1266 // password forms). |
| 1234 password_element = (*iter)[form_data.password_field.name]; | 1267 password_element = (*iter)[password_field_name]; |
| 1235 | 1268 |
| 1236 // If wait_for_username is true, we don't want to initially fill the form | 1269 // If wait_for_username is true, we don't want to initially fill the form |
| 1237 // until the user types in a valid username. | 1270 // until the user types in a valid username. |
| 1238 if (!form_data.wait_for_username) { | 1271 if (!form_data.wait_for_username) { |
| 1239 FillFormOnPasswordReceived( | 1272 FillFormOnPasswordReceived( |
| 1240 form_data, | 1273 form_data, |
| 1241 username_element, | 1274 username_element, |
| 1242 password_element, | 1275 password_element, |
| 1243 &nonscript_modified_values_, | 1276 &nonscript_modified_values_, |
| 1244 base::Bind(&PasswordValueGatekeeper::RegisterElement, | 1277 base::Bind(&PasswordValueGatekeeper::RegisterElement, |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1439 void PasswordAutofillAgent::LegacyPasswordAutofillAgent::DidStopLoading() { | 1472 void PasswordAutofillAgent::LegacyPasswordAutofillAgent::DidStopLoading() { |
| 1440 agent_->DidStopLoading(); | 1473 agent_->DidStopLoading(); |
| 1441 } | 1474 } |
| 1442 | 1475 |
| 1443 void PasswordAutofillAgent::LegacyPasswordAutofillAgent:: | 1476 void PasswordAutofillAgent::LegacyPasswordAutofillAgent:: |
| 1444 DidStartProvisionalLoad(blink::WebLocalFrame* navigated_frame) { | 1477 DidStartProvisionalLoad(blink::WebLocalFrame* navigated_frame) { |
| 1445 agent_->LegacyDidStartProvisionalLoad(navigated_frame); | 1478 agent_->LegacyDidStartProvisionalLoad(navigated_frame); |
| 1446 } | 1479 } |
| 1447 | 1480 |
| 1448 } // namespace autofill | 1481 } // namespace autofill |
| OLD | NEW |