Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(273)

Side by Side Diff: components/autofill/content/renderer/password_generation_agent.cc

Issue 151503006: Re-land r248110 with ASAN error fixed. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Punctuation Created 6 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/autofill/content/renderer/password_generation_agent.h" 5 #include "components/autofill/content/renderer/password_generation_agent.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/memory/scoped_ptr.h" 9 #include "base/memory/scoped_ptr.h"
10 #include "components/autofill/content/common/autofill_messages.h" 10 #include "components/autofill/content/common/autofill_messages.h"
11 #include "components/autofill/content/renderer/form_autofill_util.h"
11 #include "components/autofill/content/renderer/password_form_conversion_utils.h" 12 #include "components/autofill/content/renderer/password_form_conversion_utils.h"
12 #include "components/autofill/core/common/autofill_switches.h" 13 #include "components/autofill/core/common/autofill_switches.h"
13 #include "components/autofill/core/common/form_data.h" 14 #include "components/autofill/core/common/form_data.h"
14 #include "components/autofill/core/common/password_form.h" 15 #include "components/autofill/core/common/password_form.h"
15 #include "components/autofill/core/common/password_generation_util.h" 16 #include "components/autofill/core/common/password_generation_util.h"
16 #include "content/public/renderer/render_view.h" 17 #include "content/public/renderer/render_view.h"
17 #include "google_apis/gaia/gaia_urls.h" 18 #include "google_apis/gaia/gaia_urls.h"
18 #include "third_party/WebKit/public/platform/WebCString.h" 19 #include "third_party/WebKit/public/platform/WebCString.h"
19 #include "third_party/WebKit/public/platform/WebRect.h" 20 #include "third_party/WebKit/public/platform/WebRect.h"
20 #include "third_party/WebKit/public/platform/WebVector.h" 21 #include "third_party/WebKit/public/platform/WebVector.h"
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
91 return true; 92 return true;
92 } 93 }
93 return false; 94 return false;
94 } 95 }
95 96
96 } // namespace 97 } // namespace
97 98
98 PasswordGenerationAgent::PasswordGenerationAgent( 99 PasswordGenerationAgent::PasswordGenerationAgent(
99 content::RenderView* render_view) 100 content::RenderView* render_view)
100 : content::RenderViewObserver(render_view), 101 : content::RenderViewObserver(render_view),
101 render_view_(render_view) { 102 render_view_(render_view),
103 password_is_generated_(false),
104 password_edited_(false),
105 enabled_(password_generation::IsPasswordGenerationEnabled()) {
106 DVLOG(2) << "Password Generation is " << (enabled_ ? "Enabled" : "Disabled");
102 render_view_->GetWebView()->setPasswordGeneratorClient(this); 107 render_view_->GetWebView()->setPasswordGeneratorClient(this);
103 } 108 }
104 PasswordGenerationAgent::~PasswordGenerationAgent() {} 109 PasswordGenerationAgent::~PasswordGenerationAgent() {}
105 110
106 void PasswordGenerationAgent::DidFinishDocumentLoad(blink::WebFrame* frame) { 111 void PasswordGenerationAgent::DidFinishDocumentLoad(blink::WebFrame* frame) {
107 // In every navigation, the IPC message sent by the password autofill manager 112 // In every navigation, the IPC message sent by the password autofill manager
108 // to query whether the current form is blacklisted or not happens when the 113 // to query whether the current form is blacklisted or not happens when the
109 // document load finishes, so we need to clear previous states here before we 114 // document load finishes, so we need to clear previous states here before we
110 // hear back from the browser. We only clear this state on main frame load 115 // hear back from the browser. We only clear this state on main frame load
111 // as we don't want subframe loads to clear state that we have recieved from 116 // as we don't want subframe loads to clear state that we have received from
112 // the main frame. Note that we assume there is only one account creation 117 // the main frame. Note that we assume there is only one account creation
113 // form, but there could be multiple password forms in each frame. 118 // form, but there could be multiple password forms in each frame.
114 //
115 // TODO(zysxqn): Add stat when local heuristic fires but we don't show the
116 // password generation icon.
117 if (!frame->parent()) { 119 if (!frame->parent()) {
118 not_blacklisted_password_form_origins_.clear(); 120 not_blacklisted_password_form_origins_.clear();
119 generation_enabled_forms_.clear(); 121 generation_enabled_forms_.clear();
122 generation_element_.reset();
120 possible_account_creation_form_.reset(new PasswordForm()); 123 possible_account_creation_form_.reset(new PasswordForm());
121 passwords_.clear(); 124 password_elements_.clear();
125 password_is_generated_ = false;
126 if (password_edited_) {
127 password_generation::LogPasswordGenerationEvent(
128 password_generation::PASSWORD_EDITED);
129 }
130 password_edited_ = false;
122 } 131 }
123 } 132 }
124 133
125 void PasswordGenerationAgent::DidFinishLoad(blink::WebFrame* frame) { 134 void PasswordGenerationAgent::DidFinishLoad(blink::WebFrame* frame) {
135 if (!enabled_)
136 return;
137
126 // We don't want to generate passwords if the browser won't store or sync 138 // We don't want to generate passwords if the browser won't store or sync
127 // them. 139 // them.
128 if (!ShouldAnalyzeDocument(frame->document())) 140 if (!ShouldAnalyzeDocument(frame->document()))
129 return; 141 return;
130 142
131 blink::WebVector<blink::WebFormElement> forms; 143 blink::WebVector<blink::WebFormElement> forms;
132 frame->document().forms(forms); 144 frame->document().forms(forms);
133 for (size_t i = 0; i < forms.size(); ++i) { 145 for (size_t i = 0; i < forms.size(); ++i) {
134 if (forms[i].isNull()) 146 if (forms[i].isNull())
135 continue; 147 continue;
(...skipping 11 matching lines...) Expand all
147 // generated paswords. 159 // generated paswords.
148 GURL realm(password_form->signon_realm); 160 GURL realm(password_form->signon_realm);
149 if (realm == GaiaUrls::GetInstance()->gaia_login_form_realm()) 161 if (realm == GaiaUrls::GetInstance()->gaia_login_form_realm())
150 continue; 162 continue;
151 163
152 std::vector<blink::WebInputElement> passwords; 164 std::vector<blink::WebInputElement> passwords;
153 if (GetAccountCreationPasswordFields(forms[i], &passwords)) { 165 if (GetAccountCreationPasswordFields(forms[i], &passwords)) {
154 DVLOG(2) << "Account creation form detected"; 166 DVLOG(2) << "Account creation form detected";
155 password_generation::LogPasswordGenerationEvent( 167 password_generation::LogPasswordGenerationEvent(
156 password_generation::SIGN_UP_DETECTED); 168 password_generation::SIGN_UP_DETECTED);
157 passwords_ = passwords; 169 password_elements_ = passwords;
158 possible_account_creation_form_.swap(password_form); 170 possible_account_creation_form_.swap(password_form);
159 MaybeShowIcon(); 171 DetermineGenerationElement();
160 // We assume that there is only one account creation field per URL. 172 // We assume that there is only one account creation field per URL.
161 return; 173 return;
162 } 174 }
163 } 175 }
164 password_generation::LogPasswordGenerationEvent( 176 password_generation::LogPasswordGenerationEvent(
165 password_generation::NO_SIGN_UP_DETECTED); 177 password_generation::NO_SIGN_UP_DETECTED);
166 } 178 }
167 179
168 bool PasswordGenerationAgent::ShouldAnalyzeDocument( 180 bool PasswordGenerationAgent::ShouldAnalyzeDocument(
169 const blink::WebDocument& document) const { 181 const blink::WebDocument& document) const {
(...skipping 14 matching lines...) Expand all
184 gfx::Rect rect(button.boundsInViewportSpace()); 196 gfx::Rect rect(button.boundsInViewportSpace());
185 scoped_ptr<PasswordForm> password_form( 197 scoped_ptr<PasswordForm> password_form(
186 CreatePasswordForm(element.form())); 198 CreatePasswordForm(element.form()));
187 // We should not have shown the icon we can't create a valid PasswordForm. 199 // We should not have shown the icon we can't create a valid PasswordForm.
188 DCHECK(password_form.get()); 200 DCHECK(password_form.get());
189 201
190 Send(new AutofillHostMsg_ShowPasswordGenerationPopup(routing_id(), 202 Send(new AutofillHostMsg_ShowPasswordGenerationPopup(routing_id(),
191 rect, 203 rect,
192 element.maxLength(), 204 element.maxLength(),
193 *password_form)); 205 *password_form));
194 password_generation::LogPasswordGenerationEvent(
195 password_generation::BUBBLE_SHOWN);
196 } 206 }
197 207
198 bool PasswordGenerationAgent::OnMessageReceived(const IPC::Message& message) { 208 bool PasswordGenerationAgent::OnMessageReceived(const IPC::Message& message) {
199 bool handled = true; 209 bool handled = true;
200 IPC_BEGIN_MESSAGE_MAP(PasswordGenerationAgent, message) 210 IPC_BEGIN_MESSAGE_MAP(PasswordGenerationAgent, message)
201 IPC_MESSAGE_HANDLER(AutofillMsg_FormNotBlacklisted, 211 IPC_MESSAGE_HANDLER(AutofillMsg_FormNotBlacklisted,
202 OnFormNotBlacklisted) 212 OnFormNotBlacklisted)
203 IPC_MESSAGE_HANDLER(AutofillMsg_GeneratedPasswordAccepted, 213 IPC_MESSAGE_HANDLER(AutofillMsg_GeneratedPasswordAccepted,
204 OnPasswordAccepted) 214 OnPasswordAccepted)
205 IPC_MESSAGE_HANDLER(AutofillMsg_AccountCreationFormsDetected, 215 IPC_MESSAGE_HANDLER(AutofillMsg_AccountCreationFormsDetected,
206 OnAccountCreationFormsDetected) 216 OnAccountCreationFormsDetected)
207 IPC_MESSAGE_UNHANDLED(handled = false) 217 IPC_MESSAGE_UNHANDLED(handled = false)
208 IPC_END_MESSAGE_MAP() 218 IPC_END_MESSAGE_MAP()
209 return handled; 219 return handled;
210 } 220 }
211 221
212 void PasswordGenerationAgent::OnFormNotBlacklisted(const PasswordForm& form) { 222 void PasswordGenerationAgent::OnFormNotBlacklisted(const PasswordForm& form) {
213 not_blacklisted_password_form_origins_.push_back(form.origin); 223 not_blacklisted_password_form_origins_.push_back(form.origin);
214 MaybeShowIcon(); 224 DetermineGenerationElement();
215 } 225 }
216 226
217 void PasswordGenerationAgent::OnPasswordAccepted( 227 void PasswordGenerationAgent::OnPasswordAccepted(
218 const base::string16& password) { 228 const base::string16& password) {
219 for (std::vector<blink::WebInputElement>::iterator it = passwords_.begin(); 229 password_is_generated_ = true;
220 it != passwords_.end(); ++it) { 230 password_generation::LogPasswordGenerationEvent(
231 password_generation::PASSWORD_ACCEPTED);
232 for (std::vector<blink::WebInputElement>::iterator it =
233 password_elements_.begin();
234 it != password_elements_.end(); ++it) {
221 it->setValue(password); 235 it->setValue(password);
222 it->setAutofilled(true); 236 it->setAutofilled(true);
223 // Advance focus to the next input field. We assume password fields in 237 // Advance focus to the next input field. We assume password fields in
224 // an account creation form are always adjacent. 238 // an account creation form are always adjacent.
225 render_view_->GetWebView()->advanceFocus(false); 239 render_view_->GetWebView()->advanceFocus(false);
226 } 240 }
227 } 241 }
228 242
229 void PasswordGenerationAgent::OnAccountCreationFormsDetected( 243 void PasswordGenerationAgent::OnAccountCreationFormsDetected(
230 const std::vector<autofill::FormData>& forms) { 244 const std::vector<autofill::FormData>& forms) {
231 generation_enabled_forms_.insert( 245 generation_enabled_forms_.insert(
232 generation_enabled_forms_.end(), forms.begin(), forms.end()); 246 generation_enabled_forms_.end(), forms.begin(), forms.end());
233 MaybeShowIcon(); 247 DetermineGenerationElement();
234 } 248 }
235 249
236 void PasswordGenerationAgent::MaybeShowIcon() { 250 void PasswordGenerationAgent::DetermineGenerationElement() {
237 // Make sure local heuristics have identified a possible account creation 251 // Make sure local heuristics have identified a possible account creation
238 // form. 252 // form.
239 if (!possible_account_creation_form_.get() || passwords_.empty()) { 253 if (!possible_account_creation_form_.get() || password_elements_.empty()) {
240 DVLOG(2) << "Local hueristics have not detected a possible account " 254 DVLOG(2) << "Local hueristics have not detected a possible account "
241 << "creation form"; 255 << "creation form";
242 return; 256 return;
243 } 257 }
244 258
245 // Verify that it's not blacklisted. 259 if (CommandLine::ForCurrentProcess()->HasSwitch(
246 if (not_blacklisted_password_form_origins_.empty() || 260 switches::kLocalHeuristicsOnlyForPasswordGeneration)) {
247 !ContainsURL(not_blacklisted_password_form_origins_, 261 DVLOG(2) << "Bypassing additional checks.";
248 possible_account_creation_form_->origin)) { 262 } else if (not_blacklisted_password_form_origins_.empty() ||
249 DVLOG(2) << "Have not recieved confirmation that password form isn't " 263 !ContainsURL(not_blacklisted_password_form_origins_,
264 possible_account_creation_form_->origin)) {
265 DVLOG(2) << "Have not received confirmation that password form isn't "
250 << "blacklisted"; 266 << "blacklisted";
251 return; 267 return;
268 } else if (generation_enabled_forms_.empty() ||
269 !ContainsForm(generation_enabled_forms_,
270 *possible_account_creation_form_)) {
271 // Note that this message will never be sent if this feature is disabled
272 // (e.g. Password saving is disabled).
273 DVLOG(2) << "Have not received confirmation from Autofill that form is "
274 << "used for account creation";
275 return;
252 } 276 }
253 277
254 // Ensure that we get a ping from Autofill saying that this form is used for 278 DVLOG(2) << "Password generation eligible form found";
255 // account creation. Note that this message will not be set if this feature 279 generation_element_ = password_elements_[0];
256 // is not enabled. If kNoAutofillNecessaryForPasswordGeneration is set, 280 password_generation::LogPasswordGenerationEvent(
257 // skip this check. This switch should only be used in testing environments. 281 password_generation::GENERATION_AVAILABLE);
258 if (!CommandLine::ForCurrentProcess()->HasSwitch( 282 }
259 switches::kNoAutofillNecessaryForPasswordGeneration) && 283
260 (generation_enabled_forms_.empty() || 284 void PasswordGenerationAgent::FocusedNodeChanged(const blink::WebNode& node) {
261 !ContainsForm(generation_enabled_forms_, 285 // TODO(gcasto): Re-hide generation_element text.
262 *possible_account_creation_form_))) { 286 if (node.isNull() || !node.isElementNode())
263 DVLOG(2) << "Have not recieved confirmation from Autofill that form is used"
264 << " for account creation";
265 return; 287 return;
288
289 const blink::WebElement web_element = node.toConst<blink::WebElement>();
290 if (!web_element.document().frame())
291 return;
292
293 const blink::WebInputElement* element = toWebInputElement(&web_element);
294 if (!element || *element != generation_element_)
295 return;
296
297 if (password_is_generated_) {
298 // TODO(gcasto): Make characters visible.
299 ShowEditingPopup();
266 } 300 }
267 301
268 passwords_[0].passwordGeneratorButtonElement().setAttribute("style", 302 // Only trigger if the password field is empty.
269 "display:block"); 303 if (!element->isReadOnly() &&
304 element->isEnabled() &&
305 element->value().isEmpty()) {
306 ShowGenerationPopup();
307 }
308 }
309
310 bool PasswordGenerationAgent::TextDidChangeInTextField(
311 const blink::WebInputElement& element) {
312 if (element != generation_element_)
313 return false;
314
315 if (element.value().isEmpty()) {
316 if (password_is_generated_) {
317 // User generated a password and then deleted it.
318 password_generation::LogPasswordGenerationEvent(
319 password_generation::PASSWORD_DELETED);
320 }
321
322 // TODO(gcasto): Set PasswordForm::type in the browser to TYPE_NORMAL.
323 password_is_generated_ = false;
324 // Offer generation again.
325 ShowGenerationPopup();
326 } else if (!password_is_generated_) {
327 // User has rejected the feature and has started typing a password.
328 HidePopup();
329 } else {
330 password_edited_ = true;
331 // Mirror edits to any confirmation password fields.
332 for (std::vector<blink::WebInputElement>::iterator it =
333 password_elements_.begin();
334 it != password_elements_.end(); ++it) {
335 it->setValue(element.value());
336 }
337 }
338
339 return true;
340 }
341
342 void PasswordGenerationAgent::ShowGenerationPopup() {
343 gfx::RectF bounding_box_scaled =
344 GetScaledBoundingBox(render_view_->GetWebView()->pageScaleFactor(),
345 &generation_element_);
346
347 Send(new AutofillHostMsg_ShowPasswordGenerationPopup(
348 routing_id(),
349 bounding_box_scaled,
350 generation_element_.maxLength(),
351 *possible_account_creation_form_));
352
270 password_generation::LogPasswordGenerationEvent( 353 password_generation::LogPasswordGenerationEvent(
271 password_generation::ICON_SHOWN); 354 password_generation::GENERATION_POPUP_SHOWN);
355 }
356
357 void PasswordGenerationAgent::ShowEditingPopup() {
358 gfx::RectF bounding_box_scaled =
359 GetScaledBoundingBox(render_view_->GetWebView()->pageScaleFactor(),
360 &generation_element_);
361
362 Send(new AutofillHostMsg_ShowPasswordEditingPopup(routing_id(),
363 bounding_box_scaled));
364
365 password_generation::LogPasswordGenerationEvent(
366 password_generation::EDITING_POPUP_SHOWN);
367 }
368
369 void PasswordGenerationAgent::HidePopup() {
370 Send(new AutofillHostMsg_HidePasswordGenerationPopup(routing_id()));
272 } 371 }
273 372
274 } // namespace autofill 373 } // namespace autofill
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698