diff options
Diffstat (limited to 'chrome/browser')
5 files changed, 220 insertions, 11 deletions
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc index b8643fb..c908c09 100644 --- a/chrome/browser/extensions/extension_function_dispatcher.cc +++ b/chrome/browser/extensions/extension_function_dispatcher.cc @@ -278,10 +278,11 @@ void FactoryRegistry::ResetFunctions() { RegisterFunction<UninstallFunction>(); // WebstorePrivate. - RegisterFunction<GetSyncLoginFunction>(); + RegisterFunction<GetBrowserLoginFunction>(); RegisterFunction<GetStoreLoginFunction>(); RegisterFunction<InstallFunction>(); RegisterFunction<SetStoreLoginFunction>(); + RegisterFunction<PromptBrowserLoginFunction>(); } void FactoryRegistry::GetAllNames(std::vector<std::string>* names) { diff --git a/chrome/browser/extensions/extension_webstore_private_api.cc b/chrome/browser/extensions/extension_webstore_private_api.cc index f18c2d5..8f1a33b 100644 --- a/chrome/browser/extensions/extension_webstore_private_api.cc +++ b/chrome/browser/extensions/extension_webstore_private_api.cc @@ -18,6 +18,9 @@ namespace { const char* install_base_url = extension_urls::kGalleryUpdateHttpsUrl; +const char kAlreadyLoggedInError[] = "User already logged in"; +const char kLoginKey[] = "login"; +ProfileSyncService* test_sync_service = NULL; bool IsWebStoreURL(Profile* profile, const GURL& url) { ExtensionsService* service = profile->GetExtensionsService(); @@ -26,7 +29,7 @@ bool IsWebStoreURL(Profile* profile, const GURL& url) { return (service->GetExtensionByWebExtent(url) == store); } -} +} // namespace // static void InstallFunction::SetTestingInstallBaseUrl( @@ -67,12 +70,15 @@ bool InstallFunction::RunImpl() { return true; } -bool GetSyncLoginFunction::RunImpl() { +bool GetBrowserLoginFunction::RunImpl() { if (!IsWebStoreURL(profile_, source_url())) return false; ProfileSyncService* sync_service = profile_->GetProfileSyncService(); string16 username = sync_service->GetAuthenticatedUsername(); - result_.reset(Value::CreateStringValue(username)); + ListValue* list = new ListValue(); + // TODO(asargent) - send the browser login token here too if available. + list->Append(Value::CreateStringValue(username)); + result_.reset(list); return true; } @@ -100,3 +106,67 @@ bool SetStoreLoginFunction::RunImpl() { prefs->SetWebStoreLogin(login); return true; } + +// static +void PromptBrowserLoginFunction::SetTestingProfileSyncService( + ProfileSyncService* service) { + test_sync_service = service; +} + +ProfileSyncService* PromptBrowserLoginFunction::profile_sync_service() { + if (test_sync_service) + return test_sync_service; + else + return profile_->GetProfileSyncService(); +} + +PromptBrowserLoginFunction::~PromptBrowserLoginFunction() { + if (observing_sync_state_) + profile_sync_service()->RemoveObserver(this); +} + +bool PromptBrowserLoginFunction::RunImpl() { + if (!IsWebStoreURL(profile_, source_url())) + return false; + + std::string preferred_email; + ProfileSyncService* sync_service = profile_sync_service(); + if (args_->GetSize() > 0) { + EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &preferred_email)); + if (!sync_service->GetAuthenticatedUsername().empty()) { + error_ = kAlreadyLoggedInError; + return false; + } + } + + // We return the result asynchronously, so we addref to keep ourself alive. + // Matched with a Release in OnStateChanged(). + AddRef(); + + observing_sync_state_ = true; + sync_service->AddObserver(this); + // TODO(mirandac/estade) - make use of |preferred_email| to pre-populate the + // browser login dialog if it was set to non-empty above. + sync_service->ShowLoginDialog(NULL); + + // The response will be sent asynchronously in OnStateChanged(). + return true; +} + +void PromptBrowserLoginFunction::OnStateChanged() { + ProfileSyncService* sync_service = profile_sync_service(); + // If the setup is finished, we'll report back what happened. + if (!sync_service->SetupInProgress()) { + DictionaryValue* dictionary = new DictionaryValue(); + + // TODO(asargent) - send the browser login token here too if available. + string16 username = sync_service->GetAuthenticatedUsername(); + dictionary->SetString(kLoginKey, username); + + result_.reset(dictionary); + SendResponse(true); + + // Matches the AddRef in RunImpl(). + Release(); + } +} diff --git a/chrome/browser/extensions/extension_webstore_private_api.h b/chrome/browser/extensions/extension_webstore_private_api.h index 0ba27ac..4da35cf 100644 --- a/chrome/browser/extensions/extension_webstore_private_api.h +++ b/chrome/browser/extensions/extension_webstore_private_api.h @@ -2,11 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_WEBSTORE_PRIVATE_API_H__ -#define CHROME_BROWSER_EXTENSIONS_EXTENSION_WEBSTORE_PRIVATE_API_H__ +#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_WEBSTORE_PRIVATE_API_H_ +#define CHROME_BROWSER_EXTENSIONS_EXTENSION_WEBSTORE_PRIVATE_API_H_ #pragma once #include "chrome/browser/extensions/extension_function.h" +#include "chrome/browser/sync/profile_sync_service_observer.h" + +class ProfileSyncService; class InstallFunction : public SyncExtensionFunction { public: @@ -18,9 +21,9 @@ class InstallFunction : public SyncExtensionFunction { DECLARE_EXTENSION_FUNCTION_NAME("webstorePrivate.install"); }; -class GetSyncLoginFunction : public SyncExtensionFunction { +class GetBrowserLoginFunction : public SyncExtensionFunction { virtual bool RunImpl(); - DECLARE_EXTENSION_FUNCTION_NAME("webstorePrivate.getSyncLogin"); + DECLARE_EXTENSION_FUNCTION_NAME("webstorePrivate.getBrowserLogin"); }; class GetStoreLoginFunction : public SyncExtensionFunction { @@ -33,4 +36,30 @@ class SetStoreLoginFunction : public SyncExtensionFunction { DECLARE_EXTENSION_FUNCTION_NAME("webstorePrivate.setStoreLogin"); }; -#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_WEBSTORE_PRIVATE_API_H__ +class PromptBrowserLoginFunction : public AsyncExtensionFunction, + public ProfileSyncServiceObserver { + public: + // Allows you to set the ProfileSyncService the function will use for + // testing purposes. + static void SetTestingProfileSyncService(ProfileSyncService* service); + + // Implements ProfileSyncServiceObserver interface. + virtual void OnStateChanged(); + + protected: + virtual ~PromptBrowserLoginFunction(); + virtual bool RunImpl(); + + // Returns either the actual ProfileSyncService or the test service if one + // was set. + ProfileSyncService* profile_sync_service(); + + DECLARE_EXTENSION_FUNCTION_NAME("webstorePrivate.promptBrowserLogin"); + + private: + // This indicates whether we're currently registered as an observer of the + // ProfileSyncService, and need to unregister ourselves at destruction. + bool observing_sync_state_; +}; + +#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_WEBSTORE_PRIVATE_API_H_ diff --git a/chrome/browser/extensions/extension_webstore_private_browsertest.cc b/chrome/browser/extensions/extension_webstore_private_browsertest.cc new file mode 100644 index 0000000..a0e03b4 --- /dev/null +++ b/chrome/browser/extensions/extension_webstore_private_browsertest.cc @@ -0,0 +1,109 @@ +// Copyright (c) 2010 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 "base/string_number_conversions.h" +#include "base/utf_string_conversions.h" +#include "chrome/browser/extensions/extension_browsertest.h" +#include "chrome/browser/extensions/extension_test_message_listener.h" +#include "chrome/browser/extensions/extension_webstore_private_api.h" +#include "chrome/browser/sync/profile_sync_service.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/url_constants.h" +#include "chrome/test/ui_test_utils.h" +#include "googleurl/src/gurl.h" +#include "net/base/mock_host_resolver.h" + +using chrome::kHttpScheme; +using chrome::kStandardSchemeSeparator; + +namespace { + +const char kTestUrlHostname[] = "www.example.com"; + +} // namespace + +// A fake version of ProfileSyncService used for testing. +class FakeProfileSyncService : public ProfileSyncService { + public: + // The |username_after_login| parameter determines what this fake + // ProfileSyncService will set the username to when ShowLoginDialog is called. + explicit FakeProfileSyncService(const std::string& username_after_login) : + username_after_login_(username_after_login), observer_(NULL) {} + virtual ~FakeProfileSyncService() { + EXPECT_TRUE(observer_ == NULL); + } + + // Overrides of virtual methods in ProfileSyncService. + virtual string16 GetAuthenticatedUsername() const { return username_; } + virtual void ShowLoginDialog(gfx::NativeWindow) { + EXPECT_TRUE(observer_ != NULL); + username_ = ASCIIToUTF16(username_after_login_); + observer_->OnStateChanged(); + } + virtual bool SetupInProgress() const { + return false; + } + virtual void AddObserver(ProfileSyncServiceObserver* observer) { + EXPECT_TRUE(observer_ == NULL); + observer_ = observer; + } + virtual void RemoveObserver(ProfileSyncServiceObserver* observer) { + EXPECT_TRUE(observer == observer_); + observer_ = NULL; + } + + private: + std::string username_after_login_; + string16 username_; + ProfileSyncServiceObserver* observer_; +}; + +class ExtensionWebstorePrivateBrowserTest : public ExtensionBrowserTest { + public: + ExtensionWebstorePrivateBrowserTest() { + test_url_base_ = std::string() + kHttpScheme + kStandardSchemeSeparator + + kTestUrlHostname; + } + + void SetUpCommandLine(CommandLine* command_line) { + ExtensionBrowserTest::SetUpCommandLine(command_line); + command_line->AppendSwitchASCII(switches::kAppsGalleryURL, test_url_base_); + } + + // This generates a regular test server url pointing to a test file at + // |relative_path|, but replaces the hostname with kTestUrlHostname so that + // we get the webstore private APIs injected (this happens because of the + // command line switch we added in SetupCommandLine). + GURL GetUrl(const std::string& relative_path) { + GURL base_url = test_server()->GetURL( + "files/extensions/webstore_private/" + relative_path); + GURL::Replacements replacements; + std::string replacement_host = std::string(kTestUrlHostname); + replacements.SetHostStr(replacement_host); + return base_url.ReplaceComponents(replacements); + } + + void RunLoginTest(const std::string& relative_path, + const std::string& login_result) { + FakeProfileSyncService sync_service(login_result); + PromptBrowserLoginFunction::SetTestingProfileSyncService(&sync_service); + ExtensionTestMessageListener listener("success", false); + GURL url = GetUrl(relative_path); + ui_test_utils::NavigateToURL(browser(), url); + EXPECT_TRUE(listener.WaitUntilSatisfied()); + PromptBrowserLoginFunction::SetTestingProfileSyncService(NULL); + } + + protected: + std::string test_url_base_; +}; + +IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateBrowserTest, BrowserLogin) { + host_resolver()->AddRule(kTestUrlHostname, "127.0.0.1"); + ASSERT_TRUE(test_server()->Start()); + + RunLoginTest("browser_login/no_preferred.html", ""); + RunLoginTest("browser_login/preferred.html", "foo@bar.com"); +} + diff --git a/chrome/browser/sync/profile_sync_service.h b/chrome/browser/sync/profile_sync_service.h index e68f554..5a889f1 100644 --- a/chrome/browser/sync/profile_sync_service.h +++ b/chrome/browser/sync/profile_sync_service.h @@ -214,11 +214,11 @@ class ProfileSyncService : public browser_sync::SyncFrontend, // progress, the sync system is already authenticated, or some error // occurred preventing the action. We make it the duty of ProfileSyncService // to open the dialog to easily ensure only one is ever showing. - bool SetupInProgress() const; + virtual bool SetupInProgress() const; bool WizardIsVisible() const { return wizard_.IsVisible(); } - void ShowLoginDialog(gfx::NativeWindow parent_window); + virtual void ShowLoginDialog(gfx::NativeWindow parent_window); void ShowChooseDataTypes(gfx::NativeWindow parent_window); |