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