1 // Copyright 2016 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 "components/autofill/core/common/signatures.h"
6 
7 #include <cctype>
8 
9 #include "base/hash/sha1.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "build/build_config.h"
13 #include "components/autofill/core/common/autofill_util.h"
14 #include "components/autofill/core/common/form_data.h"
15 #include "components/autofill/core/common/form_field_data.h"
16 #include "url/gurl.h"
17 
18 using base::UTF16ToUTF8;
19 
20 namespace autofill {
21 
22 namespace {
23 
24 // Returns a copy of |input| without >= 5 consecutive digits.
StripDigitsIfRequired(const base::string16 & input)25 std::string StripDigitsIfRequired(const base::string16& input) {
26   std::string input_utf8 = UTF16ToUTF8(input);
27   std::string result;
28   result.reserve(input_utf8.length());
29 
30   for (size_t i = 0; i < input_utf8.length();) {
31     if (std::isdigit(input_utf8[i])) {
32       size_t count = 0;
33       while (i < input_utf8.length() && std::isdigit(input_utf8[i])) {
34         i++;
35         count++;
36       }
37       if (count < 5)
38         result.append(input_utf8, i - count, count);
39     } else {
40       result.push_back(input_utf8[i]);
41       i++;
42     }
43   }
44   return result;
45 }
46 
47 }  // namespace
48 
49 // If a form name was set by Chrome, we should ignore it when calculating
50 // the form signature.
GetDOMFormName(const std::string & form_name)51 std::string GetDOMFormName(const std::string& form_name) {
52 #if defined(OS_IOS)
53   // In case of an empty form name, the synthetic name is created. Ignore it.
54   return (StartsWith(form_name, "gChrome~form~", base::CompareCase::SENSITIVE)
55               ? std::string()
56               : form_name);
57 #else
58   return form_name;
59 #endif
60 }
61 
CalculateFormSignature(const FormData & form_data)62 FormSignature CalculateFormSignature(const FormData& form_data) {
63   const GURL& target_url = form_data.action;
64   const GURL& source_url = form_data.url;
65   std::string scheme(target_url.scheme());
66   std::string host(target_url.host());
67 
68   // If target host or scheme is empty, set scheme and host of source url.
69   // This is done to match the Toolbar's behavior.
70   if (scheme.empty() || host.empty()) {
71     scheme = source_url.scheme();
72     host = source_url.host();
73   }
74 
75   std::string form_signature_field_names;
76 
77   for (const FormFieldData& field : form_data.fields) {
78     if (!ShouldSkipField(field)) {
79       // Add all supported form fields (including with empty names) to the
80       // signature.  This is a requirement for Autofill servers.
81       form_signature_field_names.append("&");
82       form_signature_field_names.append(StripDigitsIfRequired(field.name));
83     }
84   }
85 
86   std::string form_name = GetDOMFormName(UTF16ToUTF8(form_data.name));
87   std::string form_string =
88       scheme + "://" + host + "&" + form_name + form_signature_field_names;
89 
90   return FormSignature(StrToHash64Bit(form_string));
91 }
92 
CalculateFieldSignatureByNameAndType(const base::string16 & field_name,const std::string & field_type)93 FieldSignature CalculateFieldSignatureByNameAndType(
94     const base::string16& field_name,
95     const std::string& field_type) {
96   std::string name = UTF16ToUTF8(field_name);
97   std::string field_string = name + "&" + field_type;
98   return FieldSignature(StrToHash32Bit(field_string));
99 }
100 
CalculateFieldSignatureForField(const FormFieldData & field_data)101 FieldSignature CalculateFieldSignatureForField(
102     const FormFieldData& field_data) {
103   return CalculateFieldSignatureByNameAndType(field_data.name,
104                                               field_data.form_control_type);
105 }
106 
StrToHash64Bit(const std::string & str)107 uint64_t StrToHash64Bit(const std::string& str) {
108   std::string hash_bin = base::SHA1HashString(str);
109   DCHECK_EQ(base::kSHA1Length, hash_bin.length());
110 
111   uint64_t hash64 = (((static_cast<uint64_t>(hash_bin[0])) & 0xFF) << 56) |
112                     (((static_cast<uint64_t>(hash_bin[1])) & 0xFF) << 48) |
113                     (((static_cast<uint64_t>(hash_bin[2])) & 0xFF) << 40) |
114                     (((static_cast<uint64_t>(hash_bin[3])) & 0xFF) << 32) |
115                     (((static_cast<uint64_t>(hash_bin[4])) & 0xFF) << 24) |
116                     (((static_cast<uint64_t>(hash_bin[5])) & 0xFF) << 16) |
117                     (((static_cast<uint64_t>(hash_bin[6])) & 0xFF) << 8) |
118                     ((static_cast<uint64_t>(hash_bin[7])) & 0xFF);
119 
120   return hash64;
121 }
122 
StrToHash32Bit(const std::string & str)123 uint32_t StrToHash32Bit(const std::string& str) {
124   std::string hash_bin = base::SHA1HashString(str);
125   DCHECK_EQ(base::kSHA1Length, hash_bin.length());
126 
127   uint32_t hash32 = ((hash_bin[0] & 0xFF) << 24) |
128                     ((hash_bin[1] & 0xFF) << 16) | ((hash_bin[2] & 0xFF) << 8) |
129                     (hash_bin[3] & 0xFF);
130 
131   return hash32;
132 }
133 
HashFormSignature(autofill::FormSignature form_signature)134 int64_t HashFormSignature(autofill::FormSignature form_signature) {
135   return static_cast<uint64_t>(form_signature.value()) % 1021;
136 }
137 
HashFieldSignature(autofill::FieldSignature field_signature)138 int64_t HashFieldSignature(autofill::FieldSignature field_signature) {
139   return static_cast<uint64_t>(field_signature.value()) % 1021;
140 }
141 
142 }  // namespace autofill
143