diff options
author | gcasto@chromium.org <gcasto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-21 02:01:01 +0000 |
---|---|---|
committer | gcasto@chromium.org <gcasto@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-21 02:01:01 +0000 |
commit | 90ee092309f6b1b1b2c30d7f2b1cf61116bc757c (patch) | |
tree | 65bd1ac92c362535ad70f35699264c3ee1815c3f | |
parent | 9ccf5ec7ec6965e6fb0cffb3e8dbd3dc861c1f8a (diff) | |
download | chromium_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.cc | 9 | ||||
-rw-r--r-- | chrome/browser/autofill/autofill_manager.h | 1 | ||||
-rw-r--r-- | chrome/browser/autofill/password_generator.cc | 26 | ||||
-rw-r--r-- | chrome/browser/autofill/password_generator.h | 35 | ||||
-rw-r--r-- | chrome/browser/autofill/password_generator_unittest.cc | 24 | ||||
-rw-r--r-- | chrome/browser/ui/browser_window.h | 5 | ||||
-rw-r--r-- | chrome/browser/ui/views/frame/browser_view.cc | 21 | ||||
-rw-r--r-- | chrome/browser/ui/views/frame/browser_view.h | 1 | ||||
-rw-r--r-- | chrome/browser/ui/views/password_generation_bubble_view.cc | 80 | ||||
-rw-r--r-- | chrome/browser/ui/views/password_generation_bubble_view.h | 61 | ||||
-rw-r--r-- | chrome/chrome_browser.gypi | 6 | ||||
-rw-r--r-- | chrome/chrome_tests.gypi | 1 | ||||
-rw-r--r-- | chrome/common/autofill_messages.h | 11 | ||||
-rw-r--r-- | chrome/renderer/autofill/password_generation_manager.cc | 38 | ||||
-rw-r--r-- | chrome/renderer/autofill/password_generation_manager.h | 14 | ||||
-rw-r--r-- | chrome/renderer/autofill/password_generation_manager_browsertest.cc | 65 |
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()); } |