OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012 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 "chrome/browser/autofill/autocomplete_history_manager.h" | |
6 | |
7 #include <vector> | |
8 | |
9 #include "base/prefs/pref_service.h" | |
10 #include "base/string16.h" | |
11 #include "base/strings/string_number_conversions.h" | |
12 #include "base/utf_string_conversions.h" | |
13 #include "chrome/browser/autofill/autofill_external_delegate.h" | |
14 #include "chrome/browser/autofill/validation.h" | |
15 #include "components/autofill/common/autofill_messages.h" | |
16 #include "components/autofill/common/autofill_pref_names.h" | |
17 #include "components/autofill/common/form_data.h" | |
18 #include "components/user_prefs/user_prefs.h" | |
19 #include "content/public/browser/browser_context.h" | |
20 #include "content/public/browser/render_view_host.h" | |
21 #include "content/public/browser/web_contents.h" | |
22 | |
23 using base::StringPiece16; | |
24 using content::BrowserContext; | |
25 using content::WebContents; | |
26 | |
27 namespace { | |
28 | |
29 // Limit on the number of suggestions to appear in the pop-up menu under an | |
30 // text input element in a form. | |
31 const int kMaxAutocompleteMenuItems = 6; | |
32 | |
33 // The separator characters for SSNs. | |
34 const char16 kSSNSeparators[] = {' ', '-', 0}; | |
35 | |
36 bool IsSSN(const string16& text) { | |
37 string16 number_string; | |
38 RemoveChars(text, kSSNSeparators, &number_string); | |
39 | |
40 // A SSN is of the form AAA-GG-SSSS (A = area number, G = group number, S = | |
41 // serial number). The validation we do here is simply checking if the area, | |
42 // group, and serial numbers are valid. | |
43 // | |
44 // Historically, the area number was assigned per state, with the group number | |
45 // ascending in an alternating even/odd sequence. With that scheme it was | |
46 // possible to check for validity by referencing a table that had the highest | |
47 // group number assigned for a given area number. (This was something that | |
48 // Chromium never did though, because the "high group" values were constantly | |
49 // changing.) | |
50 // | |
51 // However, starting on 25 June 2011 the SSA began issuing SSNs randomly from | |
52 // all areas and groups. Group numbers and serial numbers of zero remain | |
53 // invalid, and areas 000, 666, and 900-999 remain invalid. | |
54 // | |
55 // References for current practices: | |
56 // http://www.socialsecurity.gov/employer/randomization.html | |
57 // http://www.socialsecurity.gov/employer/randomizationfaqs.html | |
58 // | |
59 // References for historic practices: | |
60 // http://www.socialsecurity.gov/history/ssn/geocard.html | |
61 // http://www.socialsecurity.gov/employer/stateweb.htm | |
62 // http://www.socialsecurity.gov/employer/ssnvhighgroup.htm | |
63 | |
64 if (number_string.length() != 9 || !IsStringASCII(number_string)) | |
65 return false; | |
66 | |
67 int area; | |
68 if (!base::StringToInt(StringPiece16(number_string.begin(), | |
69 number_string.begin() + 3), | |
70 &area)) { | |
71 return false; | |
72 } | |
73 if (area < 1 || | |
74 area == 666 || | |
75 area >= 900) { | |
76 return false; | |
77 } | |
78 | |
79 int group; | |
80 if (!base::StringToInt(StringPiece16(number_string.begin() + 3, | |
81 number_string.begin() + 5), | |
82 &group) | |
83 || group == 0) { | |
84 return false; | |
85 } | |
86 | |
87 int serial; | |
88 if (!base::StringToInt(StringPiece16(number_string.begin() + 5, | |
89 number_string.begin() + 9), | |
90 &serial) | |
91 || serial == 0) { | |
92 return false; | |
93 } | |
94 | |
95 return true; | |
96 } | |
97 | |
98 bool IsTextField(const FormFieldData& field) { | |
99 return | |
100 field.form_control_type == "text" || | |
101 field.form_control_type == "search" || | |
102 field.form_control_type == "tel" || | |
103 field.form_control_type == "url" || | |
104 field.form_control_type == "email" || | |
105 field.form_control_type == "text"; | |
106 } | |
107 | |
108 } // namespace | |
109 | |
110 AutocompleteHistoryManager::AutocompleteHistoryManager( | |
111 WebContents* web_contents) | |
112 : content::WebContentsObserver(web_contents), | |
113 browser_context_(web_contents->GetBrowserContext()), | |
114 autofill_data_( | |
115 AutofillWebDataService::FromBrowserContext(browser_context_)), | |
116 pending_query_handle_(0), | |
117 query_id_(0), | |
118 external_delegate_(NULL) { | |
119 autofill_enabled_.Init( | |
120 prefs::kAutofillEnabled, | |
121 components::UserPrefs::Get(browser_context_)); | |
122 } | |
123 | |
124 AutocompleteHistoryManager::~AutocompleteHistoryManager() { | |
125 CancelPendingQuery(); | |
126 } | |
127 | |
128 bool AutocompleteHistoryManager::OnMessageReceived( | |
129 const IPC::Message& message) { | |
130 bool handled = true; | |
131 IPC_BEGIN_MESSAGE_MAP(AutocompleteHistoryManager, message) | |
132 IPC_MESSAGE_HANDLER(AutofillHostMsg_RemoveAutocompleteEntry, | |
133 OnRemoveAutocompleteEntry) | |
134 IPC_MESSAGE_UNHANDLED(handled = false) | |
135 IPC_END_MESSAGE_MAP() | |
136 return handled; | |
137 } | |
138 | |
139 void AutocompleteHistoryManager::OnWebDataServiceRequestDone( | |
140 WebDataServiceBase::Handle h, | |
141 const WDTypedResult* result) { | |
142 DCHECK(pending_query_handle_); | |
143 pending_query_handle_ = 0; | |
144 | |
145 if (!*autofill_enabled_) { | |
146 SendSuggestions(NULL); | |
147 return; | |
148 } | |
149 | |
150 DCHECK(result); | |
151 // Returning early here if |result| is NULL. We've seen this happen on | |
152 // Linux due to NFS dismounting and causing sql failures. | |
153 // See http://crbug.com/68783. | |
154 if (!result) { | |
155 SendSuggestions(NULL); | |
156 return; | |
157 } | |
158 | |
159 DCHECK_EQ(AUTOFILL_VALUE_RESULT, result->GetType()); | |
160 const WDResult<std::vector<string16> >* autofill_result = | |
161 static_cast<const WDResult<std::vector<string16> >*>(result); | |
162 std::vector<string16> suggestions = autofill_result->GetValue(); | |
163 SendSuggestions(&suggestions); | |
164 } | |
165 | |
166 void AutocompleteHistoryManager::OnGetAutocompleteSuggestions( | |
167 int query_id, | |
168 const string16& name, | |
169 const string16& prefix, | |
170 const std::vector<string16>& autofill_values, | |
171 const std::vector<string16>& autofill_labels, | |
172 const std::vector<string16>& autofill_icons, | |
173 const std::vector<int>& autofill_unique_ids) { | |
174 CancelPendingQuery(); | |
175 | |
176 query_id_ = query_id; | |
177 autofill_values_ = autofill_values; | |
178 autofill_labels_ = autofill_labels; | |
179 autofill_icons_ = autofill_icons; | |
180 autofill_unique_ids_ = autofill_unique_ids; | |
181 if (!*autofill_enabled_) { | |
182 SendSuggestions(NULL); | |
183 return; | |
184 } | |
185 | |
186 if (autofill_data_.get()) { | |
187 pending_query_handle_ = autofill_data_->GetFormValuesForElementName( | |
188 name, prefix, kMaxAutocompleteMenuItems, this); | |
189 } | |
190 } | |
191 | |
192 void AutocompleteHistoryManager::OnFormSubmitted(const FormData& form) { | |
193 if (!*autofill_enabled_) | |
194 return; | |
195 | |
196 if (browser_context_->IsOffTheRecord()) | |
197 return; | |
198 | |
199 // Don't save data that was submitted through JavaScript. | |
200 if (!form.user_submitted) | |
201 return; | |
202 | |
203 // We put the following restriction on stored FormFields: | |
204 // - non-empty name | |
205 // - non-empty value | |
206 // - text field | |
207 // - value is not a credit card number | |
208 // - value is not a SSN | |
209 std::vector<FormFieldData> values; | |
210 for (std::vector<FormFieldData>::const_iterator iter = | |
211 form.fields.begin(); | |
212 iter != form.fields.end(); ++iter) { | |
213 if (!iter->value.empty() && | |
214 !iter->name.empty() && | |
215 IsTextField(*iter) && | |
216 !autofill::IsValidCreditCardNumber(iter->value) && | |
217 !IsSSN(iter->value)) { | |
218 values.push_back(*iter); | |
219 } | |
220 } | |
221 | |
222 if (!values.empty() && autofill_data_.get()) | |
223 autofill_data_->AddFormFields(values); | |
224 } | |
225 | |
226 void AutocompleteHistoryManager::OnRemoveAutocompleteEntry( | |
227 const string16& name, const string16& value) { | |
228 if (autofill_data_.get()) | |
229 autofill_data_->RemoveFormValueForElementName(name, value); | |
230 } | |
231 | |
232 void AutocompleteHistoryManager::SetExternalDelegate( | |
233 AutofillExternalDelegate* delegate) { | |
234 external_delegate_ = delegate; | |
235 } | |
236 | |
237 void AutocompleteHistoryManager::CancelPendingQuery() { | |
238 if (pending_query_handle_) { | |
239 if (autofill_data_) | |
240 autofill_data_->CancelRequest(pending_query_handle_); | |
241 pending_query_handle_ = 0; | |
242 } | |
243 } | |
244 | |
245 void AutocompleteHistoryManager::SendSuggestions( | |
246 const std::vector<string16>* suggestions) { | |
247 if (suggestions) { | |
248 // Combine Autofill and Autocomplete values into values and labels. | |
249 for (size_t i = 0; i < suggestions->size(); ++i) { | |
250 bool unique = true; | |
251 for (size_t j = 0; j < autofill_values_.size(); ++j) { | |
252 // Don't add duplicate values. | |
253 if (autofill_values_[j] == (*suggestions)[i]) { | |
254 unique = false; | |
255 break; | |
256 } | |
257 } | |
258 | |
259 if (unique) { | |
260 autofill_values_.push_back((*suggestions)[i]); | |
261 autofill_labels_.push_back(string16()); | |
262 autofill_icons_.push_back(string16()); | |
263 autofill_unique_ids_.push_back(0); // 0 means no profile. | |
264 } | |
265 } | |
266 } | |
267 | |
268 if (external_delegate_) { | |
269 external_delegate_->OnSuggestionsReturned( | |
270 query_id_, | |
271 autofill_values_, | |
272 autofill_labels_, | |
273 autofill_icons_, | |
274 autofill_unique_ids_); | |
275 } else { | |
276 Send(new AutofillMsg_SuggestionsReturned(routing_id(), | |
277 query_id_, | |
278 autofill_values_, | |
279 autofill_labels_, | |
280 autofill_icons_, | |
281 autofill_unique_ids_)); | |
282 } | |
283 | |
284 query_id_ = 0; | |
285 autofill_values_.clear(); | |
286 autofill_labels_.clear(); | |
287 autofill_icons_.clear(); | |
288 autofill_unique_ids_.clear(); | |
289 } | |
OLD | NEW |