summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgcasto@chromium.org <gcasto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-21 02:01:01 +0000
committergcasto@chromium.org <gcasto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-21 02:01:01 +0000
commit90ee092309f6b1b1b2c30d7f2b1cf61116bc757c (patch)
tree65bd1ac92c362535ad70f35699264c3ee1815c3f
parent9ccf5ec7ec6965e6fb0cffb3e8dbd3dc861c1f8a (diff)
downloadchromium_src-90ee092309f6b1b1b2c30d7f2b1cf61116bc757c.zip
chromium_src-90ee092309f6b1b1b2c30d7f2b1cf61116bc757c.tar.gz
chromium_src-90ee092309f6b1b1b2c30d7f2b1cf61116bc757c.tar.bz2
Add password generation browser UI for Windows.
The mocks that I am modeling this off of are located at http://dev.chromium.org/developers/design-documents/password-generation. You can see a screenshot of this implementation at http://www.corp.google.com/~gcasto/windows_ui.png There are two major differences between this implementation and the mocks. - Currently the bubble does not have a close button, but instead is closed when it loses focus. Doing it the other way requires constructing a native close button (which wasn't obvious to me) and controlling when to hide or move the UI (say when you switch tabs or move the browser window). - There is no clickable image to regenerate the password. This should be trivial once we have an image to use. Both of these can be added in a later CL. I also need to add some polish to the bubble (I don't like the font, not sure if I like the spacing, etc). Note that what I'm doing in the renderer right now is temporary until I get the shadow dom changes into WebKit. BUG=114092 TEST=Ran unittests Review URL: http://codereview.chromium.org/9704040 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@127879 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/autofill/autofill_manager.cc9
-rw-r--r--chrome/browser/autofill/autofill_manager.h1
-rw-r--r--chrome/browser/autofill/password_generator.cc26
-rw-r--r--chrome/browser/autofill/password_generator.h35
-rw-r--r--chrome/browser/autofill/password_generator_unittest.cc24
-rw-r--r--chrome/browser/ui/browser_window.h5
-rw-r--r--chrome/browser/ui/views/frame/browser_view.cc21
-rw-r--r--chrome/browser/ui/views/frame/browser_view.h1
-rw-r--r--chrome/browser/ui/views/password_generation_bubble_view.cc80
-rw-r--r--chrome/browser/ui/views/password_generation_bubble_view.h61
-rw-r--r--chrome/chrome_browser.gypi6
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/autofill_messages.h11
-rw-r--r--chrome/renderer/autofill/password_generation_manager.cc38
-rw-r--r--chrome/renderer/autofill/password_generation_manager.h14
-rw-r--r--chrome/renderer/autofill/password_generation_manager_browsertest.cc65
16 files changed, 379 insertions, 19 deletions
diff --git a/chrome/browser/autofill/autofill_manager.cc b/chrome/browser/autofill/autofill_manager.cc
index 571e05f3..7119d54 100644
--- a/chrome/browser/autofill/autofill_manager.cc
+++ b/chrome/browser/autofill/autofill_manager.cc
@@ -37,6 +37,7 @@
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
#include "chrome/common/autofill_messages.h"
#include "chrome/common/chrome_notification_types.h"
@@ -318,6 +319,8 @@ bool AutofillManager::OnMessageReceived(const IPC::Message& message) {
OnDidEndTextFieldEditing)
IPC_MESSAGE_HANDLER(AutofillHostMsg_HideAutofillPopup,
OnHideAutofillPopup)
+ IPC_MESSAGE_HANDLER(AutofillHostMsg_ShowPasswordGenerationPopup,
+ OnShowPasswordGenerationPopup)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
@@ -691,6 +694,12 @@ void AutofillManager::OnHideAutofillPopup() {
external_delegate_->HideAutofillPopup();
}
+void AutofillManager::OnShowPasswordGenerationPopup(const gfx::Rect& bounds) {
+ Browser* browser = BrowserList::GetLastActiveWithProfile(
+ Profile::FromBrowserContext(web_contents()->GetBrowserContext()));
+ browser->window()->ShowPasswordGenerationBubble(bounds);
+}
+
void AutofillManager::OnLoadedServerPredictions(
const std::string& response_xml) {
// Parse and store the server predictions.
diff --git a/chrome/browser/autofill/autofill_manager.h b/chrome/browser/autofill/autofill_manager.h
index f372819..b750703 100644
--- a/chrome/browser/autofill/autofill_manager.h
+++ b/chrome/browser/autofill/autofill_manager.h
@@ -82,6 +82,7 @@ class AutofillManager : public content::WebContentsObserver,
void OnDidFillAutofillFormData(const base::TimeTicks& timestamp);
void OnShowAutofillDialog();
void OnDidPreviewAutofillFormData();
+ void OnShowPasswordGenerationPopup(const gfx::Rect& bounds);
protected:
// Only test code should subclass AutofillManager.
diff --git a/chrome/browser/autofill/password_generator.cc b/chrome/browser/autofill/password_generator.cc
new file mode 100644
index 0000000..3361fb4
--- /dev/null
+++ b/chrome/browser/autofill/password_generator.cc
@@ -0,0 +1,26 @@
+// Copyright (c) 2012 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/password_generator.h"
+
+#include "base/rand_util.h"
+
+const int kMinChar = 33; // First printable character '!'
+const int kMaxChar = 126; // Last printable character '~'
+const int kPasswordLength = 12;
+
+namespace autofill {
+
+PasswordGenerator::PasswordGenerator() {}
+PasswordGenerator::~PasswordGenerator() {}
+
+std::string PasswordGenerator::Generate() {
+ std::string ret;
+ for (int i = 0; i < kPasswordLength; i++) {
+ ret.push_back(static_cast<char>(base::RandInt(kMinChar, kMaxChar)));
+ }
+ return ret;
+}
+
+} // namespace autofill
diff --git a/chrome/browser/autofill/password_generator.h b/chrome/browser/autofill/password_generator.h
new file mode 100644
index 0000000..0adbd43
--- /dev/null
+++ b/chrome/browser/autofill/password_generator.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2012 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_PASSWORD_GENERATOR_H_
+#define CHROME_BROWSER_AUTOFILL_PASSWORD_GENERATOR_H_
+#pragma once
+
+#include <string>
+
+#include "base/basictypes.h"
+
+namespace autofill {
+
+// Class to generate random passwords. Currently we just use a generic algorithm
+// for all sites, but eventually we can incorporate additional information to
+// determine passwords that are likely to be accepted (i.e. use pattern field,
+// previous generated passwords, crowdsourcing, etc.)
+class PasswordGenerator {
+ public:
+ PasswordGenerator();
+ ~PasswordGenerator();
+
+ // Returns a random password. The string is guaranteed to be printable and
+ // will not include whitespace characters.
+ std::string Generate();
+
+ private:
+
+ DISALLOW_COPY_AND_ASSIGN(PasswordGenerator);
+};
+
+} // namespace autofill
+
+#endif // CHROME_BROWSER_AUTOFILL_PASSWORD_GENERATOR_H_
diff --git a/chrome/browser/autofill/password_generator_unittest.cc b/chrome/browser/autofill/password_generator_unittest.cc
new file mode 100644
index 0000000..4efbc8b
--- /dev/null
+++ b/chrome/browser/autofill/password_generator_unittest.cc
@@ -0,0 +1,24 @@
+// Copyright (c) 2012 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 <locale>
+
+#include "chrome/browser/autofill/password_generator.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+
+TEST(PasswordGeneratorTest, PasswordGeneratorSimpleTest) {
+ // Not much to test, just make sure that the characters in a generated
+ // password are reasonable.
+ PasswordGenerator pg;
+ std::string password = pg.Generate();
+ for (size_t i = 0; i < password.size(); i++) {
+ // Make sure that the character is printable.
+ EXPECT_TRUE(isgraph(password[i]));
+ }
+}
+
+} // namespace autofill
diff --git a/chrome/browser/ui/browser_window.h b/chrome/browser/ui/browser_window.h
index f31a537..3d3851bb 100644
--- a/chrome/browser/ui/browser_window.h
+++ b/chrome/browser/ui/browser_window.h
@@ -352,6 +352,11 @@ class BrowserWindow : public BaseWindow {
// Shows the avatar bubble on the window frame off of the avatar button.
virtual void ShowAvatarBubbleFromAvatarButton() = 0;
+ // Show bubble for password generation positioned relative to |rect|. A stub
+ // implementation is provided since this feature is currently only available
+ // for Windows.
+ virtual void ShowPasswordGenerationBubble(const gfx::Rect& rect) {}
+
protected:
friend class BrowserList;
friend class BrowserView;
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 640babf..7f791b2 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -57,6 +57,7 @@
#include "chrome/browser/ui/views/fullscreen_exit_bubble_views.h"
#include "chrome/browser/ui/views/infobars/infobar_container_view.h"
#include "chrome/browser/ui/views/location_bar/location_icon_view.h"
+#include "chrome/browser/ui/views/password_generation_bubble_view.h"
#include "chrome/browser/ui/views/status_bubble_views.h"
#include "chrome/browser/ui/views/tab_contents/tab_contents_container.h"
#include "chrome/browser/ui/views/tabs/browser_tab_strip_controller.h"
@@ -2471,3 +2472,23 @@ void BrowserView::ShowAvatarBubbleFromAvatarButton() {
if (button)
button->ShowAvatarBubble();
}
+
+void BrowserView::ShowPasswordGenerationBubble(const gfx::Rect& rect) {
+ // Create a rect in the content bounds that the bubble will point to.
+ gfx::Point origin(rect.origin());
+ views::View::ConvertPointToScreen(GetTabContentsContainerView(), &origin);
+ gfx::Rect bounds(origin, rect.size());
+
+ // Create the bubble.
+ WebContents* web_contents = GetSelectedWebContents();
+ if (!web_contents)
+ return;
+
+ PasswordGenerationBubbleView* bubble =
+ new PasswordGenerationBubbleView(bounds,
+ this,
+ web_contents->GetRenderViewHost());
+ browser::CreateViewsBubble(bubble);
+ bubble->SetAlignment(views::BubbleBorder::ALIGN_EDGE_TO_ANCHOR_EDGE);
+ bubble->Show();
+}
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index d01e7b7..10104d4 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -324,6 +324,7 @@ class BrowserView : public BrowserWindow,
virtual void ShowAvatarBubble(content::WebContents* web_contents,
const gfx::Rect& rect) OVERRIDE;
virtual void ShowAvatarBubbleFromAvatarButton() OVERRIDE;
+ virtual void ShowPasswordGenerationBubble(const gfx::Rect& rect) OVERRIDE;
// Overridden from BrowserWindowTesting:
virtual BookmarkBarView* GetBookmarkBarView() const OVERRIDE;
diff --git a/chrome/browser/ui/views/password_generation_bubble_view.cc b/chrome/browser/ui/views/password_generation_bubble_view.cc
new file mode 100644
index 0000000..46404b4
--- /dev/null
+++ b/chrome/browser/ui/views/password_generation_bubble_view.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2012 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/ui/views/password_generation_bubble_view.h"
+
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/autofill/password_generator.h"
+#include "chrome/browser/ui/views/window.h"
+#include "chrome/common/autofill_messages.h"
+#include "content/public/browser/render_view_host.h"
+#include "ui/views/controls/button/text_button.h"
+#include "ui/views/controls/label.h"
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/layout/grid_layout.h"
+#include "ui/views/layout/layout_constants.h"
+
+using views::ColumnSet;
+using views::GridLayout;
+
+PasswordGenerationBubbleView::PasswordGenerationBubbleView(
+ const gfx::Rect& anchor_rect,
+ views::View* anchor_view,
+ content::RenderViewHost* render_view_host)
+ : BubbleDelegateView(anchor_view, views::BubbleBorder::TOP_LEFT),
+ accept_button_(NULL),
+ text_field_(NULL),
+ anchor_rect_(anchor_rect),
+ render_view_host_(render_view_host) {}
+
+PasswordGenerationBubbleView::~PasswordGenerationBubbleView() {}
+
+void PasswordGenerationBubbleView::Init() {
+ // TODO(gcasto): Localize text after we have finalized the UI.
+ // crbug.com/118062
+ accept_button_ = new views::NativeTextButton(this,
+ ASCIIToUTF16("Try It"));
+
+ text_field_ = new views::Textfield();
+ text_field_->SetText(ASCIIToUTF16(password_generator_.Generate()));
+
+ views::Label* title_label = new views::Label(
+ ASCIIToUTF16("Password Suggestion"));
+
+ GridLayout* layout = new GridLayout(this);
+ SetLayoutManager(layout);
+
+ // Title row.
+ ColumnSet* cs = layout->AddColumnSet(0);
+ cs->AddColumn(GridLayout::CENTER, GridLayout::CENTER, 0,
+ GridLayout::USE_PREF, 0, 0);
+
+ // Input row
+ cs = layout->AddColumnSet(1);
+ cs->AddColumn(GridLayout::FILL, GridLayout::CENTER, 0,
+ GridLayout::USE_PREF, 0, 100);
+ cs->AddPaddingColumn(1, views::kRelatedControlHorizontalSpacing);
+ cs->AddColumn(GridLayout::TRAILING, GridLayout::CENTER, 0,
+ GridLayout::USE_PREF, 0, 0);
+
+ layout->StartRow(0, 0);
+ layout->AddView(title_label);
+
+ layout->StartRow(0, 1);
+ layout->AddView(text_field_);
+ layout->AddView(accept_button_);
+}
+
+gfx::Rect PasswordGenerationBubbleView::GetAnchorRect() {
+ return anchor_rect_;
+}
+
+void PasswordGenerationBubbleView::ButtonPressed(views::Button* sender,
+ const views::Event& event) {
+ if (sender == accept_button_) {
+ render_view_host_->Send(new AutofillMsg_GeneratedPasswordAccepted(
+ render_view_host_->GetRoutingID(), text_field_->text()));
+ StartFade(false);
+ }
+}
diff --git a/chrome/browser/ui/views/password_generation_bubble_view.h b/chrome/browser/ui/views/password_generation_bubble_view.h
new file mode 100644
index 0000000..bce9aff
--- /dev/null
+++ b/chrome/browser/ui/views/password_generation_bubble_view.h
@@ -0,0 +1,61 @@
+// Copyright (c) 2012 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_UI_VIEWS_PASSWORD_GENERATION_BUBBLE_VIEW_H_
+#define CHROME_BROWSER_UI_VIEWS_PASSWORD_GENERATION_BUBBLE_VIEW_H_
+#pragma once
+
+#include "chrome/browser/autofill/password_generator.h"
+#include "ui/gfx/rect.h"
+#include "ui/views/bubble/bubble_delegate.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/view.h"
+
+namespace content {
+class RenderViewHost;
+}
+
+namespace views {
+class TextButton;
+class Textfield;
+}
+
+// PasswordGenerationBubbleView is a bubble used to show possible generated
+// passwords to users. It is set in the page content, anchored at |anchor_rect|.
+// If the generated password is accepted by the user, the renderer associated
+// with |render_view_host| is informed.
+class PasswordGenerationBubbleView : public views::BubbleDelegateView,
+ public views::ButtonListener {
+ public:
+ PasswordGenerationBubbleView(const gfx::Rect& anchor_rect,
+ views::View* anchor_view,
+ content::RenderViewHost* render_view_host);
+ virtual ~PasswordGenerationBubbleView();
+
+ private:
+ // views::BubbleDelegateView
+ virtual void Init() OVERRIDE;
+ virtual gfx::Rect GetAnchorRect() OVERRIDE;
+
+ // views::ButtonListener
+ virtual void ButtonPressed(views::Button* sender,
+ const views::Event& event) OVERRIDE;
+
+ // Subviews
+ views::TextButton* accept_button_;
+ views::Textfield* text_field_;
+
+ // Location that the bubble points to
+ gfx::Rect anchor_rect_;
+
+ // RenderViewHost associated with the button that spawned this bubble.
+ content::RenderViewHost* render_view_host_;
+
+ // Class to generate passwords
+ autofill::PasswordGenerator password_generator_;
+
+ DISALLOW_COPY_AND_ASSIGN(PasswordGenerationBubbleView);
+};
+
+#endif // CHROME_BROWSER_UI_VIEWS_PASSWORD_GENERATION_BUBBLE_VIEW_H_
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 7376d17..608190e 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -199,6 +199,8 @@
'browser/autofill/form_structure.h',
'browser/autofill/name_field.cc',
'browser/autofill/name_field.h',
+ 'browser/autofill/password_generator.cc',
+ 'browser/autofill/password_generator.h',
'browser/autofill/personal_data_manager.cc',
'browser/autofill/personal_data_manager.h',
'browser/autofill/personal_data_manager_factory.cc',
@@ -3470,6 +3472,8 @@
'browser/ui/views/one_click_signin_dialog_views.cc',
'browser/ui/views/page_info_bubble_view.cc',
'browser/ui/views/page_info_bubble_view.h',
+ 'browser/ui/views/password_generation_bubble_view.cc',
+ 'browser/ui/views/password_generation_bubble_view.h',
'browser/ui/views/reload_button.cc',
'browser/ui/views/reload_button.h',
'browser/ui/views/restart_message_box.cc',
@@ -4938,6 +4942,8 @@
['include', '^browser/ui/views/omnibox/omnibox_view_views.cc'],
['include', '^browser/ui/views/omnibox/omnibox_view_views.h'],
['include', '^browser/ui/views/page_info_bubble_view.cc'],
+ ['include', '^browser/ui/views/password_generation_bubble_view.cc'],
+ ['include', '^browser/ui/views/password_generation_bubble_view.h'],
['include', '^browser/ui/views/profile_tag_view.cc'],
['include', '^browser/ui/views/profile_tag_view.h'],
['include', '^browser/ui/views/reload_button.cc'],
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 64348c1..34ab8ee 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1276,6 +1276,7 @@
'browser/autofill/form_field_unittest.cc',
'browser/autofill/form_structure_unittest.cc',
'browser/autofill/name_field_unittest.cc',
+ 'browser/autofill/password_generator_unittest.cc',
'browser/autofill/personal_data_manager_unittest.cc',
'browser/autofill/phone_field_unittest.cc',
'browser/autofill/phone_number_unittest.cc',
diff --git a/chrome/common/autofill_messages.h b/chrome/common/autofill_messages.h
index d7a4b05..4542e49 100644
--- a/chrome/common/autofill_messages.h
+++ b/chrome/common/autofill_messages.h
@@ -111,6 +111,11 @@ IPC_MESSAGE_ROUTED0(AutofillMsg_ClearPreviewedForm)
IPC_MESSAGE_ROUTED1(AutofillMsg_SetNodeText,
string16)
+// Tells the renderer to populate the correct password fields with this
+// generated password.
+IPC_MESSAGE_ROUTED1(AutofillMsg_GeneratedPasswordAccepted,
+ string16 /* generated_password */)
+
// Autofill messages sent from the renderer to the browser.
// Notification that forms have been seen that are candidates for
@@ -181,3 +186,9 @@ IPC_MESSAGE_ROUTED0(AutofillHostMsg_DidEndTextFieldEditing)
// Instructs the browser to hide the Autofill popup.
IPC_MESSAGE_ROUTED0(AutofillHostMsg_HideAutofillPopup)
+
+// Instructs the browser to show the password generation bubble at the
+// specified location. This location should be specified in the renderers
+// coordinate system.
+IPC_MESSAGE_ROUTED1(AutofillHostMsg_ShowPasswordGenerationPopup,
+ gfx::Rect /* source location */)
diff --git a/chrome/renderer/autofill/password_generation_manager.cc b/chrome/renderer/autofill/password_generation_manager.cc
index f7c58cb..a5b7dc3 100644
--- a/chrome/renderer/autofill/password_generation_manager.cc
+++ b/chrome/renderer/autofill/password_generation_manager.cc
@@ -5,12 +5,15 @@
#include "chrome/renderer/autofill/password_generation_manager.h"
#include "base/logging.h"
+#include "chrome/common/autofill_messages.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebInputElement.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFormElement.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebRect.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebVector.h"
+#include "ui/gfx/rect.h"
namespace autofill {
@@ -66,16 +69,31 @@ bool PasswordGenerationManager::ShouldAnalyzeFrame(
void PasswordGenerationManager::FocusedNodeChanged(
const WebKit::WebNode& node) {
- if (account_creation_elements_.first ==
- node.toConst<WebKit::WebInputElement>()) {
- // Eventually we will show UI here and possibly fill the passwords
- // depending on the user interaction. For now, we will just say that the
- // associated passwords fields have been autocompleted to aid in testing.
- std::vector<WebKit::WebInputElement> passwords =
- account_creation_elements_.second;
- for (size_t i = 0; i < passwords.size(); ++i) {
- passwords[i].setAutofilled(true);
- }
+ WebKit::WebInputElement input_element =
+ node.toConst<WebKit::WebInputElement>();
+ if (account_creation_elements_.first == input_element) {
+ gfx::Rect rect(input_element.boundsInViewportSpace());
+ Send(new AutofillHostMsg_ShowPasswordGenerationPopup(routing_id(),
+ rect));
+ }
+}
+
+bool PasswordGenerationManager::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(PasswordGenerationManager, message)
+ IPC_MESSAGE_HANDLER(AutofillMsg_GeneratedPasswordAccepted,
+ OnPasswordAccepted)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void PasswordGenerationManager::OnPasswordAccepted(const string16& password) {
+ for (std::vector<WebKit::WebInputElement>::iterator it =
+ account_creation_elements_.second.begin();
+ it != account_creation_elements_.second.end(); ++it) {
+ it->setValue(password);
+ it->setAutofilled(true);
}
}
diff --git a/chrome/renderer/autofill/password_generation_manager.h b/chrome/renderer/autofill/password_generation_manager.h
index 9a35846..a93eedd 100644
--- a/chrome/renderer/autofill/password_generation_manager.h
+++ b/chrome/renderer/autofill/password_generation_manager.h
@@ -15,10 +15,11 @@
namespace autofill {
-// This class is responsible for controlling generation of passwords. We show
-// UI if we think that we are on an account creation or password change page,
-// and possibly generate and autofill passwords depending on user input.
-// Note that the UI hasn't been implemented yet.
+// This class is responsible for controlling communication for password
+// generation between the browser (which shows the popup and generates
+// passwords) and WebKit (determines which fields are for account signup and
+// fills in the generated passwords). Currently the WebKit part is not
+// implemented.
class PasswordGenerationManager : public content::RenderViewObserver {
public:
explicit PasswordGenerationManager(content::RenderView* render_view);
@@ -29,11 +30,16 @@ class PasswordGenerationManager : public content::RenderViewObserver {
// Virtual so that it can be overriden during testing.
virtual bool ShouldAnalyzeFrame(const WebKit::WebFrame& frame) const;
+ // RenderViewObserver:
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+
private:
// RenderViewObserver:
virtual void DidFinishDocumentLoad(WebKit::WebFrame* frame) OVERRIDE;
virtual void FocusedNodeChanged(const WebKit::WebNode& node) OVERRIDE;
+ void OnPasswordAccepted(const string16& password);
+
std::pair<WebKit::WebInputElement,
std::vector<WebKit::WebInputElement> > account_creation_elements_;
diff --git a/chrome/renderer/autofill/password_generation_manager_browsertest.cc b/chrome/renderer/autofill/password_generation_manager_browsertest.cc
index f66c365..72e612b 100644
--- a/chrome/renderer/autofill/password_generation_manager_browsertest.cc
+++ b/chrome/renderer/autofill/password_generation_manager_browsertest.cc
@@ -3,6 +3,9 @@
// found in the LICENSE file.
#include "base/memory/scoped_ptr.h"
+#include "base/memory/scoped_vector.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/common/autofill_messages.h"
#include "chrome/renderer/autofill/password_generation_manager.h"
#include "chrome/test/base/chrome_render_view_test.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -24,13 +27,29 @@ class TestPasswordGenerationManager : public PasswordGenerationManager {
: PasswordGenerationManager(view) {}
virtual ~TestPasswordGenerationManager() {}
+ // Make this public
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
+ return PasswordGenerationManager::OnMessageReceived(message);
+ }
+
+ const std::vector<IPC::Message*>& messages() {
+ return messages_.get();
+ }
+
protected:
virtual bool ShouldAnalyzeFrame(const WebKit::WebFrame& frame) const
OVERRIDE {
return true;
}
+ virtual bool Send(IPC::Message* message) OVERRIDE {
+ messages_.push_back(message);
+ return true;
+ }
+
private:
+ ScopedVector<IPC::Message> messages_;
+
DISALLOW_COPY_AND_ASSIGN(TestPasswordGenerationManager);
};
@@ -46,9 +65,10 @@ class PasswordGenerationManagerTest : public ChromeRenderViewTest {
generation_manager_.reset(new TestPasswordGenerationManager(view_));
}
- private:
- scoped_ptr<PasswordGenerationManager> generation_manager_;
+ protected:
+ scoped_ptr<TestPasswordGenerationManager> generation_manager_;
+ private:
DISALLOW_COPY_AND_ASSIGN(PasswordGenerationManagerTest);
};
@@ -67,7 +87,7 @@ TEST_F(PasswordGenerationManagerTest, DetectionTest) {
document.getElementById(WebString::fromUTF8("password"));
ASSERT_FALSE(element.isNull());
WebInputElement password_element = element.to<WebInputElement>();
- EXPECT_FALSE(password_element.isAutofilled());
+ EXPECT_EQ(0u, generation_manager_->messages().size());
const char kAccountCreationFormHTML[] =
"<FORM name = 'blah' action = 'www.random.com/'> "
@@ -83,14 +103,49 @@ TEST_F(PasswordGenerationManagerTest, DetectionTest) {
element = document.getElementById(WebString::fromUTF8("first_password"));
ASSERT_FALSE(element.isNull());
WebInputElement first_password_element = element.to<WebInputElement>();
- EXPECT_FALSE(first_password_element.isAutofilled());
+ EXPECT_EQ(0u, generation_manager_->messages().size());
element = document.getElementById(WebString::fromUTF8("second_password"));
ASSERT_FALSE(element.isNull());
WebInputElement second_password_element = element.to<WebInputElement>();
- EXPECT_FALSE(second_password_element.isAutofilled());
+ EXPECT_EQ(0u, generation_manager_->messages().size());
// After first element is focused, then we autofill.
SetFocused(first_password_element.to<WebNode>());
+ EXPECT_EQ(1u, generation_manager_->messages().size());
+ EXPECT_EQ(AutofillHostMsg_ShowPasswordGenerationPopup::ID,
+ generation_manager_->messages()[0]->type());
+}
+
+TEST_F(PasswordGenerationManagerTest, FillTest) {
+ const char kAccountCreationFormHTML[] =
+ "<FORM name = 'blah' action = 'www.random.com/'> "
+ " <INPUT type = 'text' id = 'username'/> "
+ " <INPUT type = 'password' id = 'first_password'/> "
+ " <INPUT type = 'password' id = 'second_password'/> "
+ " <INPUT type = 'submit' value = 'LOGIN' />"
+ "</FORM>";
+ LoadHTML(kAccountCreationFormHTML);
+
+ WebDocument document = GetMainFrame()->document();
+ WebElement element =
+ document.getElementById(WebString::fromUTF8("first_password"));
+ ASSERT_FALSE(element.isNull());
+ WebInputElement first_password_element = element.to<WebInputElement>();
+ element = document.getElementById(WebString::fromUTF8("second_password"));
+ ASSERT_FALSE(element.isNull());
+ WebInputElement second_password_element = element.to<WebInputElement>();
+
+ // Both password fields should be empty.
+ EXPECT_TRUE(first_password_element.value().isNull());
+ EXPECT_TRUE(second_password_element.value().isNull());
+
+ string16 password = ASCIIToUTF16("random_password");
+ AutofillMsg_GeneratedPasswordAccepted msg(0, password);
+ generation_manager_->OnMessageReceived(msg);
+
+ // Password fields are filled out and set as being autofilled.
+ EXPECT_EQ(password, first_password_element.value());
+ EXPECT_EQ(password, second_password_element.value());
EXPECT_TRUE(first_password_element.isAutofilled());
EXPECT_TRUE(second_password_element.isAutofilled());
}