Commit 25ae0154 authored by dubroy@chromium.org's avatar dubroy@chromium.org

Add policies to specify an enterprise web store.

Admins can specify the URL, name, and icon to be used for the enterprise
web store. The app itself is implemented as a component extension, with
some of the manifest values being specified by policy.

BUG=88464
TEST=New ComponentLoaderTest class added to unit_tests. Additional
manual testing: set "EnterpriseWebStoreURL" policy to a valid URL and
start up Chrome. Verify that there is an app on the new tab page that
links to the specified URL. If possible, try installing an extension from
somewhere on that URL, and ensure that no warning is shown before
showing the permission dialog.

Review URL: http://codereview.chromium.org/8477005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@110698 0039d316-1c4b-4281-b951-d872f2087c98
parent 3b0836d4
...@@ -100,7 +100,7 @@ ...@@ -100,7 +100,7 @@
# persistent IDs for all fields (but not for groups!) are needed. These are # persistent IDs for all fields (but not for groups!) are needed. These are
# specified by the 'id' keys of each policy. NEVER CHANGE EXISTING IDs, # specified by the 'id' keys of each policy. NEVER CHANGE EXISTING IDs,
# because doing so would break the deployed wire format! # because doing so would break the deployed wire format!
# For your editing convenience: highest ID currently used: 111 # For your editing convenience: highest ID currently used: 113
# #
# Placeholders: # Placeholders:
# The following placeholder strings are automatically substituted: # The following placeholder strings are automatically substituted:
...@@ -2103,6 +2103,32 @@ ...@@ -2103,6 +2103,32 @@
If this setting is disabled, users cannot print to <ph name="CLOUD_PRINT_NAME">Google Cloud Print</ph> from the <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> print dialog''', If this setting is disabled, users cannot print to <ph name="CLOUD_PRINT_NAME">Google Cloud Print</ph> from the <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> print dialog''',
}, },
{
'name': 'EnterpriseWebStoreURL',
'type': 'string',
'supported_on': ['chrome.*:17-','chrome_os:0.17-'],
'features': {'dynamic_refresh': 1},
'future': False,
'example_value': 'http://company-intranet/chromeapps',
'id': 112,
'caption': '''Enterprise web store URL''',
'desc': '''Specifies the URL for the enterprise web store. When this setting is enabled, an app will appear on the new tab page which, when clicked, will take the user to the specified URL. Extensions and apps can be installed from this page without extra warnings being presented to the user. If this policy is set, the EnterpriseWebStoreName setting should also be set.
If this setting is disabled, no enterprise web store app will appear on the new tab page.''',
},
{
'name': 'EnterpriseWebStoreName',
'type': 'string',
'supported_on': ['chrome.*:17-','chrome_os:0.17-'],
'features': {'dynamic_refresh': 1},
'future': False,
'example_value': 'WidgCo Chrome Apps',
'id': 113,
'caption': '''Enterprise web store name''',
'desc': '''The name of the enterprise web store, which will appear underneath the app icon on the new tab page. This setting has no effect if EnterpriseWebStoreURL is not set.
If this setting is disabled, the enterprise web store app (if it exists) will be labeled with its URL.''',
},
], ],
'messages': { 'messages': {
# Messages that are not associated to any policies. # Messages that are not associated to any policies.
......
...@@ -116,6 +116,7 @@ ...@@ -116,6 +116,7 @@
<include name="IDR_TRACING_JS" file="resources\tracing.js" flattenhtml="true" type="BINDATA" /> <include name="IDR_TRACING_JS" file="resources\tracing.js" flattenhtml="true" type="BINDATA" />
<include name="IDR_TRANSLATE_JS" file="resources\translate.js" type="BINDATA" /> <include name="IDR_TRANSLATE_JS" file="resources\translate.js" type="BINDATA" />
<include name="IDR_WEBSTORE_MANIFEST" file="resources\webstore_app\manifest.json" type="BINDATA" /> <include name="IDR_WEBSTORE_MANIFEST" file="resources\webstore_app\manifest.json" type="BINDATA" />
<include name="IDR_ENTERPRISE_WEBSTORE_MANIFEST" file="resources\enterprise_webstore_app\manifest.json" type="BINDATA" />
<if expr="not pp_ifdef('chromeos')"> <if expr="not pp_ifdef('chromeos')">
<include name="IDR_SYNC_PROMO_JS" file="resources\sync_promo.js" flattenhtml="true" type="BINDATA" /> <include name="IDR_SYNC_PROMO_JS" file="resources\sync_promo.js" flattenhtml="true" type="BINDATA" />
<include name="IDR_SYNC_PROMO_HTML" file="resources\sync_promo.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> <include name="IDR_SYNC_PROMO_HTML" file="resources\sync_promo.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
......
...@@ -108,13 +108,12 @@ void EnableAccessibility(bool enabled, WebUI* login_web_ui) { ...@@ -108,13 +108,12 @@ void EnableAccessibility(bool enabled, WebUI* login_web_ui) {
Profile* profile = ProfileManager::GetDefaultProfile(); Profile* profile = ProfileManager::GetDefaultProfile();
ExtensionService* extension_service = ExtensionService* extension_service =
profile->GetExtensionService(); profile->GetExtensionService();
std::string manifest = ResourceBundle::GetSharedInstance().
GetRawDataResource(IDR_CHROMEVOX_MANIFEST).as_string();
FilePath path = FilePath(extension_misc::kAccessExtensionPath) FilePath path = FilePath(extension_misc::kAccessExtensionPath)
.AppendASCII(extension_misc::kChromeVoxDirectoryName); .AppendASCII(extension_misc::kChromeVoxDirectoryName);
if (enabled) { // Load ChromeVox if (enabled) { // Load ChromeVox
const Extension* extension = const Extension* extension =
extension_service->component_loader()->Add(manifest, path); extension_service->component_loader()->Add(IDR_CHROMEVOX_MANIFEST,
path);
if (login_web_ui) { if (login_web_ui) {
RenderViewHost* render_view_host = RenderViewHost* render_view_host =
...@@ -136,7 +135,7 @@ void EnableAccessibility(bool enabled, WebUI* login_web_ui) { ...@@ -136,7 +135,7 @@ void EnableAccessibility(bool enabled, WebUI* login_web_ui) {
LOG(INFO) << "ChromeVox was Loaded."; LOG(INFO) << "ChromeVox was Loaded.";
} else { // Unload ChromeVox } else { // Unload ChromeVox
extension_service->component_loader()->Remove(manifest); extension_service->component_loader()->Remove(path);
LOG(INFO) << "ChromeVox was Unloaded."; LOG(INFO) << "ChromeVox was Unloaded.";
} }
} }
......
...@@ -9,30 +9,41 @@ ...@@ -9,30 +9,41 @@
#include <string> #include <string>
#include "base/file_path.h" #include "base/file_path.h"
#include "base/values.h"
#include "chrome/browser/prefs/pref_change_registrar.h"
#include "content/public/browser/notification_observer.h"
#include "testing/gtest/include/gtest/gtest_prod.h"
class Extension; class Extension;
class ExtensionService; class ExtensionServiceInterface;
class PrefService;
namespace extensions { namespace extensions {
// For registering, loading, and unloading component extensions. // For registering, loading, and unloading component extensions.
class ComponentLoader { class ComponentLoader : public content::NotificationObserver {
public: public:
explicit ComponentLoader(ExtensionService* extension_service); ComponentLoader(ExtensionServiceInterface* extension_service,
PrefService* prefs,
PrefService* local_state);
virtual ~ComponentLoader(); virtual ~ComponentLoader();
// Loads any registered component extensions. // Loads any registered component extensions.
void LoadAll(); void LoadAll();
// Loads and registers a component extension. If ExtensionService has been // Registers and possibly loads a component extension. If ExtensionService
// initialized, the extension is loaded; otherwise, the load is deferred // has been initialized, the extension is loaded; otherwise, the load is
// until LoadAll is called. // deferred until LoadAll is called.
const Extension* Add(const std::string& manifest, const Extension* Add(std::string& manifest_contents,
const FilePath& root_directory);
// Convenience method for registering a component extension by resource id.
const Extension* Add(int manifest_resource_id,
const FilePath& root_directory); const FilePath& root_directory);
// Unloads a component extension and removes it from the list of component // Unloads a component extension and removes it from the list of component
// extensions to be loaded. // extensions to be loaded.
void Remove(const std::string& manifest_str); void Remove(const FilePath& root_directory);
// Adds the default component extensions. // Adds the default component extensions.
// //
...@@ -44,38 +55,59 @@ class ComponentLoader { ...@@ -44,38 +55,59 @@ class ComponentLoader {
// openssl rsa -pubout -outform DER < /tmp/key.pem 2>/dev/null | base64 -w 0 // openssl rsa -pubout -outform DER < /tmp/key.pem 2>/dev/null | base64 -w 0
void AddDefaultComponentExtensions(); void AddDefaultComponentExtensions();
// content::NotificationObserver implementation
virtual void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE;
static void RegisterUserPrefs(PrefService* prefs);
// Parse the given JSON manifest. Returns NULL if it cannot be parsed, or if
// if the result is not a DictionaryValue.
DictionaryValue* ParseManifest(const std::string& manifest_contents) const;
// Clear the list of registered extensions.
void ClearAllRegistered() {
component_extensions_.clear();
}
private: private:
// Information about a registered component extension. // Information about a registered component extension.
struct ComponentExtensionInfo { struct ComponentExtensionInfo {
ComponentExtensionInfo(const std::string& manifest, ComponentExtensionInfo(const DictionaryValue* manifest,
const FilePath& root_directory) const FilePath& root_directory)
: manifest(manifest), : manifest(manifest),
root_directory(root_directory) { root_directory(root_directory) {
} }
bool Equals(const ComponentExtensionInfo& other) const; // The parsed contents of the extensions's manifest file.
const DictionaryValue* manifest;
// The extension's manifest. This is required for component extensions so
// that ExtensionService doesn't need to go to disk to load them.
std::string manifest;
// Directory where the extension is stored. // Directory where the extension is stored.
FilePath root_directory; FilePath root_directory;
}; };
const Extension* Add(const DictionaryValue* parsed_manifest,
const FilePath& root_directory);
// Loads a registered component extension. // Loads a registered component extension.
const Extension* Load(const ComponentExtensionInfo& info); const Extension* Load(const ComponentExtensionInfo& info);
// Registers an extension to be loaded as a component extension. void AddFileManagerExtension();
void Register(const ComponentExtensionInfo& info) {
component_extensions_.push_back(info); // Add the enterprise webstore extension, or reload it if already loaded.
} void AddOrReloadEnterpriseWebStore();
PrefService* prefs_;
PrefService* local_state_;
ExtensionServiceInterface* extension_service_;
// List of registered component extensions (see Extension::Location). // List of registered component extensions (see Extension::Location).
typedef std::vector<ComponentExtensionInfo> RegisteredComponentExtensions; typedef std::vector<ComponentExtensionInfo> RegisteredComponentExtensions;
RegisteredComponentExtensions component_extensions_; RegisteredComponentExtensions component_extensions_;
ExtensionService* extension_service_; PrefChangeRegistrar pref_change_registrar_;
}; };
} // namespace extensions } // namespace extensions
......
// Copyright (c) 2011 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 <string>
#include "chrome/browser/extensions/component_loader.h"
#include "base/file_util.h"
#include "base/path_service.h"
#include "chrome/browser/extensions/test_extension_service.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_pref_service.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
class MockExtensionService : public TestExtensionService {
private:
bool ready_;
ExtensionList extension_list_;
public:
MockExtensionService() : ready_(false) {
}
virtual void AddExtension(const Extension* extension) OVERRIDE {
// ExtensionService must become the owner of the extension object.
extension_list_.push_back(extension);
}
virtual void UnloadExtension(
const std::string& extension_id,
extension_misc::UnloadedExtensionReason reason) OVERRIDE {
// Remove the extension with the matching id.
for (ExtensionList::iterator it = extension_list_.begin();
it != extension_list_.end();
++it) {
if ((*it)->id() == extension_id) {
extension_list_.erase(it);
return;
}
}
}
virtual bool is_ready() OVERRIDE {
return ready_;
}
virtual const ExtensionList* extensions() const OVERRIDE {
return &extension_list_;
}
void set_ready(bool ready) {
ready_ = ready;
}
void clear_extension_list() {
extension_list_.clear();
}
};
} // namespace
namespace extensions {
class ComponentLoaderTest : public testing::Test {
public:
ComponentLoaderTest() :
// Note: we pass the same pref service here, to stand in for both
// user prefs and local state.
component_loader_(&extension_service_, &prefs_, &prefs_) {
}
void SetUp() {
FilePath test_data_dir;
ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir));
extension_path_ =
test_data_dir.AppendASCII("extensions")
.AppendASCII("good")
.AppendASCII("Extensions")
.AppendASCII("behllobkkfkfnphdnhnkndlbkcpglgmj")
.AppendASCII("1.0.0.0");
// Read in the extension manifest.
ASSERT_TRUE(file_util::ReadFileToString(
extension_path_.Append(Extension::kManifestFilename),
&manifest_contents_));
// Register the user prefs that ComponentLoader will read.
prefs_.RegisterStringPref(prefs::kEnterpriseWebStoreURL, std::string());
prefs_.RegisterStringPref(prefs::kEnterpriseWebStoreName, std::string());
// Register the local state prefs.
#if defined(OS_CHROMEOS)
prefs_.RegisterBooleanPref(prefs::kAccessibilityEnabled, false);
#endif
}
protected:
MockExtensionService extension_service_;
TestingPrefService prefs_;
ComponentLoader component_loader_;
// The root directory of the text extension.
FilePath extension_path_;
// The contents of the text extension's manifest file.
std::string manifest_contents_;
};
TEST_F(ComponentLoaderTest, ParseManifest) {
scoped_ptr<DictionaryValue> manifest;
// Test invalid JSON.
manifest.reset(
component_loader_.ParseManifest("{ 'test': 3 } invalid"));
ASSERT_EQ((DictionaryValue*)NULL, manifest.get());
// Test manifests that are valid JSON, but don't have an object literal
// at the root. ParseManifest() should always return NULL.
manifest.reset(component_loader_.ParseManifest(""));
ASSERT_EQ((DictionaryValue*)NULL, manifest.get());
manifest.reset(component_loader_.ParseManifest("[{ \"foo\": 3 }]"));
ASSERT_EQ((DictionaryValue*)NULL, manifest.get());
manifest.reset(component_loader_.ParseManifest("\"Test\""));
ASSERT_EQ((DictionaryValue*)NULL, manifest.get());
manifest.reset(component_loader_.ParseManifest("42"));
ASSERT_EQ((DictionaryValue*)NULL, manifest.get());
manifest.reset(component_loader_.ParseManifest("true"));
ASSERT_EQ((DictionaryValue*)NULL, manifest.get());
manifest.reset(component_loader_.ParseManifest("false"));
ASSERT_EQ((DictionaryValue*)NULL, manifest.get());
manifest.reset(component_loader_.ParseManifest("null"));
ASSERT_EQ((DictionaryValue*)NULL, manifest.get());
// Test parsing valid JSON.
int value;
manifest.reset(component_loader_.ParseManifest(
"{ \"test\": { \"one\": 1 }, \"two\": 2 }"));
ASSERT_NE(manifest.get(), (DictionaryValue*)NULL);
ASSERT_TRUE(manifest->GetInteger("test.one", &value));
ASSERT_EQ(1, value);
ASSERT_TRUE(manifest->GetInteger("two", &value));
ASSERT_EQ(2, value);
std::string string_value;
manifest.reset(component_loader_.ParseManifest(manifest_contents_));
ASSERT_TRUE(manifest->GetString("background_page", &string_value));
ASSERT_EQ("backgroundpage.html", string_value);
}
// Test that the extension isn't loaded if the extension service isn't ready.
TEST_F(ComponentLoaderTest, AddWhenNotReady) {
scoped_refptr<const Extension> extension;
extension_service_.set_ready(false);
extension = component_loader_.Add(manifest_contents_, extension_path_);
ASSERT_EQ((Extension*)NULL, extension.get());
ASSERT_EQ(0U, extension_service_.extensions()->size());
}
// Test that it *is* loaded when the extension service *is* ready.
TEST_F(ComponentLoaderTest, AddWhenReady) {
scoped_refptr<const Extension> extension;
extension_service_.set_ready(true);
extension = component_loader_.Add(manifest_contents_, extension_path_);
ASSERT_NE((Extension*)NULL, extension.get());
ASSERT_EQ(1U, extension_service_.extensions()->size());
}
TEST_F(ComponentLoaderTest, Remove) {
extension_service_.set_ready(false);
// Removing an extension that was never added should be ok.
component_loader_.Remove(extension_path_);
ASSERT_EQ(0U, extension_service_.extensions()->size());
// Try adding and removing before LoadAll() is called.
component_loader_.Add(manifest_contents_, extension_path_);
component_loader_.Remove(extension_path_);
component_loader_.LoadAll();
ASSERT_EQ(0U, extension_service_.extensions()->size());
// Load an extension, and check that it's unloaded when Remove() is called.
scoped_refptr<const Extension> extension;
extension_service_.set_ready(true);
extension = component_loader_.Add(manifest_contents_, extension_path_);
ASSERT_NE((Extension*)NULL, extension.get());
component_loader_.Remove(extension_path_);
ASSERT_EQ(0U, extension_service_.extensions()->size());
// And after calling LoadAll(), it shouldn't get loaded.
component_loader_.LoadAll();
ASSERT_EQ(0U, extension_service_.extensions()->size());
}
TEST_F(ComponentLoaderTest, LoadAll) {
extension_service_.set_ready(false);
// No extensions should be loaded if none were added.
component_loader_.LoadAll();
ASSERT_EQ(0U, extension_service_.extensions()->size());
// Use LoadAll() to load the default extensions.
component_loader_.AddDefaultComponentExtensions();
component_loader_.LoadAll();
unsigned int default_count = extension_service_.extensions()->size();
// Clear the list of loaded extensions, and reload with one more.
extension_service_.clear_extension_list();
component_loader_.Add(manifest_contents_, extension_path_);
component_loader_.LoadAll();
ASSERT_EQ(default_count + 1, extension_service_.extensions()->size());
}
TEST_F(ComponentLoaderTest, EnterpriseWebStore) {
component_loader_.AddDefaultComponentExtensions();
component_loader_.LoadAll();
unsigned int default_count = extension_service_.extensions()->size();
// Set the pref, and it should get loaded automatically.
extension_service_.set_ready(true);
prefs_.SetUserPref(prefs::kEnterpriseWebStoreURL,
Value::CreateStringValue("http://www.google.com"));
ASSERT_EQ(default_count + 1, extension_service_.extensions()->size());
// Now that the pref is set, check if it's added by default.
extension_service_.set_ready(false);
extension_service_.clear_extension_list();
component_loader_.ClearAllRegistered();
component_loader_.AddDefaultComponentExtensions();
component_loader_.LoadAll();
ASSERT_EQ(default_count + 1, extension_service_.extensions()->size());
// Number of loaded extensions should be the same after changing the pref.
prefs_.SetUserPref(prefs::kEnterpriseWebStoreURL,
Value::CreateStringValue("http://www.google.de"));
ASSERT_EQ(default_count + 1, extension_service_.extensions()->size());
}
} // namespace extensions
...@@ -410,7 +410,10 @@ ExtensionService::ExtensionService(Profile* profile, ...@@ -410,7 +410,10 @@ ExtensionService::ExtensionService(Profile* profile,
update_frequency)); update_frequency));
} }
component_loader_.reset(new extensions::ComponentLoader(this)); component_loader_.reset(
new extensions::ComponentLoader(this,
profile->GetPrefs(),
g_browser_process->local_state()));
app_notification_manager_->Init(); app_notification_manager_->Init();
...@@ -1136,6 +1139,10 @@ ExtensionContentSettingsStore* ...@@ -1136,6 +1139,10 @@ ExtensionContentSettingsStore*
return extension_prefs()->content_settings_store(); return extension_prefs()->content_settings_store();
} }
bool ExtensionService::is_ready() {
return ready_;
}
ExtensionUpdater* ExtensionService::updater() { ExtensionUpdater* ExtensionService::updater() {
return updater_.get(); return updater_.get();
} }
......
...@@ -114,6 +114,14 @@ class ExtensionServiceInterface : public SyncableService { ...@@ -114,6 +114,14 @@ class ExtensionServiceInterface : public SyncableService {
// TODO(akalin): Remove this method (and others) once we refactor // TODO(akalin): Remove this method (and others) once we refactor
// themes sync to not use it directly. // themes sync to not use it directly.
virtual void CheckForUpdatesSoon() = 0; virtual void CheckForUpdatesSoon() = 0;
virtual void AddExtension(const Extension* extension) = 0;
virtual void UnloadExtension(
const std::string& extension_id,
extension_misc::UnloadedExtensionReason reason) = 0;
virtual bool is_ready() = 0;
}; };
// Manages installed and running Chromium extensions. // Manages installed and running Chromium extensions.
...@@ -312,8 +320,9 @@ class ExtensionService ...@@ -312,8 +320,9 @@ class ExtensionService
void CheckForExternalUpdates(); void CheckForExternalUpdates();
// Unload the specified extension. // Unload the specified extension.
void UnloadExtension(const std::string& extension_id, virtual void UnloadExtension(
extension_misc::UnloadedExtensionReason reason); const std::string& extension_id,
extension_misc::UnloadedExtensionReason reason);
// Unload all extensions. This is currently only called on shutdown, and // Unload all extensions. This is currently only called on shutdown, and
// does not send notifications. // does not send notifications.
...@@ -360,7 +369,7 @@ class ExtensionService ...@@ -360,7 +369,7 @@ class ExtensionService
// Adds |extension| to this ExtensionService and notifies observers than an // Adds |extension| to this ExtensionService and notifies observers than an
// extension has been loaded. Called by the backend after an extension has // extension has been loaded. Called by the backend after an extension has
// been loaded from a file and installed. // been loaded from a file and installed.
void AddExtension(const Extension* extension); virtual void AddExtension(const Extension* extension);
// Called by the backend when an extension has been installed. // Called by the backend when an extension has been installed.
void OnExtensionInstalled( void OnExtensionInstalled(
...@@ -415,7 +424,7 @@ class ExtensionService ...@@ -415,7 +424,7 @@ class ExtensionService
ExtensionContentSettingsStore* GetExtensionContentSettingsStore(); ExtensionContentSettingsStore* GetExtensionContentSettingsStore();
// Whether the extension service is ready. // Whether the extension service is ready.
bool is_ready() { return ready_; } virtual bool is_ready() OVERRIDE;
extensions::ComponentLoader* component_loader() { extensions::ComponentLoader* component_loader() {
return component_loader_.get(); return component_loader_.get();
......
...@@ -80,7 +80,7 @@ class ExtensionSettingsFrontendTest : public testing::Test { ...@@ -80,7 +80,7 @@ class ExtensionSettingsFrontendTest : public testing::Test {
TEST_F(ExtensionSettingsFrontendTest, SettingsPreservedAcrossReconstruction) { TEST_F(ExtensionSettingsFrontendTest, SettingsPreservedAcrossReconstruction) {
const std::string id = "ext"; const std::string id = "ext";
profile_->GetMockExtensionService()->AddExtension( profile_->GetMockExtensionService()->AddExtensionWithId(
id, Extension::TYPE_EXTENSION); id, Extension::TYPE_EXTENSION);
SettingsStorage* storage = GetStorage(id, frontend_.get()); SettingsStorage* storage = GetStorage(id, frontend_.get());
...@@ -111,7 +111,7 @@ TEST_F(ExtensionSettingsFrontendTest, SettingsPreservedAcrossReconstruction) { ...@@ -111,7 +111,7 @@ TEST_F(ExtensionSettingsFrontendTest, SettingsPreservedAcrossReconstruction) {
TEST_F(ExtensionSettingsFrontendTest, SettingsClearedOnUninstall) { TEST_F(ExtensionSettingsFrontendTest, SettingsClearedOnUninstall) {
const std::string id = "ext"; const std::string id = "ext";
profile_->GetMockExtensionService()->AddExtension( profile_->GetMockExtensionService()->AddExtensionWithId(
id, Extension::TYPE_PACKAGED_APP); id, Extension::TYPE_PACKAGED_APP);
SettingsStorage* storage = GetStorage(id, frontend_.get()); SettingsStorage* storage = GetStorage(id, frontend_.get());
...@@ -137,7 +137,7 @@ TEST_F(ExtensionSettingsFrontendTest, SettingsClearedOnUninstall) { ...@@ -137,7 +137,7 @@ TEST_F(ExtensionSettingsFrontendTest, SettingsClearedOnUninstall) {
TEST_F(ExtensionSettingsFrontendTest, LeveldbDatabaseDeletedFromDiskOnClear) { TEST_F(ExtensionSettingsFrontendTest, LeveldbDatabaseDeletedFromDiskOnClear) {
const std::string id = "ext"; const std::string id = "ext";
profile_->GetMockExtensionService()->AddExtension( profile_->GetMockExtensionService()->AddExtensionWithId(
id, Extension::TYPE_EXTENSION); id, Extension::TYPE_EXTENSION);
SettingsStorage* storage = GetStorage(id, frontend_.get()); SettingsStorage* storage = GetStorage(id, frontend_.get());
...@@ -169,7 +169,7 @@ TEST_F(ExtensionSettingsFrontendTest, ...@@ -169,7 +169,7 @@ TEST_F(ExtensionSettingsFrontendTest,
LeveldbCreationFailureFailsAllOperations) { LeveldbCreationFailureFailsAllOperations) {
const StringValue bar("bar"); const StringValue bar("bar");
const std::string id = "ext"; const std::string id = "ext";
profile_->GetMockExtensionService()->AddExtension( profile_->GetMockExtensionService()->AddExtensionWithId(
id, Extension::TYPE_EXTENSION); id, Extension::TYPE_EXTENSION);
storage_factory_->Reset(new NullSettingsStorageFactory()); storage_factory_->Reset(new NullSettingsStorageFactory());
......
...@@ -194,7 +194,7 @@ class ExtensionSettingsSyncTest : public testing::Test { ...@@ -194,7 +194,7 @@ class ExtensionSettingsSyncTest : public testing::Test {
// its storage area. // its storage area.
SettingsStorage* AddExtensionAndGetStorage( SettingsStorage* AddExtensionAndGetStorage(
const std::string& id, Extension::Type type) { const std::string& id, Extension::Type type) {
profile_->GetMockExtensionService()->AddExtension(id, type); profile_->GetMockExtensionService()->AddExtensionWithId(id, type);
return GetStorage(id, frontend_.get()); return GetStorage(id, frontend_.get());
} }
......
...@@ -41,7 +41,7 @@ const Extension* MockExtensionService::GetExtensionById( ...@@ -41,7 +41,7 @@ const Extension* MockExtensionService::GetExtensionById(
NULL : maybe_extension->second.get(); NULL : maybe_extension->second.get();
} }
void MockExtensionService::AddExtension( void MockExtensionService::AddExtensionWithId(
const std::string& id, Extension::Type type) { const std::string& id, Extension::Type type) {
DictionaryValue manifest; DictionaryValue manifest;
manifest.SetString("name", std::string("Test extension ") + id); manifest.SetString("name", std::string("Test extension ") + id);
......
...@@ -38,7 +38,7 @@ class MockExtensionService : public TestExtensionService { ...@@ -38,7 +38,7 @@ class MockExtensionService : public TestExtensionService {
virtual ~MockExtensionService(); virtual ~MockExtensionService();
// Adds an extension with id |id| to be returned by GetExtensionById. // Adds an extension with id |id| to be returned by GetExtensionById.
void AddExtension(const std::string& id, Extension::Type type); void AddExtensionWithId(const std::string& id, Extension::Type type);
virtual const Extension* GetExtensionById( virtual const Extension* GetExtensionById(
const std::string& id, bool include_disabled) const OVERRIDE; const std::string& id, bool include_disabled) const OVERRIDE;
......
...@@ -89,3 +89,18 @@ SyncError TestExtensionService::ProcessSyncChanges( ...@@ -89,3 +89,18 @@ SyncError TestExtensionService::ProcessSyncChanges(
ADD_FAILURE(); ADD_FAILURE();
return SyncError(); return SyncError();
} }
bool TestExtensionService::is_ready() {
ADD_FAILURE();
return false;
}
void TestExtensionService::AddExtension(const Extension* extension) {
ADD_FAILURE();
}
void TestExtensionService::UnloadExtension(
const std::string& extension_id,
extension_misc::UnloadedExtensionReason reason) {
ADD_FAILURE();
}
...@@ -52,6 +52,14 @@ class TestExtensionService : public ExtensionServiceInterface { ...@@ -52,6 +52,14 @@ class TestExtensionService : public ExtensionServiceInterface {
virtual SyncError ProcessSyncChanges( virtual SyncError ProcessSyncChanges(
const tracked_objects::Location& from_here, const tracked_objects::Location& from_here,
const SyncChangeList& change_list) OVERRIDE; const SyncChangeList& change_list) OVERRIDE;
virtual bool is_ready() OVERRIDE;
virtual void AddExtension(const Extension* extension) OVERRIDE;
virtual void UnloadExtension(
const std::string& extension_id,
extension_misc::UnloadedExtensionReason reason) OVERRIDE;
}; };
#endif // CHROME_BROWSER_EXTENSIONS_TEST_EXTENSION_SERVICE_H_ #endif // CHROME_BROWSER_EXTENSIONS_TEST_EXTENSION_SERVICE_H_
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include "base/path_service.h" #include "base/path_service.h"
#include "base/scoped_temp_dir.h" #include "base/scoped_temp_dir.h"
#include "base/utf_string_conversions.h" #include "base/utf_string_conversions.h"
#include "chrome/browser/extensions/test_extension_service.h"
#include "chrome/browser/intents/web_intents_registry.h" #include "chrome/browser/intents/web_intents_registry.h"
#include "chrome/browser/webdata/web_data_service.h" #include "chrome/browser/webdata/web_data_service.h"
#include "chrome/common/chrome_paths.h" #include "chrome/common/chrome_paths.h"
...@@ -17,37 +18,10 @@ ...@@ -17,37 +18,10 @@
using content::BrowserThread; using content::BrowserThread;
using webkit_glue::WebIntentServiceData; using webkit_glue::WebIntentServiceData;
class MockExtensionService: public ExtensionServiceInterface { class MockExtensionService: public TestExtensionService {
public: public:
virtual ~MockExtensionService() {} virtual ~MockExtensionService() {}
MOCK_CONST_METHOD0(extensions, const ExtensionList*()); MOCK_CONST_METHOD0(extensions, const ExtensionList*());
MOCK_METHOD0(pending_extension_manager, PendingExtensionManager*());
MOCK_METHOD4(UpdateExtension, bool(const std::string& id,
const FilePath& path,
const GURL& download_url,
CrxInstaller** out_crx_installer));
MOCK_CONST_METHOD2(GetExtensionById,
const Extension*(const std::string& id,
bool include_disabled));
MOCK_CONST_METHOD1(GetInstalledExtension,
const Extension*(const std::string& id));
MOCK_CONST_METHOD1(IsExtensionEnabled,bool(const std::string& extension_id));
MOCK_CONST_METHOD1(IsExternalExtensionUninstalled,
bool(const std::string& extension_id));
MOCK_METHOD1(UpdateExtensionBlacklist,
void(const std::vector<std::string>& blacklist));
MOCK_METHOD0(CheckAdminBlacklist, void());;
MOCK_METHOD0(CheckForUpdatesSoon,void());
MOCK_METHOD3(MergeDataAndStartSyncing,
SyncError(syncable::ModelType type,
const SyncDataList& initial_sync_data,
SyncChangeProcessor* sync_processor));
MOCK_METHOD1(StopSyncing, void(syncable::ModelType type));
MOCK_CONST_METHOD1(GetAllSyncData, SyncDataList(syncable::ModelType type));
MOCK_METHOD2(ProcessSyncChanges,
SyncError(const tracked_objects::Location& from_here,
const SyncChangeList& change_list));
}; };
// TODO(groby): Unify loading functions with extension_manifest_unittest code. // TODO(groby): Unify loading functions with extension_manifest_unittest code.
...@@ -121,8 +95,8 @@ class WebIntentsRegistryTest : public testing::Test { ...@@ -121,8 +95,8 @@ class WebIntentsRegistryTest : public testing::Test {
wds_ = new WebDataService(); wds_ = new WebDataService();
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
wds_->Init(temp_dir_.path()); wds_->Init(temp_dir_.path());
registry_.Initialize(wds_, &extensionService_); registry_.Initialize(wds_, &extension_service_);
EXPECT_CALL(extensionService_, extensions()). EXPECT_CALL(extension_service_, extensions()).
WillRepeatedly(testing::Return(&extensions_)); WillRepeatedly(testing::Return(&extensions_));
} }
...@@ -139,7 +113,7 @@ class WebIntentsRegistryTest : public testing::Test { ...@@ -139,7 +113,7 @@ class WebIntentsRegistryTest : public testing::Test {
content::TestBrowserThread ui_thread_; content::TestBrowserThread ui_thread_;
content::TestBrowserThread db_thread_; content::TestBrowserThread db_thread_;
scoped_refptr<WebDataService> wds_; scoped_refptr<WebDataService> wds_;
MockExtensionService extensionService_; MockExtensionService extension_service_;
ExtensionList extensions_; ExtensionList extensions_;
WebIntentsRegistry registry_; WebIntentsRegistry registry_;
ScopedTempDir temp_dir_; ScopedTempDir temp_dir_;
......
...@@ -188,6 +188,10 @@ const PolicyToPreferenceMapEntry kSimplePolicyMap[] = { ...@@ -188,6 +188,10 @@ const PolicyToPreferenceMapEntry kSimplePolicyMap[] = {
prefs::kUrlBlacklist }, prefs::kUrlBlacklist },
{ Value::TYPE_LIST, kPolicyURLWhitelist, { Value::TYPE_LIST, kPolicyURLWhitelist,
prefs::kUrlWhitelist }, prefs::kUrlWhitelist },
{ Value::TYPE_STRING, kPolicyEnterpriseWebStoreURL,
prefs::kEnterpriseWebStoreURL },
{ Value::TYPE_STRING, kPolicyEnterpriseWebStoreName,
prefs::kEnterpriseWebStoreName },
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
{ Value::TYPE_BOOLEAN, kPolicyChromeOsLockOnIdleSuspend, { Value::TYPE_BOOLEAN, kPolicyChromeOsLockOnIdleSuspend,
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "chrome/browser/debugger/devtools_window.h" #include "chrome/browser/debugger/devtools_window.h"
#include "chrome/browser/download/download_prefs.h" #include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/extensions/apps_promo.h" #include "chrome/browser/extensions/apps_promo.h"
#include "chrome/browser/extensions/component_loader.h"
#include "chrome/browser/extensions/extension_prefs.h" #include "chrome/browser/extensions/extension_prefs.h"
#include "chrome/browser/extensions/extension_web_ui.h" #include "chrome/browser/extensions/extension_web_ui.h"
#include "chrome/browser/external_protocol/external_protocol_handler.h" #include "chrome/browser/external_protocol/external_protocol_handler.h"
...@@ -194,6 +195,7 @@ void RegisterUserPrefs(PrefService* user_prefs) { ...@@ -194,6 +195,7 @@ void RegisterUserPrefs(PrefService* user_prefs) {
#if !defined(OS_CHROMEOS) #if !defined(OS_CHROMEOS)
default_apps::RegisterUserPrefs(user_prefs); default_apps::RegisterUserPrefs(user_prefs);
#endif #endif
extensions::ComponentLoader::RegisterUserPrefs(user_prefs);
} }
void MigrateBrowserPrefs(PrefService* user_prefs, PrefService* local_state) { void MigrateBrowserPrefs(PrefService* user_prefs, PrefService* local_state) {
......
{
"key": "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDT/VTRfIVU2P0jPQOHFevNpKTFyKHReHOLaeYmCKK+T/GoXYJocfOOwyibhTqvwYequQPrK32Wjw4mbzkfTq5/LYYl2oXkoUL72FmJ5lMQcJsrJVGD0DfvjNpCPBEaCRkLnHPnJPw3NQlKb98aMMdmbfgiGvymBXekesKF3dg4dwIDAQAB",
"name": "", // Must be specified by policy.
"version": "0.1",
"description": "Enterprise Web Store",
"icons": {
},
"app": {
"launch": {
"web_url": "" // Must be specified by policy.
}
},
"permissions": [
"webstorePrivate",
"management"
]
}
...@@ -1334,6 +1334,7 @@ ...@@ -1334,6 +1334,7 @@
'browser/extensions/app_notification_test_util.cc', 'browser/extensions/app_notification_test_util.cc',
'browser/extensions/app_notify_channel_setup_unittest.cc', 'browser/extensions/app_notify_channel_setup_unittest.cc',
'browser/extensions/apps_promo_unittest.cc', 'browser/extensions/apps_promo_unittest.cc',
'browser/extensions/component_loader_unittest.cc',
'browser/extensions/convert_user_script_unittest.cc', 'browser/extensions/convert_user_script_unittest.cc',
'browser/extensions/convert_web_app_unittest.cc', 'browser/extensions/convert_web_app_unittest.cc',
'browser/extensions/extension_content_settings_store_unittest.cc', 'browser/extensions/extension_content_settings_store_unittest.cc',
......
...@@ -859,6 +859,14 @@ const char kImportSearchEngine[] = "import_search_engine"; ...@@ -859,6 +859,14 @@ const char kImportSearchEngine[] = "import_search_engine";
// browser on first run. // browser on first run.
const char kImportSavedPasswords[] = "import_saved_passwords"; const char kImportSavedPasswords[] = "import_saved_passwords";
// The URL of the enterprise web store, which is a site trusted by the
// enterprise admin. Users can install apps & extensions from this site
// without scary warnings.
const char kEnterpriseWebStoreURL[] = "webstore.enterprise_store_url";
// The name of the enterprise web store, to be shown to the user.
const char kEnterpriseWebStoreName[] = "webstore.enterprise_store_name";
#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) && defined(OS_POSIX) #if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) && defined(OS_POSIX)
// The local profile id for this profile. // The local profile id for this profile.
const char kLocalProfileId[] = "profile.local_profile_id"; const char kLocalProfileId[] = "profile.local_profile_id";
......
...@@ -304,6 +304,9 @@ extern const char kImportHomepage[]; ...@@ -304,6 +304,9 @@ extern const char kImportHomepage[];
extern const char kImportSearchEngine[]; extern const char kImportSearchEngine[];
extern const char kImportSavedPasswords[]; extern const char kImportSavedPasswords[];
extern const char kEnterpriseWebStoreURL[];
extern const char kEnterpriseWebStoreName[];
#if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) && defined(OS_POSIX) #if !defined(OS_MACOSX) && !defined(OS_CHROMEOS) && defined(OS_POSIX)
extern const char kLocalProfileId[]; extern const char kLocalProfileId[];
extern const char kPasswordsUseLocalProfileId[]; extern const char kPasswordsUseLocalProfileId[];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment