diff options
-rw-r--r-- | base/base.gyp | 3 | ||||
-rw-r--r-- | base/sha1.cc | 202 | ||||
-rw-r--r-- | base/sha1.h | 24 | ||||
-rw-r--r-- | base/sha1_unittest.cc | 56 | ||||
-rw-r--r-- | chrome/DEPS | 3 | ||||
-rw-r--r-- | chrome/browser/autofill/autofill_field.cc | 37 | ||||
-rw-r--r-- | chrome/browser/autofill/autofill_field.h | 25 | ||||
-rw-r--r-- | chrome/browser/autofill/autofill_manager.cc | 20 | ||||
-rw-r--r-- | chrome/browser/autofill/autofill_manager.h | 6 | ||||
-rw-r--r-- | chrome/browser/autofill/field_types.h | 85 | ||||
-rw-r--r-- | chrome/browser/autofill/form_structure.cc | 154 | ||||
-rw-r--r-- | chrome/browser/autofill/form_structure.h | 63 | ||||
-rw-r--r-- | chrome/browser/webdata/web_database_unittest.cc | 28 | ||||
-rwxr-xr-x | chrome/chrome.gyp | 6 | ||||
-rw-r--r-- | chrome/common/render_messages.h | 8 | ||||
-rw-r--r-- | webkit/glue/form_field.cc | 2 | ||||
-rw-r--r-- | webkit/glue/form_field.h | 3 | ||||
-rw-r--r-- | webkit/glue/form_field_values.cc | 11 | ||||
-rw-r--r-- | webkit/glue/form_field_values.h | 3 |
19 files changed, 723 insertions, 16 deletions
diff --git a/base/base.gyp b/base/base.gyp index b79568d..47d2438 100644 --- a/base/base.gyp +++ b/base/base.gyp @@ -267,6 +267,8 @@ 'scoped_vector.h', 'setproctitle_linux.c', 'setproctitle_linux.h', + 'sha1.cc', + 'sha1.h', 'sha2.cc', 'sha2.h', 'shared_memory.h', @@ -606,6 +608,7 @@ 'scoped_ptr_unittest.cc', 'scoped_temp_dir_unittest.cc', 'scoped_variant_win_unittest.cc', + 'sha1_unittest.cc', 'sha2_unittest.cc', 'shared_memory_unittest.cc', 'simple_thread_unittest.cc', diff --git a/base/sha1.cc b/base/sha1.cc new file mode 100644 index 0000000..620dd56 --- /dev/null +++ b/base/sha1.cc @@ -0,0 +1,202 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/sha1.h" + +#include "base/basictypes.h" + +namespace base { + +// Implementation of SHA-1. Only handles data in byte-sized blocks, +// which simplifies the code a fair bit. + +// This file also contains an HMAC implementation using SHA-1 + +// Identifier names follow notation in FIPS PUB 180-3, where you'll +// also find a description of the algorithm: +// http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf + +// Usage example: +// +// SecureHashAlgorithm sha; +// while(there is data to hash) +// sha.Update(moredata, size of data); +// sha.Final(); +// memcpy(somewhere, sha.Digest(), 20); +// +// to reuse the instance of sha, call sha.Init(); + +// TODO(jhawkins): Replace this implementation with a per-platform +// implementation using each platform's crypto library. + +class SecureHashAlgorithm { + public: + SecureHashAlgorithm() { Init(); } + + static const int kDigestSizeBytes; + + void Init(); + void Update(const void* data, size_t nbytes); + void Final(); + + // 20 bytes of message digest. + const unsigned char* Digest() const { + return reinterpret_cast<const unsigned char*>(H); + } + + private: + void Pad(); + void Process(); + + uint32 A, B, C, D, E; + + uint32 H[5]; + + union { + uint32 W[80]; + uint8 M[64]; + }; + + uint32 cursor; + uint32 l; +}; + +static inline uint32 f(uint32 t, uint32 B, uint32 C, uint32 D) { + if (t < 20) { + return (B & C) | ((~B) & D); + } else if (t < 40) { + return B ^ C ^ D; + } else if (t < 60) { + return (B & C) | (B & D) | (C & D); + } else { + return B ^ C ^ D; + } +} + +static inline uint32 S(uint32 n, uint32 X) { + return (X << n) | (X >> (32-n)); +} + +static inline uint32 K(uint32 t) { + if (t < 20) { + return 0x5a827999; + } else if (t < 40) { + return 0x6ed9eba1; + } else if (t < 60) { + return 0x8f1bbcdc; + } else { + return 0xca62c1d6; + } +} + +static inline void swapends(uint32& t) { + t = ((t & 0xff000000) >> 24) | + ((t & 0xff0000) >> 8) | + ((t & 0xff00) << 8) | + ((t & 0xff) << 24); +} + +const int SecureHashAlgorithm::kDigestSizeBytes = 20; + +void SecureHashAlgorithm::Init() { + cursor = 0; + l = 0; + H[0] = 0x67452301; + H[1] = 0xefcdab89; + H[2] = 0x98badcfe; + H[3] = 0x10325476; + H[4] = 0xc3d2e1f0; +} + +void SecureHashAlgorithm::Final() { + Pad(); + Process(); + + for (int t = 0; t < 5; ++t) + swapends(H[t]); +} + +void SecureHashAlgorithm::Update(const void* data, size_t nbytes) { + const uint8* d = reinterpret_cast<const uint8*>(data); + while (nbytes--) { + M[cursor++] = *d++; + if (cursor >= 64) + Process(); + l += 8; + } +} + +void SecureHashAlgorithm::Pad() { + M[cursor++] = 0x80; + + if (cursor > 64-8) { + // pad out to next block + while (cursor < 64) + M[cursor++] = 0; + + Process(); + } + + while (cursor < 64-4) + M[cursor++] = 0; + + M[64-4] = (l & 0xff000000) >> 24; + M[64-3] = (l & 0xff0000) >> 16; + M[64-2] = (l & 0xff00) >> 8; + M[64-1] = (l & 0xff); +} + +void SecureHashAlgorithm::Process() { + uint32 t; + + // Each a...e corresponds to a section in the FIPS 180-3 algorithm. + + // a. + // + // W and M are in a union, so no need to memcpy. + // memcpy(W, M, sizeof(M)); + for (t = 0; t < 16; ++t) + swapends(W[t]); + + // b. + for (t = 16; t < 80; ++t) + W[t] = S(1, W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]); + + // c. + A = H[0]; + B = H[1]; + C = H[2]; + D = H[3]; + E = H[4]; + + // d. + for (t = 0; t < 80; ++t) { + uint32 TEMP = S(5, A) + f(t, B, C, D) + E + W[t] + K(t); + E = D; + D = C; + C = S(30, B); + B = A; + A = TEMP; + } + + // e. + H[0] += A; + H[1] += B; + H[2] += C; + H[3] += D; + H[4] += E; + + cursor = 0; +} + +std::string SHA1HashString(const std::string& str) { + SecureHashAlgorithm sha; + sha.Update(str.c_str(), str.length()); + sha.Final(); + std::string out(reinterpret_cast<const char*>(sha.Digest()), + SecureHashAlgorithm::kDigestSizeBytes); + return out; +} + +} // namespace base diff --git a/base/sha1.h b/base/sha1.h new file mode 100644 index 0000000..bcc1ced --- /dev/null +++ b/base/sha1.h @@ -0,0 +1,24 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BASE_SHA1_H_ +#define BASE_SHA1_H_ + +#include <string> + +namespace base { + +// This function performs SHA-1 operations. + +enum { + SHA1_LENGTH = 20 // Length in bytes of a SHA-1 hash. +}; + +// Computes the SHA-1 hash of the input string |str| and returns the full +// hash. +std::string SHA1HashString(const std::string& str); + +} // namespace base + +#endif // BASE_SHA1_H_ diff --git a/base/sha1_unittest.cc b/base/sha1_unittest.cc new file mode 100644 index 0000000..e445e8f --- /dev/null +++ b/base/sha1_unittest.cc @@ -0,0 +1,56 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/sha1.h" + +#include <string> + +#include "base/basictypes.h" +#include "testing/gtest/include/gtest/gtest.h" + +TEST(SHA1Test, Test1) { + // Example A.1 from FIPS 180-2: one-block message. + std::string input = "abc"; + + int expected[] = { 0xa9, 0x99, 0x3e, 0x36, + 0x47, 0x06, 0x81, 0x6a, + 0xba, 0x3e, 0x25, 0x71, + 0x78, 0x50, 0xc2, 0x6c, + 0x9c, 0xd0, 0xd8, 0x9d }; + + std::string output = base::SHA1HashString(input); + for (size_t i = 0; i < base::SHA1_LENGTH; i++) + EXPECT_EQ(expected[i], output[i] & 0xFF); +} + +TEST(SHA1Test, Test2) { + // Example A.2 from FIPS 180-2: multi-block message. + std::string input = + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + + int expected[] = { 0x84, 0x98, 0x3e, 0x44, + 0x1c, 0x3b, 0xd2, 0x6e, + 0xba, 0xae, 0x4a, 0xa1, + 0xf9, 0x51, 0x29, 0xe5, + 0xe5, 0x46, 0x70, 0xf1 }; + + std::string output = base::SHA1HashString(input); + for (size_t i = 0; i < base::SHA1_LENGTH; i++) + EXPECT_EQ(expected[i], output[i] & 0xFF); +} + +TEST(SHA1Test, Test3) { + // Example A.3 from FIPS 180-2: long message. + std::string input(1000000, 'a'); + + int expected[] = { 0x34, 0xaa, 0x97, 0x3c, + 0xd4, 0xc4, 0xda, 0xa4, + 0xf6, 0x1e, 0xeb, 0x2b, + 0xdb, 0xad, 0x27, 0x31, + 0x65, 0x34, 0x01, 0x6f }; + + std::string output = base::SHA1HashString(input); + for (size_t i = 0; i < base::SHA1_LENGTH; i++) + EXPECT_EQ(expected[i], output[i] & 0xFF); +} diff --git a/chrome/DEPS b/chrome/DEPS index c1fb4b8..ca6752e 100644 --- a/chrome/DEPS +++ b/chrome/DEPS @@ -30,6 +30,9 @@ include_rules = [ # Allow usage of Google Toolbox for Mac. "+third_party/GTM", + # Allow usage of the libjingle library. + "+third_party/libjingle", + # Our Skia extensions. "+skia/ext", diff --git a/chrome/browser/autofill/autofill_field.cc b/chrome/browser/autofill/autofill_field.cc new file mode 100644 index 0000000..fba28a0 --- /dev/null +++ b/chrome/browser/autofill/autofill_field.cc @@ -0,0 +1,37 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/autofill/autofill_field.h" + +#include "base/logging.h" +#include "base/sha1.h" +#include "base/string_util.h" +#include "base/utf_string_conversions.h" + +namespace { + +static std::string Hash32Bit(const std::string& str) { + std::string hash_bin = base::SHA1HashString(str); + DCHECK(hash_bin.length() == 20); + + uint32 hash32 = ((hash_bin[0] & 0xFF) << 24) | + ((hash_bin[1] & 0xFF) << 16) | + ((hash_bin[2] & 0xFF) << 8) | + (hash_bin[3] & 0xFF); + + return UintToString(hash32); +} + +} // namespace + +AutoFillField::AutoFillField(const webkit_glue::FormField& field) + : webkit_glue::FormField(field) { +} + +std::string AutoFillField::FieldSignature() const { + std::string field_name = UTF16ToUTF8(name()); + std::string type = UTF16ToUTF8(html_input_type()); + std::string field_string = field_name + "&" + type; + return Hash32Bit(field_string); +} diff --git a/chrome/browser/autofill/autofill_field.h b/chrome/browser/autofill/autofill_field.h new file mode 100644 index 0000000..670fd14 --- /dev/null +++ b/chrome/browser/autofill/autofill_field.h @@ -0,0 +1,25 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_AUTOFILL_AUTOFILL_FIELD_H_ +#define CHROME_BROWSER_AUTOFILL_AUTOFILL_FIELD_H_ + +#include "chrome/browser/autofill/field_types.h" +#include "webkit/glue/form_field.h" + +class AutoFillField : public webkit_glue::FormField { + public: + AutoFillField(const webkit_glue::FormField& field); + + const FieldTypeSet& possible_types() const { return possible_types_; } + + // The unique signature of this field, composed of the field name and the html + // input type in a 32-bit hash. + std::string FieldSignature() const; + + private: + FieldTypeSet possible_types_; +}; + +#endif // CHROME_BROWSER_AUTOFILL_AUTOFILL_FIELD_H_ diff --git a/chrome/browser/autofill/autofill_manager.cc b/chrome/browser/autofill/autofill_manager.cc index 6b78a3d..2a9d3f3 100644 --- a/chrome/browser/autofill/autofill_manager.cc +++ b/chrome/browser/autofill/autofill_manager.cc @@ -4,8 +4,11 @@ #include "chrome/browser/autofill/autofill_manager.h" +#include <string> + #include "base/command_line.h" #include "chrome/browser/autofill/autofill_infobar_delegate.h" +#include "chrome/browser/autofill/form_structure.h" #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/common/chrome_switches.h" #include "webkit/glue/form_field_values.h" @@ -26,16 +29,29 @@ void AutoFillManager::FormFieldValuesSubmitted( return; // Grab a copy of the form data. - form_data_.reset(new webkit_glue::FormFieldValues(form)); + form_structure_.reset(new FormStructure(form)); + + if (!form_structure_->IsAutoFillable()) + return; // Ask the user for permission to save form information. infobar_.reset(new AutoFillInfoBarDelegate(tab_contents_, this)); } void AutoFillManager::SaveFormData() { + UploadFormData(); + // TODO(jhawkins): Save the form data to the web database. } +void AutoFillManager::UploadFormData() { + std::string xml; + bool ok = form_structure_->EncodeUploadRequest(false, &xml); + DCHECK(ok); + + // TODO(jhawkins): Initiate the upload request thread. +} + void AutoFillManager::Reset() { - form_data_.reset(); + form_structure_.reset(); } diff --git a/chrome/browser/autofill/autofill_manager.h b/chrome/browser/autofill/autofill_manager.h index 6e09e6f..521d48b 100644 --- a/chrome/browser/autofill/autofill_manager.h +++ b/chrome/browser/autofill/autofill_manager.h @@ -13,6 +13,7 @@ class FormFieldValues; } class AutoFillInfoBarDelegate; +class FormStructure; class TabContents; // Manages saving and restoring the user's personal information entered into web @@ -29,6 +30,9 @@ class AutoFillManager : public RenderViewHostDelegate::AutoFill { // Saves the form data to the web database. void SaveFormData(); + // Uploads the form data to the autofill server. + void UploadFormData(); + // Resets the stored form data. void Reset(); @@ -37,7 +41,7 @@ class AutoFillManager : public RenderViewHostDelegate::AutoFill { TabContents* tab_contents_; // Our copy of the form data. - scoped_ptr<webkit_glue::FormFieldValues> form_data_; + scoped_ptr<FormStructure> form_structure_; // The infobar asking for permission to store form information. scoped_ptr<AutoFillInfoBarDelegate> infobar_; diff --git a/chrome/browser/autofill/field_types.h b/chrome/browser/autofill/field_types.h new file mode 100644 index 0000000..903af7e --- /dev/null +++ b/chrome/browser/autofill/field_types.h @@ -0,0 +1,85 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_AUTOFILL_FIELD_TYPES_H_ +#define CHROME_BROWSER_AUTOFILL_FIELD_TYPES_H_ + +#include <set> + +// NOTE: This list MUST not be modified. The server aggregates and stores these +// types over several versions, so we must remain fully compatible with the +// autofill server, which is itself backward-compatible. The list must be kept +// up to date with the autofill server list. +// +// This is the list of all valid field types. +typedef enum _FieldType { + // Server indication that it has no data for the requested field. + NO_SERVER_DATA = 0, + // Client indication that the text entered did not match anything in the + // personal data. + UNKNOWN_TYPE = 1, + // The "empty" type indicates that the user hasn't entered anything + // in this field. + EMPTY_TYPE = 2, + // Personal Information categorization types. + NAME_FIRST = 3, + NAME_MIDDLE = 4, + NAME_LAST = 5, + NAME_MIDDLE_INITIAL = 6, + NAME_FULL = 7, + NAME_SUFFIX = 8, + EMAIL_ADDRESS = 9, + PHONE_HOME_NUMBER = 10, + PHONE_HOME_CITY_CODE = 11, + PHONE_HOME_COUNTRY_CODE = 12, + PHONE_HOME_CITY_AND_NUMBER = 13, + PHONE_HOME_WHOLE_NUMBER = 14, + + // Work phone numbers (values [15,19]) are deprecated. + + PHONE_FAX_NUMBER = 20, + PHONE_FAX_CITY_CODE = 21, + PHONE_FAX_COUNTRY_CODE = 22, + PHONE_FAX_CITY_AND_NUMBER = 23, + PHONE_FAX_WHOLE_NUMBER = 24, + + // Cell phone numbers (values [25, 29]) are deprecated. + + ADDRESS_HOME_LINE1 = 30, + ADDRESS_HOME_LINE2 = 31, + ADDRESS_HOME_APPT_NUM = 32, + ADDRESS_HOME_CITY = 33, + ADDRESS_HOME_STATE = 34, + ADDRESS_HOME_ZIP = 35, + ADDRESS_HOME_COUNTRY = 36, + ADDRESS_BILLING_LINE1 = 37, + ADDRESS_BILLING_LINE2 = 38, + ADDRESS_BILLING_APPT_NUM = 39, + ADDRESS_BILLING_CITY = 40, + ADDRESS_BILLING_STATE = 41, + ADDRESS_BILLING_ZIP = 42, + ADDRESS_BILLING_COUNTRY = 43, + + // ADDRESS_SHIPPING values [44,50] are deprecated. + + CREDIT_CARD_NAME = 51, + CREDIT_CARD_NUMBER = 52, + CREDIT_CARD_EXP_MONTH = 53, + CREDIT_CARD_EXP_2_DIGIT_YEAR = 54, + CREDIT_CARD_EXP_4_DIGIT_YEAR = 55, + CREDIT_CARD_EXP_DATE_2_DIGIT_YEAR = 56, + CREDIT_CARD_EXP_DATE_4_DIGIT_YEAR = 57, + CREDIT_CARD_TYPE = 58, + CREDIT_CARD_VERIFICATION_CODE = 59, + + COMPANY_NAME = 60, + + // No new types can be added. + + MAX_VALID_FIELD_TYPE = 61, +} AutoFillFieldType; + +typedef std::set<AutoFillFieldType> FieldTypeSet; + +#endif // CHROME_BROWSER_AUTOFILL_FIELD_TYPES_H_ diff --git a/chrome/browser/autofill/form_structure.cc b/chrome/browser/autofill/form_structure.cc new file mode 100644 index 0000000..354a36c --- /dev/null +++ b/chrome/browser/autofill/form_structure.cc @@ -0,0 +1,154 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/autofill/form_structure.h" + +#include "base/basictypes.h" +#include "base/logging.h" +#include "base/sha1.h" +#include "base/string_util.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/autofill/field_types.h" +#include "third_party/libjingle/files/talk/xmllite/xmlelement.h" +#include "webkit/glue/form_field.h" +#include "webkit/glue/form_field_values.h" + +const char* kFormMethodGet = "get"; +const char* kFormMethodPost = "post"; + +// XML attribute names +const char* const kAttributeClientVersion = "clientversion"; +const char* const kAttributeAutoFillUsed = "autofillused"; +const char* const kAttributeSignature = "signature"; +const char* const kAttributeFormSignature = "formsignature"; +const char* const kAttributeDataPresent = "datapresent"; + +const char* const kXMLElementForm = "form"; +const char* const kXMLElementField = "field"; +const char* const kAttributeAutoFillType = "autofilltype"; + +namespace { + +static std::string Hash64Bit(const std::string& str) { + std::string hash_bin = base::SHA1HashString(str); + DCHECK(hash_bin.length() == 20); + + uint64 hash64 = (((static_cast<uint64>(hash_bin[0])) & 0xFF) << 56) | + (((static_cast<uint64>(hash_bin[1])) & 0xFF) << 48) | + (((static_cast<uint64>(hash_bin[2])) & 0xFF) << 40) | + (((static_cast<uint64>(hash_bin[3])) & 0xFF) << 32) | + (((static_cast<uint64>(hash_bin[4])) & 0xFF) << 24) | + (((static_cast<uint64>(hash_bin[5])) & 0xFF) << 16) | + (((static_cast<uint64>(hash_bin[6])) & 0xFF) << 8) | + ((static_cast<uint64>(hash_bin[7])) & 0xFF); + + return Uint64ToString(hash64); +} + +} // namespace + +FormStructure::FormStructure(const webkit_glue::FormFieldValues& values) + : form_name_(UTF16ToUTF8(values.form_name)), + source_url_(values.source_url), + target_url_(values.target_url) { + // Copy the form fields. + std::vector<webkit_glue::FormField>::const_iterator field; + for (field = values.elements.begin(); + field != values.elements.end(); field++) { + fields_.push_back(AutoFillField(*field)); + } + + std::string method = UTF16ToUTF8(values.method); + if (method == kFormMethodPost) { + method_ = POST; + } else { + // Either the method is 'get', or we don't know. In this case we default + // to GET. + method_ = GET; + } +} + +bool FormStructure::EncodeUploadRequest(bool auto_fill_used, + std::string* encoded_xml) const { + bool auto_fillable = IsAutoFillable(); + DCHECK(auto_fillable); // Caller should've checked for search pages. + if (!auto_fillable) + return false; + + buzz::XmlElement autofill_upload(buzz::QName("autofillupload")); + + // Attributes for the <autofillupload> element. + // + // TODO(jhawkins): Work with toolbar devs to make a spec for autofill clients. + // For now these values are hacked from the toolbar code. + autofill_upload.SetAttr(buzz::QName(kAttributeClientVersion), + "6.1.1715.1442/en (GGLL)"); + + autofill_upload.SetAttr(buzz::QName(kAttributeFormSignature), + FormSignature()); + + autofill_upload.SetAttr(buzz::QName(kAttributeAutoFillUsed), + auto_fill_used ? "true" : "false"); + + // TODO(jhawkins): Hook this up to the personal data manager. + // personaldata_manager_->GetDataPresent(); + autofill_upload.SetAttr(buzz::QName(kAttributeDataPresent), ""); + + // Add the child nodes for the form fields. + std::vector<AutoFillField>::const_iterator field; + for (field = fields_.begin(); field != fields_.end(); field++) { + FieldTypeSet types = field->possible_types(); + for (FieldTypeSet::const_iterator type = types.begin(); + type != types.end(); type++) { + buzz::XmlElement *field_element = new buzz::XmlElement( + buzz::QName(kXMLElementField)); + + field_element->SetAttr(buzz::QName(kAttributeSignature), + field->FieldSignature()); + + field_element->SetAttr(buzz::QName(kAttributeAutoFillType), + IntToString(*type)); + + autofill_upload.AddElement(field_element); + } + } + + // Obtain the XML structure as a string. + *encoded_xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; + *encoded_xml += autofill_upload.Str().c_str(); + + return true; +} + +std::string FormStructure::FormSignature() const { + std::string form_string = target_url_.host() + + "&" + + form_name_ + + form_signature_field_names_; + + return Hash64Bit(form_string); +} + +bool FormStructure::IsAutoFillable() const { + if (fields_.size() == 0) + return false; + + // Rule out http(s)://*/search?... + // e.g. http://www.google.com/search?q=... + // http://search.yahoo.com/search?p=... + if (target_url_.path() == "/search") + return false; + + // Disqualify all forms that are likely to be search boxes (like google.com). + if (fields_.size() == 1) { + std::string name = UTF16ToUTF8(fields_[0].name()); + if (name == "q") + return false; + } + + if (method_ == GET) + return false; + + return true; +} diff --git a/chrome/browser/autofill/form_structure.h b/chrome/browser/autofill/form_structure.h new file mode 100644 index 0000000..c0d178d9 --- /dev/null +++ b/chrome/browser/autofill/form_structure.h @@ -0,0 +1,63 @@ +// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_AUTOFILL_FORM_STRUCTURE_H_ +#define CHROME_BROWSER_AUTOFILL_FORM_STRUCTURE_H_ + +#include <string> +#include <vector> + +#include "base/scoped_ptr.h" +#include "chrome/browser/autofill/autofill_field.h" +#include "googleurl/src/gurl.h" + +namespace webkit_glue { +class FormFieldValues; +} + +enum RequestMethod { + GET, + POST +}; + +// FormStructure stores a single HTML form together with the values entered +// in the fields along with additional information needed by AutoFill. +class FormStructure { + public: + explicit FormStructure(const webkit_glue::FormFieldValues& values); + + // Encodes the XML upload request from this FormStructure. + bool EncodeUploadRequest(bool auto_fill_used, std::string* encoded_xml) const; + + // The unique signature for this form, composed of the target url domain, + // the form name, and the form field names in a 64-bit hash. + std::string FormSignature() const; + + // Runs a quick heuristic to rule out pages but obviously not auto-fillable, + // like google/yahoo/msn search, etc. + bool IsAutoFillable() const; + + private: + // The name of the form. + std::string form_name_; + + // The source URL. + GURL source_url_; + + // The target URL. + GURL target_url_; + + // A vector of all the input fields in the form. + std::vector<AutoFillField> fields_; + + // The names of the form input elements, that are part of the form signature. + // The string starts with "&" and the names are also separated by the "&" + // character. E.g.: "&form_input1_name&form_input2_name&...&form_inputN_name" + std::string form_signature_field_names_; + + // GET or POST. + RequestMethod method_; +}; + +#endif // CHROME_BROWSER_AUTOFILL_FORM_STRUCTURE_H_ diff --git a/chrome/browser/webdata/web_database_unittest.cc b/chrome/browser/webdata/web_database_unittest.cc index 0a6d6c5..14f52e1 100644 --- a/chrome/browser/webdata/web_database_unittest.cc +++ b/chrome/browser/webdata/web_database_unittest.cc @@ -392,19 +392,25 @@ TEST_F(WebDatabaseTest, Autofill) { // Simulate the submission of a handful of entries in a field called "Name", // some more often than others. EXPECT_TRUE(db.AddFormFieldValue( - FormField(ASCIIToUTF16("Name"), ASCIIToUTF16("Superman")))); + FormField(ASCIIToUTF16("Name"), string16(), ASCIIToUTF16("Superman")))); std::vector<string16> v; for (int i = 0; i < 5; i++) { EXPECT_TRUE(db.AddFormFieldValue( - FormField(ASCIIToUTF16("Name"), ASCIIToUTF16("Clark Kent")))); + FormField(ASCIIToUTF16("Name"), + string16(), + ASCIIToUTF16("Clark Kent")))); } for (int i = 0; i < 3; i++) { EXPECT_TRUE(db.AddFormFieldValue( - FormField(ASCIIToUTF16("Name"), ASCIIToUTF16("Clark Sutter")))); + FormField(ASCIIToUTF16("Name"), + string16(), + ASCIIToUTF16("Clark Sutter")))); } for (int i = 0; i < 2; i++) { EXPECT_TRUE(db.AddFormFieldValue( - FormField(ASCIIToUTF16("Favorite Color"), ASCIIToUTF16("Green")))); + FormField(ASCIIToUTF16("Favorite Color"), + string16(), + ASCIIToUTF16("Green")))); } int count = 0; @@ -413,7 +419,7 @@ TEST_F(WebDatabaseTest, Autofill) { // We have added the name Clark Kent 5 times, so count should be 5 and pair_id // should be somthing non-zero. EXPECT_TRUE(db.GetIDAndCountOfFormElement( - FormField(ASCIIToUTF16("Name"), ASCIIToUTF16("Clark Kent")), + FormField(ASCIIToUTF16("Name"), string16(), ASCIIToUTF16("Clark Kent")), &pair_id, &count)); EXPECT_EQ(5, count); EXPECT_NE(0, pair_id); @@ -421,12 +427,14 @@ TEST_F(WebDatabaseTest, Autofill) { // Storing in the data base should be case sensitive, so there should be no // database entry for clark kent lowercase. EXPECT_TRUE(db.GetIDAndCountOfFormElement( - FormField(ASCIIToUTF16("Name"), ASCIIToUTF16("clark kent")), + FormField(ASCIIToUTF16("Name"), string16(), ASCIIToUTF16("clark kent")), &pair_id, &count)); EXPECT_EQ(0, count); EXPECT_TRUE(db.GetIDAndCountOfFormElement( - FormField(ASCIIToUTF16("Favorite Color"), ASCIIToUTF16("Green")), + FormField(ASCIIToUTF16("Favorite Color"), + string16(), + ASCIIToUTF16("Green")), &pair_id, &count)); EXPECT_EQ(2, count); @@ -467,7 +475,7 @@ TEST_F(WebDatabaseTest, Autofill) { EXPECT_TRUE(db.RemoveFormElementsAddedBetween(t1, Time())); EXPECT_TRUE(db.GetIDAndCountOfFormElement( - FormField(ASCIIToUTF16("Name"), ASCIIToUTF16("Clark Kent")), + FormField(ASCIIToUTF16("Name"), string16(), ASCIIToUTF16("Clark Kent")), &pair_id, &count)); EXPECT_EQ(0, count); @@ -478,12 +486,16 @@ TEST_F(WebDatabaseTest, Autofill) { // Now add some values with empty strings. const string16 kValue = ASCIIToUTF16(" toto "); EXPECT_TRUE(db.AddFormFieldValue(FormField(ASCIIToUTF16("blank"), + string16(), string16()))); EXPECT_TRUE(db.AddFormFieldValue(FormField(ASCIIToUTF16("blank"), + string16(), ASCIIToUTF16(" ")))); EXPECT_TRUE(db.AddFormFieldValue(FormField(ASCIIToUTF16("blank"), + string16(), ASCIIToUTF16(" ")))); EXPECT_TRUE(db.AddFormFieldValue(FormField(ASCIIToUTF16("blank"), + string16(), kValue))); // They should be stored normally as the DB layer does not check for empty diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 02c8668..de12db9 100755 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -786,6 +786,7 @@ '../third_party/bzip2/bzip2.gyp:bzip2', '../third_party/icu/icu.gyp:icui18n', '../third_party/icu/icu.gyp:icuuc', + '../third_party/libjingle/libjingle.gyp:libjingle', '../third_party/libxml/libxml.gyp:libxml', '../third_party/npapi/npapi.gyp:npapi', '../third_party/hunspell/hunspell.gyp:hunspell', @@ -842,10 +843,15 @@ 'browser/autocomplete/keyword_provider.h', 'browser/autocomplete/search_provider.cc', 'browser/autocomplete/search_provider.h', + 'browser/autofill/autofill_field.cc', + 'browser/autofill/autofill_field.h', 'browser/autofill/autofill_infobar_delegate.cc', 'browser/autofill/autofill_infobar_delegate.h', 'browser/autofill/autofill_manager.cc', 'browser/autofill/autofill_manager.h', + 'browser/autofill/field_types.h', + 'browser/autofill/form_structure.cc', + 'browser/autofill/form_structure.h', 'browser/automation/automation_autocomplete_edit_tracker.h', 'browser/automation/automation_browser_tracker.h', 'browser/automation/extension_automation_constants.h', diff --git a/chrome/common/render_messages.h b/chrome/common/render_messages.h index 2e4bd89..37f7e23 100644 --- a/chrome/common/render_messages.h +++ b/chrome/common/render_messages.h @@ -819,12 +819,14 @@ struct ParamTraits<webkit_glue::FormFieldValues> { typedef webkit_glue::FormFieldValues param_type; static void Write(Message* m, const param_type& p) { WriteParam(m, p.form_name); + WriteParam(m, p.method); WriteParam(m, p.source_url); WriteParam(m, p.target_url); WriteParam(m, p.elements.size()); std::vector<webkit_glue::FormField>::const_iterator itr; for (itr = p.elements.begin(); itr != p.elements.end(); itr++) { WriteParam(m, itr->name()); + WriteParam(m, itr->html_input_type()); WriteParam(m, itr->value()); } } @@ -832,16 +834,18 @@ struct ParamTraits<webkit_glue::FormFieldValues> { bool result = true; result = result && ReadParam(m, iter, &p->form_name) && + ReadParam(m, iter, &p->method) && ReadParam(m, iter, &p->source_url) && ReadParam(m, iter, &p->target_url); size_t elements_size = 0; result = result && ReadParam(m, iter, &elements_size); p->elements.resize(elements_size); for (size_t i = 0; i < elements_size; i++) { - string16 name, value; + string16 name, type, value; result = result && ReadParam(m, iter, &name); + result = result && ReadParam(m, iter, &type); result = result && ReadParam(m, iter, &value); - p->elements[i] = webkit_glue::FormField(name, value); + p->elements[i] = webkit_glue::FormField(name, type, value); } return result; } diff --git a/webkit/glue/form_field.cc b/webkit/glue/form_field.cc index 665f498..6d49054 100644 --- a/webkit/glue/form_field.cc +++ b/webkit/glue/form_field.cc @@ -10,8 +10,10 @@ FormField::FormField() { } FormField::FormField(const string16& name, + const string16& html_input_type, const string16& value) : name_(name), + html_input_type_(html_input_type), value_(value) { } diff --git a/webkit/glue/form_field.h b/webkit/glue/form_field.h index 224934d..92e8faea 100644 --- a/webkit/glue/form_field.h +++ b/webkit/glue/form_field.h @@ -14,15 +14,18 @@ class FormField { public: FormField(); FormField(const string16& name, + const string16& html_input_type, const string16& value); string16 name() const { return name_; } + string16 html_input_type() const { return html_input_type_; } string16 value() const { return value_; } void set_value(const string16& value) { value_ = value; } private: string16 name_; + string16 html_input_type_; string16 value_; }; diff --git a/webkit/glue/form_field_values.cc b/webkit/glue/form_field_values.cc index 1f9603f..5e2e32f 100644 --- a/webkit/glue/form_field_values.cc +++ b/webkit/glue/form_field_values.cc @@ -42,6 +42,7 @@ FormFieldValues* FormFieldValues::Create(const WebForm& webform) { FormFieldValues* result = new FormFieldValues(); result->form_name = StringToString16(form->name()); + result->method = StringToString16(form->method()); result->source_url = KURLToGURL(document->url()); result->target_url = KURLToGURL(document->completeURL(form->action())); result->ExtractFormFieldValues(webform); @@ -74,14 +75,18 @@ void FormFieldValues::ExtractFormFieldValues(const WebKit::WebForm& webform) { // For each TEXT input field, store the name and value string16 value = StringToString16(input_element->value()); TrimWhitespace(value, TRIM_LEADING, &value); - if (value.length() == 0) + if (value.empty()) continue; string16 name = StringToString16(WebKit::nameOfInputElement(input_element)); - if (name.length() == 0) + if (name.empty()) continue; // If we have no name, there is nothing to store. - elements.push_back(FormField(name, value)); + string16 type = StringToString16(input_element->formControlType()); + if (type.empty()) + continue; + + elements.push_back(FormField(name, type, value)); } } diff --git a/webkit/glue/form_field_values.h b/webkit/glue/form_field_values.h index c67f1e2..bd45499 100644 --- a/webkit/glue/form_field_values.h +++ b/webkit/glue/form_field_values.h @@ -26,6 +26,9 @@ class FormFieldValues { // The name of the form. string16 form_name; + // GET or POST. + string16 method; + // The source URL. GURL source_url; |