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 <string.h> 6 7 #include "base/memory/scoped_ptr.h" 8 #include "base/strings/utf_string_conversions.h" 9 #include "chrome/test/base/chrome_render_view_test.h" 10 #include "components/autofill/content/common/autofill_messages.h" 11 #include "components/autofill/content/renderer/autofill_agent.h" 12 #include "components/autofill/content/renderer/test_password_generation_agent.h" 13 #include "components/autofill/core/common/form_data.h" 14 #include "testing/gtest/include/gtest/gtest.h" 15 #include "third_party/WebKit/public/platform/WebString.h" 16 #include "third_party/WebKit/public/web/WebDocument.h" 17 #include "third_party/WebKit/public/web/WebLocalFrame.h" 18 #include "third_party/WebKit/public/web/WebWidget.h" 19 20 using blink::WebDocument; 21 using blink::WebElement; 22 using blink::WebInputElement; 23 using blink::WebNode; 24 using blink::WebString; 25 26 namespace autofill { 27 28 class PasswordGenerationAgentTest : public ChromeRenderViewTest { 29 public: 30 PasswordGenerationAgentTest() {} 31 32 virtual void TearDown() { 33 LoadHTML(""); 34 ChromeRenderViewTest::TearDown(); 35 } 36 37 void SetNotBlacklistedMessage(const char* form_str) { 38 autofill::PasswordForm form; 39 form.origin = 40 GURL(base::StringPrintf("data:text/html;charset=utf-8,%s", form_str)); 41 AutofillMsg_FormNotBlacklisted msg(0, form); 42 password_generation_->OnMessageReceived(msg); 43 } 44 45 void SetAccountCreationFormsDetectedMessage(const char* form_str) { 46 autofill::FormData form; 47 form.origin = 48 GURL(base::StringPrintf("data:text/html;charset=utf-8,%s", form_str)); 49 std::vector<autofill::FormData> forms; 50 forms.push_back(form); 51 AutofillMsg_AccountCreationFormsDetected msg(0, forms); 52 password_generation_->OnMessageReceived(msg); 53 } 54 55 void ExpectPasswordGenerationAvailable(const char* element_id, 56 bool available) { 57 WebDocument document = GetMainFrame()->document(); 58 WebElement element = 59 document.getElementById(WebString::fromUTF8(element_id)); 60 ASSERT_FALSE(element.isNull()); 61 WebInputElement target_element = element.to<WebInputElement>(); 62 ExecuteJavaScript( 63 base::StringPrintf("document.getElementById('%s').focus();", 64 element_id).c_str()); 65 if (available) { 66 ASSERT_EQ(1u, password_generation_->messages().size()); 67 EXPECT_EQ(AutofillHostMsg_ShowPasswordGenerationPopup::ID, 68 password_generation_->messages()[0]->type()); 69 } else { 70 EXPECT_EQ(0u, password_generation_->messages().size()); 71 } 72 password_generation_->clear_messages(); 73 } 74 75 private: 76 DISALLOW_COPY_AND_ASSIGN(PasswordGenerationAgentTest); 77 }; 78 79 const char kSigninFormHTML[] = 80 "<FORM name = 'blah' action = 'http://www.random.com/'> " 81 " <INPUT type = 'text' id = 'username'/> " 82 " <INPUT type = 'password' id = 'password'/> " 83 " <INPUT type = 'submit' value = 'LOGIN' />" 84 "</FORM>"; 85 86 const char kAccountCreationFormHTML[] = 87 "<FORM name = 'blah' action = 'http://www.random.com/'> " 88 " <INPUT type = 'text' id = 'username'/> " 89 " <INPUT type = 'password' id = 'first_password' " 90 " autocomplete = 'off' size = 5/>" 91 " <INPUT type = 'password' id = 'second_password' size = 5/> " 92 " <INPUT type = 'text' id = 'address'/> " 93 " <INPUT type = 'submit' value = 'LOGIN' />" 94 "</FORM>"; 95 96 const char kHiddenPasswordAccountCreationFormHTML[] = 97 "<FORM name = 'blah' action = 'http://www.random.com/'> " 98 " <INPUT type = 'text' id = 'username'/> " 99 " <INPUT type = 'password' id = 'first_password'/> " 100 " <INPUT type = 'password' id = 'second_password' style='display:none'/> " 101 " <INPUT type = 'submit' value = 'LOGIN' />" 102 "</FORM>"; 103 104 const char kInvalidActionAccountCreationFormHTML[] = 105 "<FORM name = 'blah' action = 'invalid'> " 106 " <INPUT type = 'text' id = 'username'/> " 107 " <INPUT type = 'password' id = 'first_password'/> " 108 " <INPUT type = 'password' id = 'second_password'/> " 109 " <INPUT type = 'submit' value = 'LOGIN' />" 110 "</FORM>"; 111 112 TEST_F(PasswordGenerationAgentTest, DetectionTest) { 113 // Don't shown the icon for non account creation forms. 114 LoadHTML(kSigninFormHTML); 115 ExpectPasswordGenerationAvailable("password", false); 116 117 // We don't show the decoration yet because the feature isn't enabled. 118 LoadHTML(kAccountCreationFormHTML); 119 ExpectPasswordGenerationAvailable("first_password", false); 120 121 // Pretend like We have received message indicating site is not blacklisted, 122 // and we have received message indicating the form is classified as 123 // ACCOUNT_CREATION_FORM form Autofill server. We should show the icon. 124 LoadHTML(kAccountCreationFormHTML); 125 SetNotBlacklistedMessage(kAccountCreationFormHTML); 126 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML); 127 ExpectPasswordGenerationAvailable("first_password", true); 128 129 // This doesn't trigger because hidden password fields are ignored. 130 LoadHTML(kHiddenPasswordAccountCreationFormHTML); 131 SetNotBlacklistedMessage(kHiddenPasswordAccountCreationFormHTML); 132 SetAccountCreationFormsDetectedMessage( 133 kHiddenPasswordAccountCreationFormHTML); 134 ExpectPasswordGenerationAvailable("first_password", false); 135 136 // This doesn't trigger because the form action is invalid. 137 LoadHTML(kInvalidActionAccountCreationFormHTML); 138 SetNotBlacklistedMessage(kInvalidActionAccountCreationFormHTML); 139 SetAccountCreationFormsDetectedMessage(kInvalidActionAccountCreationFormHTML); 140 ExpectPasswordGenerationAvailable("first_password", false); 141 } 142 143 TEST_F(PasswordGenerationAgentTest, FillTest) { 144 // Make sure that we are enabled before loading HTML. 145 LoadHTML(kAccountCreationFormHTML); 146 147 WebDocument document = GetMainFrame()->document(); 148 WebElement element = 149 document.getElementById(WebString::fromUTF8("first_password")); 150 ASSERT_FALSE(element.isNull()); 151 WebInputElement first_password_element = element.to<WebInputElement>(); 152 element = document.getElementById(WebString::fromUTF8("second_password")); 153 ASSERT_FALSE(element.isNull()); 154 WebInputElement second_password_element = element.to<WebInputElement>(); 155 156 // Both password fields should be empty. 157 EXPECT_TRUE(first_password_element.value().isNull()); 158 EXPECT_TRUE(second_password_element.value().isNull()); 159 160 base::string16 password = base::ASCIIToUTF16("random_password"); 161 AutofillMsg_GeneratedPasswordAccepted msg(0, password); 162 password_generation_->OnMessageReceived(msg); 163 164 // Password fields are filled out and set as being autofilled. 165 EXPECT_EQ(password, first_password_element.value()); 166 EXPECT_EQ(password, second_password_element.value()); 167 EXPECT_TRUE(first_password_element.isAutofilled()); 168 EXPECT_TRUE(second_password_element.isAutofilled()); 169 170 // Focus moved to the next input field. 171 // TODO(zysxqn): Change this back to the address element once Bug 90224 172 // https://bugs.webkit.org/show_bug.cgi?id=90224 has been fixed. 173 element = document.getElementById(WebString::fromUTF8("first_password")); 174 ASSERT_FALSE(element.isNull()); 175 EXPECT_EQ(element, document.focusedElement()); 176 } 177 178 TEST_F(PasswordGenerationAgentTest, EditingTest) { 179 LoadHTML(kAccountCreationFormHTML); 180 SetNotBlacklistedMessage(kAccountCreationFormHTML); 181 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML); 182 183 WebDocument document = GetMainFrame()->document(); 184 WebElement element = 185 document.getElementById(WebString::fromUTF8("first_password")); 186 ASSERT_FALSE(element.isNull()); 187 WebInputElement first_password_element = element.to<WebInputElement>(); 188 element = document.getElementById(WebString::fromUTF8("second_password")); 189 ASSERT_FALSE(element.isNull()); 190 WebInputElement second_password_element = element.to<WebInputElement>(); 191 192 base::string16 password = base::ASCIIToUTF16("random_password"); 193 AutofillMsg_GeneratedPasswordAccepted msg(0, password); 194 password_generation_->OnMessageReceived(msg); 195 196 // Passwords start out the same. 197 EXPECT_EQ(password, first_password_element.value()); 198 EXPECT_EQ(password, second_password_element.value()); 199 200 // After editing the first field they are still the same. 201 base::string16 edited_password = base::ASCIIToUTF16("edited_password"); 202 first_password_element.setValue(edited_password); 203 // Cast to WebAutofillClient where textFieldDidChange() is public. 204 static_cast<blink::WebAutofillClient*>(autofill_agent_)->textFieldDidChange( 205 first_password_element); 206 // textFieldDidChange posts a task, so we need to wait until it's been 207 // processed. 208 base::MessageLoop::current()->RunUntilIdle(); 209 210 EXPECT_EQ(edited_password, first_password_element.value()); 211 EXPECT_EQ(edited_password, second_password_element.value()); 212 } 213 214 TEST_F(PasswordGenerationAgentTest, BlacklistedTest) { 215 // Did not receive not blacklisted message. Don't show password generation 216 // icon. 217 LoadHTML(kAccountCreationFormHTML); 218 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML); 219 ExpectPasswordGenerationAvailable("first_password", false); 220 221 // Receive one not blacklisted message for non account creation form. Don't 222 // show password generation icon. 223 LoadHTML(kAccountCreationFormHTML); 224 SetNotBlacklistedMessage(kSigninFormHTML); 225 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML); 226 ExpectPasswordGenerationAvailable("first_password", false); 227 228 // Receive one not blackliste message for account creation form. Show password 229 // generation icon. 230 LoadHTML(kAccountCreationFormHTML); 231 SetNotBlacklistedMessage(kAccountCreationFormHTML); 232 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML); 233 ExpectPasswordGenerationAvailable("first_password", true); 234 235 // Receive two not blacklisted messages, one is for account creation form and 236 // the other is not. Show password generation icon. 237 LoadHTML(kAccountCreationFormHTML); 238 SetNotBlacklistedMessage(kAccountCreationFormHTML); 239 SetNotBlacklistedMessage(kSigninFormHTML); 240 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML); 241 ExpectPasswordGenerationAvailable("first_password", true); 242 } 243 244 TEST_F(PasswordGenerationAgentTest, AccountCreationFormsDetectedTest) { 245 // Did not receive account creation forms detected messege. Don't show 246 // password generation icon. 247 LoadHTML(kAccountCreationFormHTML); 248 SetNotBlacklistedMessage(kAccountCreationFormHTML); 249 ExpectPasswordGenerationAvailable("first_password", false); 250 251 // Receive the account creation forms detected message. Show password 252 // generation icon. 253 LoadHTML(kAccountCreationFormHTML); 254 SetNotBlacklistedMessage(kAccountCreationFormHTML); 255 SetAccountCreationFormsDetectedMessage(kAccountCreationFormHTML); 256 ExpectPasswordGenerationAvailable("first_password", true); 257 } 258 259 } // namespace autofill 260