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

Unified Diff: components/autofill/content/renderer/password_form_conversion_utils.cc

Issue 225823006: Rewrite functions from WebPasswordFormData and WebPasswordFormUtils in (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Update code as per review comments Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/autofill/content/renderer/password_form_conversion_utils.cc
diff --git a/components/autofill/content/renderer/password_form_conversion_utils.cc b/components/autofill/content/renderer/password_form_conversion_utils.cc
index 856f6100b53213da64c2bc456c0f235053ccb8ee..b1bdbc34e2fb18a7ad7d11a556ebd3d7f5ba373c 100644
--- a/components/autofill/content/renderer/password_form_conversion_utils.cc
+++ b/components/autofill/content/renderer/password_form_conversion_utils.cc
@@ -6,42 +6,172 @@
#include "components/autofill/content/renderer/form_autofill_util.h"
#include "components/autofill/core/common/password_form.h"
+#include "third_party/WebKit/public/platform/WebString.h"
+#include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebFormControlElement.h"
-#include "third_party/WebKit/public/web/WebPasswordFormData.h"
+#include "third_party/WebKit/public/web/WebInputElement.h"
+using blink::WebDocument;
+using blink::WebFormControlElement;
using blink::WebFormElement;
-using blink::WebPasswordFormData;
+using blink::WebInputElement;
+using blink::WebString;
+using blink::WebVector;
namespace autofill {
namespace {
-scoped_ptr<PasswordForm> InitPasswordFormFromWebPasswordForm(
- const WebFormElement& web_form,
- const blink::WebPasswordFormData& web_password_form) {
- PasswordForm* password_form = new PasswordForm();
- password_form->signon_realm = web_password_form.signonRealm.utf8();
- password_form->origin = web_password_form.origin;
- password_form->action = web_password_form.action;
- password_form->submit_element = web_password_form.submitElement;
- password_form->username_element = web_password_form.userNameElement;
- password_form->username_value = web_password_form.userNameValue;
- password_form->other_possible_usernames.insert(
- password_form->other_possible_usernames.begin(),
- web_password_form.possibleUserNames.data(),
- web_password_form.possibleUserNames.data() +
- web_password_form.possibleUserNames.size());
- password_form->password_element = web_password_form.passwordElement;
- password_form->password_value = web_password_form.passwordValue;
- password_form->password_autocomplete_set =
- web_password_form.passwordShouldAutocomplete;
- password_form->old_password_element = web_password_form.oldPasswordElement;
- password_form->old_password_value = web_password_form.oldPasswordValue;
+// Maximum number of password fields we will observe before throwing our
+// hands in the air and giving up with a given form.
+static const size_t kMaxPasswords = 3;
+
+// Helper to determine which password is the main one, and which is
+// an old password (e.g on a "make new password" form), if any.
+bool LocateSpecificPasswords(std::vector<WebInputElement> passwords,
+ WebInputElement* password,
+ WebInputElement* old_password) {
+ switch (passwords.size()) {
+ case 1:
+ // Single password, easy.
+ *password = passwords[0];
+ break;
+ case 2:
+ if (passwords[0].value() == passwords[1].value()) {
+ // Treat two identical passwords as a single password.
+ *password = passwords[0];
+ } else {
+ // Assume first is old password, second is new (no choice but to guess).
+ *old_password = passwords[0];
+ *password = passwords[1];
+ }
+ break;
+ case 3:
+ if (passwords[0].value() == passwords[1].value() &&
+ passwords[0].value() == passwords[2].value()) {
+ // All three passwords the same? Just treat as one and hope.
+ *password = passwords[0];
+ } else if (passwords[0].value() == passwords[1].value()) {
+ // Two the same and one different -> old password is duplicated one.
+ *old_password = passwords[0];
+ *password = passwords[2];
+ } else if (passwords[1].value() == passwords[2].value()) {
+ *old_password = passwords[0];
+ *password = passwords[1];
+ } else {
+ // Three different passwords, or first and last match with middle
+ // different. No idea which is which, so no luck.
+ return false;
+ }
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+// Get information about a login form that encapsulated in the
+// PasswordForm struct.
+void GetPasswordForm(const WebFormElement& form, PasswordForm* password_form) {
+ WebInputElement latest_input_element;
+ std::vector<WebInputElement> passwords;
+ std::vector<base::string16> other_possible_usernames;
+
+ WebVector<WebFormControlElement> control_elements;
+ form.getFormControlElements(control_elements);
+
+ for (size_t i = 0; i < control_elements.size(); ++i) {
+ WebFormControlElement control_element = control_elements[i];
+ if (control_element.isActivatedSubmit())
+ password_form->submit_element = control_element.formControlName();
+
+ WebInputElement* input_element = toWebInputElement(&control_element);
+ if (!input_element || !input_element->isEnabled())
+ continue;
+
+ if ((passwords.size() < kMaxPasswords) &&
+ input_element->isPasswordField()) {
+ // We assume that the username element is the input element before the
+ // first password element.
+ if (passwords.empty() && !latest_input_element.isNull()) {
+ password_form->username_element =
+ latest_input_element.nameForAutofill();
+ password_form->username_value = latest_input_element.value();
+ // Remove the selected username from other_possible_usernames.
+ if (!other_possible_usernames.empty() &&
+ !latest_input_element.value().isEmpty())
+ other_possible_usernames.resize(other_possible_usernames.size() - 1);
+ }
+ passwords.push_back(*input_element);
+ }
+
+ // Various input types such as text, url, email can be a username field.
+ if (input_element->isTextField() && !input_element->isPasswordField()) {
+ latest_input_element = *input_element;
+ // We ignore elements that have no value. Unlike username_element,
+ // other_possible_usernames is used only for autofill, not for form
+ // identification, and blank autofill entries are not useful.
+ if (!input_element->value().isEmpty())
+ other_possible_usernames.push_back(input_element->value());
+ }
+ }
+
+ // Get the document URL
+ GURL full_origin(form.document().url());
+
+ // Calculate the canonical action URL
+ WebString action = form.action();
+ if (action.isNull())
+ action = WebString(""); // missing 'action' attribute implies current URL
+ GURL full_action(form.document().completeURL(action));
+ if (!full_action.is_valid())
+ return;
+
+ WebInputElement password;
+ WebInputElement old_password;
+ if (!LocateSpecificPasswords(passwords, &password, &old_password))
+ return;
+
+ // We want to keep the path but strip any authentication data, as well as
+ // query and ref portions of URL, for the form action and form origin.
+ GURL::Replacements rep;
+ rep.ClearUsername();
+ rep.ClearPassword();
+ rep.ClearQuery();
+ rep.ClearRef();
+ password_form->action = full_action.ReplaceComponents(rep);
+ password_form->origin = full_origin.ReplaceComponents(rep);
+
+ rep.SetPathStr("");
+ password_form->signon_realm = full_origin.ReplaceComponents(rep).spec();
+
+ password_form->other_possible_usernames.swap(other_possible_usernames);
+
+ if (!password.isNull()) {
+ password_form->password_element = password.nameForAutofill();
+ password_form->password_value = password.value();
+ password_form->password_autocomplete_set = password.autoComplete();
+ }
+ if (!old_password.isNull()) {
+ password_form->old_password_element = old_password.nameForAutofill();
+ password_form->old_password_value = old_password.value();
+ }
+
password_form->scheme = PasswordForm::SCHEME_HTML;
password_form->ssl_valid = false;
password_form->preferred = false;
password_form->blacklisted_by_user = false;
password_form->type = PasswordForm::TYPE_MANUAL;
password_form->use_additional_authentication = false;
+}
+
+scoped_ptr<PasswordForm> InitPasswordFormFromWebFormElement(
+ const WebFormElement& web_form,
+ PasswordForm* password_form) {
+ GetPasswordForm(web_form, password_form);
+
+ if (!password_form->action.is_valid())
+ return scoped_ptr<PasswordForm>();
+
WebFormElementToFormData(web_form,
blink::WebFormControlElement(),
REQUIRE_NONE,
@@ -53,11 +183,12 @@ scoped_ptr<PasswordForm> InitPasswordFormFromWebPasswordForm(
} // namespace
-scoped_ptr<PasswordForm> CreatePasswordForm(const WebFormElement& webform) {
- WebPasswordFormData web_password_form(webform);
- if (web_password_form.isValid())
- return InitPasswordFormFromWebPasswordForm(webform, web_password_form);
- return scoped_ptr<PasswordForm>();
+scoped_ptr<PasswordForm> CreatePasswordForm(const WebFormElement& web_form) {
+ if (web_form.isNull())
+ return scoped_ptr<PasswordForm>();
+
+ PasswordForm* password_form = new PasswordForm();
+ return InitPasswordFormFromWebFormElement(web_form, password_form);
}
} // namespace autofill

Powered by Google App Engine
This is Rietveld 408576698