Commit 3e742833 authored by ziran.sun@samsung.com's avatar ziran.sun@samsung.com

Rewrite functions from WebPasswordFormData and WebPasswordFormUtils in

password_form_conversion_utils.

There are Some old Blink code implemented in Webkit that predates the
Chromium/WebKit API, specifically WebPasswordFormData and WebPasswordFormUtils. At
this point the split just makes this code harder to update, as you need to wait
for a Blink roll when adding a new element to autofill::PasswordForm. This patch is
re-writing this code in components/autofill/content/renderer/password_form_conversion_util
s to make it cleaner.

BUG=None

Review URL: https://codereview.chromium.org/249153002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@266438 0039d316-1c4b-4281-b951-d872f2087c98
parent a0465581
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebNode.h" #include "third_party/WebKit/public/web/WebNode.h"
#include "third_party/WebKit/public/web/WebNodeList.h" #include "third_party/WebKit/public/web/WebNodeList.h"
#include "third_party/WebKit/public/web/WebPasswordFormData.h"
#include "third_party/WebKit/public/web/WebSecurityOrigin.h" #include "third_party/WebKit/public/web/WebSecurityOrigin.h"
#include "third_party/WebKit/public/web/WebUserGestureIndicator.h" #include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
#include "third_party/WebKit/public/web/WebView.h" #include "third_party/WebKit/public/web/WebView.h"
......
...@@ -6,58 +6,184 @@ ...@@ -6,58 +6,184 @@
#include "components/autofill/content/renderer/form_autofill_util.h" #include "components/autofill/content/renderer/form_autofill_util.h"
#include "components/autofill/core/common/password_form.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/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::WebFormElement;
using blink::WebPasswordFormData; using blink::WebInputElement;
using blink::WebString;
using blink::WebVector;
namespace autofill { namespace autofill {
namespace { namespace {
scoped_ptr<PasswordForm> InitPasswordFormFromWebPasswordForm( // Maximum number of password fields we will observe before throwing our
const WebFormElement& web_form, // hands in the air and giving up with a given form.
const blink::WebPasswordFormData& web_password_form) { static const size_t kMaxPasswords = 3;
PasswordForm* password_form = new PasswordForm();
password_form->signon_realm = web_password_form.signonRealm.utf8(); // Helper to determine which password is the main one, and which is
password_form->origin = web_password_form.origin; // an old password (e.g on a "make new password" form), if any.
password_form->action = web_password_form.action; bool LocateSpecificPasswords(std::vector<WebInputElement> passwords,
password_form->submit_element = web_password_form.submitElement; WebInputElement* password,
password_form->username_element = web_password_form.userNameElement; WebInputElement* old_password) {
password_form->username_value = web_password_form.userNameValue; switch (passwords.size()) {
password_form->other_possible_usernames.insert( case 1:
password_form->other_possible_usernames.begin(), // Single password, easy.
web_password_form.possibleUserNames.data(), *password = passwords[0];
web_password_form.possibleUserNames.data() + break;
web_password_form.possibleUserNames.size()); case 2:
password_form->password_element = web_password_form.passwordElement; if (passwords[0].value() == passwords[1].value()) {
password_form->password_value = web_password_form.passwordValue; // Treat two identical passwords as a single password.
password_form->password_autocomplete_set = *password = passwords[0];
web_password_form.passwordShouldAutocomplete; } else {
password_form->old_password_element = web_password_form.oldPasswordElement; // Assume first is old password, second is new (no choice but to guess).
password_form->old_password_value = web_password_form.oldPasswordValue; *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->scheme = PasswordForm::SCHEME_HTML;
password_form->ssl_valid = false; password_form->ssl_valid = false;
password_form->preferred = false; password_form->preferred = false;
password_form->blacklisted_by_user = false; password_form->blacklisted_by_user = false;
password_form->type = PasswordForm::TYPE_MANUAL; password_form->type = PasswordForm::TYPE_MANUAL;
password_form->use_additional_authentication = false; password_form->use_additional_authentication = false;
}
} // namespace
scoped_ptr<PasswordForm> CreatePasswordForm(const WebFormElement& web_form) {
if (web_form.isNull())
return scoped_ptr<PasswordForm>();
scoped_ptr<PasswordForm> password_form(new PasswordForm());
GetPasswordForm(web_form, password_form.get());
if (!password_form->action.is_valid())
return scoped_ptr<PasswordForm>();
WebFormElementToFormData(web_form, WebFormElementToFormData(web_form,
blink::WebFormControlElement(), blink::WebFormControlElement(),
REQUIRE_NONE, REQUIRE_NONE,
EXTRACT_NONE, EXTRACT_NONE,
&password_form->form_data, &password_form->form_data,
NULL /* FormFieldData */); NULL /* FormFieldData */);
return scoped_ptr<PasswordForm>(password_form);
}
} // namespace
scoped_ptr<PasswordForm> CreatePasswordForm(const WebFormElement& webform) { return password_form.Pass();
WebPasswordFormData web_password_form(webform);
if (web_password_form.isValid())
return InitPasswordFormFromWebPasswordForm(webform, web_password_form);
return scoped_ptr<PasswordForm>();
} }
} // namespace autofill } // namespace autofill
...@@ -12,11 +12,9 @@ ...@@ -12,11 +12,9 @@
#include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebDocument.h"
#include "third_party/WebKit/public/web/WebFormElement.h" #include "third_party/WebKit/public/web/WebFormElement.h"
#include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebLocalFrame.h"
#include "third_party/WebKit/public/web/WebPasswordFormData.h"
using blink::WebFormElement; using blink::WebFormElement;
using blink::WebFrame; using blink::WebFrame;
using blink::WebPasswordFormData;
using blink::WebVector; using blink::WebVector;
namespace autofill { namespace autofill {
...@@ -48,8 +46,6 @@ TEST_F(PasswordFormConversionUtilsTest, ValidWebFormElementToPasswordForm) { ...@@ -48,8 +46,6 @@ TEST_F(PasswordFormConversionUtilsTest, ValidWebFormElementToPasswordForm) {
WebVector<WebFormElement> forms; WebVector<WebFormElement> forms;
frame->document().forms(forms); frame->document().forms(forms);
ASSERT_EQ(1U, forms.size()); ASSERT_EQ(1U, forms.size());
WebPasswordFormData web_password_form(forms[0]);
ASSERT_TRUE(web_password_form.isValid());
scoped_ptr<PasswordForm> password_form = CreatePasswordForm(forms[0]); scoped_ptr<PasswordForm> password_form = CreatePasswordForm(forms[0]);
ASSERT_NE(static_cast<PasswordForm*>(NULL), password_form.get()); ASSERT_NE(static_cast<PasswordForm*>(NULL), password_form.get());
...@@ -82,11 +78,82 @@ TEST_F(PasswordFormConversionUtilsTest, InvalidWebFormElementToPasswordForm) { ...@@ -82,11 +78,82 @@ TEST_F(PasswordFormConversionUtilsTest, InvalidWebFormElementToPasswordForm) {
WebVector<WebFormElement> forms; WebVector<WebFormElement> forms;
frame->document().forms(forms); frame->document().forms(forms);
ASSERT_EQ(1U, forms.size()); ASSERT_EQ(1U, forms.size());
WebPasswordFormData web_password_form(forms[0]);
ASSERT_FALSE(web_password_form.isValid());
scoped_ptr<PasswordForm> password_form = CreatePasswordForm(forms[0]); scoped_ptr<PasswordForm> password_form = CreatePasswordForm(forms[0]);
EXPECT_EQ(static_cast<PasswordForm*>(NULL), password_form.get()); EXPECT_EQ(static_cast<PasswordForm*>(NULL), password_form.get());
} }
TEST_F(PasswordFormConversionUtilsTest,
WebFormWithMultipleUseNameAndPassWordFieldsToPasswordForm) {
LoadHTML("<FORM name=\"TestForm\" action=\"http://cnn.com\" method=\"post\">"
" <INPUT type=\"text\" name=\"username1\" "
" id=\"username1\" value=\"John\"/>"
" <INPUT type=\"password\" name=\"password1\" id=\"password1\" "
" value=\"encrypted\"/>"
" <INPUT type=\"text\" name=\"username2\" "
" id=\"username2\" value=\"Smith\"/>"
" <INPUT type=\"password\" name=\"password2\" id=\"password2\" "
" value=\"secret\"/>"
" <INPUT type=\"text\" name=\"username3\" "
" id=\"username3\" value=\"JohnSmith\"/>"
" <INPUT type=\"password\" name=\"password3\" id=\"password3\" "
" value=\"secret\"/>"
" <INPUT type=\"submit\" name=\"submit\" value=\"Submit\"/>"
"</FORM>");
WebFrame* frame = GetMainFrame();
ASSERT_NE(static_cast<WebFrame*>(NULL), frame);
WebVector<WebFormElement> forms;
frame->document().forms(forms);
ASSERT_EQ(1U, forms.size());
scoped_ptr<PasswordForm> password_form = CreatePasswordForm(forms[0]);
ASSERT_NE(static_cast<PasswordForm*>(NULL), password_form.get());
EXPECT_EQ("data:", password_form->signon_realm);
EXPECT_EQ(GURL("http://cnn.com"), password_form->action);
EXPECT_EQ(base::UTF8ToUTF16("username1"), password_form->username_element);
EXPECT_EQ(base::UTF8ToUTF16("John"), password_form->username_value);
EXPECT_EQ(base::UTF8ToUTF16("password2"), password_form->password_element);
EXPECT_EQ(base::UTF8ToUTF16("secret"), password_form->password_value);
EXPECT_EQ(base::UTF8ToUTF16("password1"),
password_form->old_password_element);
EXPECT_EQ(base::UTF8ToUTF16("encrypted"), password_form->old_password_value);
EXPECT_EQ(base::UTF8ToUTF16("Smith"),
password_form->other_possible_usernames[0]);
EXPECT_EQ(base::UTF8ToUTF16("JohnSmith"),
password_form->other_possible_usernames[1]);
EXPECT_EQ(PasswordForm::SCHEME_HTML, password_form->scheme);
EXPECT_FALSE(password_form->ssl_valid);
EXPECT_FALSE(password_form->preferred);
EXPECT_FALSE(password_form->blacklisted_by_user);
EXPECT_EQ(PasswordForm::TYPE_MANUAL, password_form->type);
}
TEST_F(PasswordFormConversionUtilsTest,
WebFormwithThreeDifferentPasswordsToPasswordForm) {
LoadHTML("<FORM name=\"TestForm\" action=\"http://cnn.com\" method=\"post\">"
" <INPUT type=\"text\" name=\"username\" "
" id=\"username\" value=\"John\"/>"
" <INPUT type=\"password\" name=\"password1\" id=\"password1\" "
" value=\"secret\"/>"
" <INPUT type=\"password\" name=\"password2\" id=\"password2\" "
" value=\"encrypted\"/>"
" <INPUT type=\"password\" name=\"password3\" id=\"password3\" "
" value=\"key\"/>"
" <INPUT type=\"submit\" name=\"submit\" value=\"Submit\"/>"
"</FORM>");
WebFrame* frame = GetMainFrame();
ASSERT_NE(static_cast<WebFrame*>(NULL), frame);
WebVector<WebFormElement> forms;
frame->document().forms(forms);
ASSERT_EQ(1U, forms.size());
scoped_ptr<PasswordForm> password_form = CreatePasswordForm(forms[0]);
ASSERT_EQ(static_cast<PasswordForm*>(NULL), password_form.get());
}
} // namespace autofill } // namespace autofill
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment