summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authorjstritar@chromium.org <jstritar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-27 18:42:31 +0000
committerjstritar@chromium.org <jstritar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-07-27 18:42:31 +0000
commit902fd7bbba5683135ec25fe83479b13ab532891a (patch)
treea6f2a4eb6b7a4349bc6fbaae0e419c715046a069 /chrome/browser
parent3a91c5b51bc1890ecf3a558dbd51e3da68c418ca (diff)
downloadchromium_src-902fd7bbba5683135ec25fe83479b13ab532891a.zip
chromium_src-902fd7bbba5683135ec25fe83479b13ab532891a.tar.gz
chromium_src-902fd7bbba5683135ec25fe83479b13ab532891a.tar.bz2
Re-land the experimental permissions API for extensions.
The permissions API lets extensions specify optional permissions in their manifest that they can request at run-time. It currently supports API permissions through a white-list. Host permissions will come later. This also fixes some clang errors from the previous attempt. BUG=48119, 70466, 84507 TEST=*Extension* Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=94288 Review URL: http://codereview.chromium.org/7432006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@94326 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/automation/testing_automation_provider.cc5
-rw-r--r--chrome/browser/background/background_mode_manager.cc24
-rw-r--r--chrome/browser/extensions/convert_web_app_browsertest.cc2
-rw-r--r--chrome/browser/extensions/convert_web_app_unittest.cc4
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.cc7
-rw-r--r--chrome/browser/extensions/extension_install_ui.cc35
-rw-r--r--chrome/browser/extensions/extension_install_ui.h14
-rw-r--r--chrome/browser/extensions/extension_management_api.cc4
-rw-r--r--chrome/browser/extensions/extension_permissions_api.cc378
-rw-r--r--chrome/browser/extensions/extension_permissions_api.h119
-rw-r--r--chrome/browser/extensions/extension_permissions_api_constants.cc23
-rw-r--r--chrome/browser/extensions/extension_permissions_api_constants.h28
-rw-r--r--chrome/browser/extensions/extension_prefs.cc171
-rw-r--r--chrome/browser/extensions/extension_prefs.h22
-rw-r--r--chrome/browser/extensions/extension_prefs_unittest.cc84
-rw-r--r--chrome/browser/extensions/extension_service.cc67
-rw-r--r--chrome/browser/extensions/extension_service.h19
-rw-r--r--chrome/browser/extensions/extension_service_unittest.cc15
-rw-r--r--chrome/browser/extensions/permissions_apitest.cc39
-rw-r--r--chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.h1
-rw-r--r--chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm4
-rw-r--r--chrome/browser/ui/gtk/extensions/extension_install_dialog_gtk.cc7
-rw-r--r--chrome/browser/ui/views/extensions/extension_install_dialog_view.cc6
23 files changed, 950 insertions, 128 deletions
diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc
index 44a3b5b..d1a523f 100644
--- a/chrome/browser/automation/testing_automation_provider.cc
+++ b/chrome/browser/automation/testing_automation_provider.cc
@@ -4111,7 +4111,7 @@ ListValue* GetHostPermissions(const Extension* ext, bool effective_perm) {
if (effective_perm)
pattern_set = ext->GetEffectiveHostPermissions();
else
- pattern_set = ext->permission_set()->explicit_hosts();
+ pattern_set = ext->GetActivePermissions()->explicit_hosts();
ListValue* permissions = new ListValue;
for (URLPatternSet::const_iterator perm = pattern_set.begin();
@@ -4124,7 +4124,8 @@ ListValue* GetHostPermissions(const Extension* ext, bool effective_perm) {
ListValue* GetAPIPermissions(const Extension* ext) {
ListValue* permissions = new ListValue;
- std::set<std::string> perm_list = ext->permission_set()->GetAPIsAsStrings();
+ std::set<std::string> perm_list =
+ ext->GetActivePermissions()->GetAPIsAsStrings();
for (std::set<std::string>::const_iterator perm = perm_list.begin();
perm != perm_list.end(); ++perm) {
permissions->Append(new StringValue(perm->c_str()));
diff --git a/chrome/browser/background/background_mode_manager.cc b/chrome/browser/background/background_mode_manager.cc
index c44362c..33eecf1 100644
--- a/chrome/browser/background/background_mode_manager.cc
+++ b/chrome/browser/background/background_mode_manager.cc
@@ -196,13 +196,15 @@ void BackgroundModeManager::RegisterProfile(Profile* profile) {
profile, this));
background_mode_data_[profile] = bmd;
- // Listen for when extensions are loaded/unloaded so we can track the
- // number of background apps and modify our keep-alive and launch-on-startup
- // state appropriately.
+ // Listen for when extensions are loaded/unloaded or add/remove the
+ // background permission so we can track the number of background apps and
+ // modify our keep-alive and launch-on-startup state appropriately.
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_LOADED,
Source<Profile>(profile));
registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_UNLOADED,
Source<Profile>(profile));
+ registrar_.Add(this, chrome::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED,
+ Source<Profile>(profile));
// Check for the presence of background apps after all extensions have been
// loaded, to handle the case where an extension has been manually removed
@@ -274,6 +276,22 @@ void BackgroundModeManager::Observe(int type,
OnBackgroundAppUninstalled();
}
break;
+ case chrome::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED: {
+ UpdatedExtensionPermissionsInfo* info =
+ Details<UpdatedExtensionPermissionsInfo>(details).ptr();
+ if (!info->permissions->HasAPIPermission(
+ ExtensionAPIPermission::kBackground))
+ break;
+
+ if (info->reason == UpdatedExtensionPermissionsInfo::ADDED) {
+ OnBackgroundAppInstalled(info->extension);
+ OnBackgroundAppLoaded();
+ } else {
+ OnBackgroundAppUnloaded();
+ OnBackgroundAppUninstalled();
+ }
+ }
+ break;
case content::NOTIFICATION_APP_TERMINATING:
// Make sure we aren't still keeping the app alive (only happens if we
// don't receive an EXTENSIONS_READY notification for some reason).
diff --git a/chrome/browser/extensions/convert_web_app_browsertest.cc b/chrome/browser/extensions/convert_web_app_browsertest.cc
index a8405b1..7fe6f94 100644
--- a/chrome/browser/extensions/convert_web_app_browsertest.cc
+++ b/chrome/browser/extensions/convert_web_app_browsertest.cc
@@ -70,7 +70,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionFromWebAppTest, Basic) {
EXPECT_EQ(extension_misc::LAUNCH_PANEL,
installed_extension_->launch_container());
- ASSERT_EQ(2u, installed_extension_->permission_set()->apis().size());
+ ASSERT_EQ(2u, installed_extension_->GetActivePermissions()->apis().size());
EXPECT_TRUE(installed_extension_->HasAPIPermission(
ExtensionAPIPermission::kGeolocation));
EXPECT_TRUE(installed_extension_->HasAPIPermission(
diff --git a/chrome/browser/extensions/convert_web_app_unittest.cc b/chrome/browser/extensions/convert_web_app_unittest.cc
index 0f3b537..640b31b 100644
--- a/chrome/browser/extensions/convert_web_app_unittest.cc
+++ b/chrome/browser/extensions/convert_web_app_unittest.cc
@@ -123,7 +123,7 @@ TEST(ExtensionFromWebApp, Basic) {
EXPECT_EQ(UTF16ToUTF8(web_app.title), extension->name());
EXPECT_EQ(UTF16ToUTF8(web_app.description), extension->description());
EXPECT_EQ(web_app.app_url, extension->GetFullLaunchURL());
- EXPECT_EQ(2u, extension->permission_set()->apis().size());
+ EXPECT_EQ(2u, extension->GetActivePermissions()->apis().size());
EXPECT_TRUE(extension->HasAPIPermission("geolocation"));
EXPECT_TRUE(extension->HasAPIPermission("notifications"));
ASSERT_EQ(1u, extension->web_extent().patterns().size());
@@ -167,7 +167,7 @@ TEST(ExtensionFromWebApp, Minimal) {
EXPECT_EQ("", extension->description());
EXPECT_EQ(web_app.app_url, extension->GetFullLaunchURL());
EXPECT_EQ(0u, extension->icons().map().size());
- EXPECT_EQ(0u, extension->permission_set()->apis().size());
+ EXPECT_EQ(0u, extension->GetActivePermissions()->apis().size());
ASSERT_EQ(1u, extension->web_extent().patterns().size());
EXPECT_EQ("*://aaronboodman.com/*",
extension->web_extent().patterns().begin()->GetAsString());
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index c8cbf9e..15529b2 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -32,6 +32,7 @@
#include "chrome/browser/extensions/extension_module.h"
#include "chrome/browser/extensions/extension_omnibox_api.h"
#include "chrome/browser/extensions/extension_page_actions_module.h"
+#include "chrome/browser/extensions/extension_permissions_api.h"
#include "chrome/browser/extensions/extension_preference_api.h"
#include "chrome/browser/extensions/extension_processes_api.h"
#include "chrome/browser/extensions/extension_proxy_api.h"
@@ -393,6 +394,12 @@ void FactoryRegistry::ResetFunctions() {
// Experimental App API.
RegisterFunction<AppNotifyFunction>();
RegisterFunction<AppClearAllNotificationsFunction>();
+
+ // Permissions
+ RegisterFunction<ContainsPermissionsFunction>();
+ RegisterFunction<GetAllPermissionsFunction>();
+ RegisterFunction<RemovePermissionsFunction>();
+ RegisterFunction<RequestPermissionsFunction>();
}
void FactoryRegistry::GetAllNames(std::vector<std::string>* names) {
diff --git a/chrome/browser/extensions/extension_install_ui.cc b/chrome/browser/extensions/extension_install_ui.cc
index 62d904a..bdbd839 100644
--- a/chrome/browser/extensions/extension_install_ui.cc
+++ b/chrome/browser/extensions/extension_install_ui.cc
@@ -39,22 +39,32 @@
// static
const int ExtensionInstallUI::kTitleIds[NUM_PROMPT_TYPES] = {
IDS_EXTENSION_INSTALL_PROMPT_TITLE,
- IDS_EXTENSION_RE_ENABLE_PROMPT_TITLE
+ IDS_EXTENSION_RE_ENABLE_PROMPT_TITLE,
+ IDS_EXTENSION_PERMISSIONS_PROMPT_TITLE
};
// static
const int ExtensionInstallUI::kHeadingIds[NUM_PROMPT_TYPES] = {
IDS_EXTENSION_INSTALL_PROMPT_HEADING,
- IDS_EXTENSION_RE_ENABLE_PROMPT_HEADING
+ IDS_EXTENSION_RE_ENABLE_PROMPT_HEADING,
+ IDS_EXTENSION_PERMISSIONS_PROMPT_HEADING
};
// static
const int ExtensionInstallUI::kButtonIds[NUM_PROMPT_TYPES] = {
IDS_EXTENSION_PROMPT_INSTALL_BUTTON,
- IDS_EXTENSION_PROMPT_RE_ENABLE_BUTTON
+ IDS_EXTENSION_PROMPT_RE_ENABLE_BUTTON,
+ IDS_EXTENSION_PROMPT_PERMISSIONS_BUTTON
+};
+// static
+const int ExtensionInstallUI::kAbortButtonIds[NUM_PROMPT_TYPES] = {
+ 0,
+ 0,
+ IDS_EXTENSION_PROMPT_PERMISSIONS_ABORT_BUTTON
};
// static
const int ExtensionInstallUI::kWarningIds[NUM_PROMPT_TYPES] = {
IDS_EXTENSION_PROMPT_WILL_HAVE_ACCESS_TO,
- IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO
+ IDS_EXTENSION_PROMPT_WILL_NOW_HAVE_ACCESS_TO,
+ IDS_EXTENSION_PROMPT_WANTS_ACCESS_TO,
};
namespace {
@@ -112,6 +122,7 @@ void ExtensionInstallUI::ConfirmInstall(Delegate* delegate,
const Extension* extension) {
DCHECK(ui_loop_ == MessageLoop::current());
extension_ = extension;
+ permissions_ = extension->GetActivePermissions();
delegate_ = delegate;
// We special-case themes to not show any confirm UI. Instead they are
@@ -129,11 +140,24 @@ void ExtensionInstallUI::ConfirmReEnable(Delegate* delegate,
const Extension* extension) {
DCHECK(ui_loop_ == MessageLoop::current());
extension_ = extension;
+ permissions_ = extension->GetActivePermissions();
delegate_ = delegate;
ShowConfirmation(RE_ENABLE_PROMPT);
}
+void ExtensionInstallUI::ConfirmPermissions(
+ Delegate* delegate,
+ const Extension* extension,
+ const ExtensionPermissionSet* permissions) {
+ DCHECK(ui_loop_ == MessageLoop::current());
+ extension_ = extension;
+ permissions_ = permissions;
+ delegate_ = delegate;
+
+ ShowConfirmation(PERMISSIONS_PROMPT);
+}
+
void ExtensionInstallUI::OnInstallSuccess(const Extension* extension,
SkBitmap* icon) {
extension_ = extension;
@@ -193,6 +217,7 @@ void ExtensionInstallUI::OnImageLoaded(
SetIcon(image);
switch (prompt_type_) {
+ case PERMISSIONS_PROMPT:
case RE_ENABLE_PROMPT:
case INSTALL_PROMPT: {
// TODO(jcivelli): http://crbug.com/44771 We should not show an install
@@ -203,7 +228,7 @@ void ExtensionInstallUI::OnImageLoaded(
NotificationService::NoDetails());
std::vector<string16> warnings =
- extension_->GetPermissionMessageStrings();
+ permissions_->GetWarningMessages();
ShowExtensionInstallDialog(
profile_, delegate_, extension_, &icon_, warnings, prompt_type_);
break;
diff --git a/chrome/browser/extensions/extension_install_ui.h b/chrome/browser/extensions/extension_install_ui.h
index 222f6a3..19965e5 100644
--- a/chrome/browser/extensions/extension_install_ui.h
+++ b/chrome/browser/extensions/extension_install_ui.h
@@ -16,6 +16,7 @@
#include "ui/gfx/native_widget_types.h"
class Extension;
+class ExtensionPermissionSet;
class MessageLoop;
class Profile;
class InfoBarDelegate;
@@ -28,6 +29,7 @@ class ExtensionInstallUI : public ImageLoadingTracker::Observer {
UNSET_PROMPT_TYPE = -1,
INSTALL_PROMPT = 0,
RE_ENABLE_PROMPT,
+ PERMISSIONS_PROMPT,
NUM_PROMPT_TYPES
};
@@ -36,6 +38,7 @@ class ExtensionInstallUI : public ImageLoadingTracker::Observer {
static const int kHeadingIds[NUM_PROMPT_TYPES];
static const int kButtonIds[NUM_PROMPT_TYPES];
static const int kWarningIds[NUM_PROMPT_TYPES];
+ static const int kAbortButtonIds[NUM_PROMPT_TYPES];
class Delegate {
public:
@@ -65,6 +68,14 @@ class ExtensionInstallUI : public ImageLoadingTracker::Observer {
// We *MUST* eventually call either Proceed() or Abort() on |delegate|.
virtual void ConfirmReEnable(Delegate* delegate, const Extension* extension);
+ // This is called by the extension permissions API to verify whether an
+ // extension may be granted additional permissions.
+ //
+ // We *MUST* eventually call either Proceed() or Abort() on |delegate|.
+ virtual void ConfirmPermissions(Delegate* delegate,
+ const Extension* extension,
+ const ExtensionPermissionSet* permissions);
+
// Installation was successful. This is declared virtual for testing.
virtual void OnInstallSuccess(const Extension* extension, SkBitmap* icon);
@@ -122,6 +133,9 @@ class ExtensionInstallUI : public ImageLoadingTracker::Observer {
// The extension we are showing the UI for.
const Extension* extension_;
+ // The permissions being prompted for.
+ scoped_refptr<const ExtensionPermissionSet> permissions_;
+
// The delegate we will call Proceed/Abort on after confirmation UI.
Delegate* delegate_;
diff --git a/chrome/browser/extensions/extension_management_api.cc b/chrome/browser/extensions/extension_management_api.cc
index 3955361..8037f56 100644
--- a/chrome/browser/extensions/extension_management_api.cc
+++ b/chrome/browser/extensions/extension_management_api.cc
@@ -92,7 +92,7 @@ static DictionaryValue* CreateExtensionInfo(const Extension& extension,
}
const std::set<std::string> perms =
- extension.permission_set()->GetAPIsAsStrings();
+ extension.GetActivePermissions()->GetAPIsAsStrings();
ListValue* permission_list = new ListValue();
if (!perms.empty()) {
std::set<std::string>::const_iterator perms_iter;
@@ -107,7 +107,7 @@ static DictionaryValue* CreateExtensionInfo(const Extension& extension,
if (!extension.is_hosted_app()) {
// Skip host permissions for hosted apps.
const URLPatternSet host_perms =
- extension.permission_set()->explicit_hosts();
+ extension.GetActivePermissions()->explicit_hosts();
if (!host_perms.is_empty()) {
URLPatternSet::const_iterator host_perms_iter;
for (host_perms_iter = host_perms.begin();
diff --git a/chrome/browser/extensions/extension_permissions_api.cc b/chrome/browser/extensions/extension_permissions_api.cc
new file mode 100644
index 0000000..87a413b
--- /dev/null
+++ b/chrome/browser/extensions/extension_permissions_api.cc
@@ -0,0 +1,378 @@
+// 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 "chrome/browser/extensions/extension_permissions_api.h"
+
+#include "base/json/json_writer.h"
+#include "base/stringprintf.h"
+#include "base/values.h"
+#include "chrome/browser/extensions/extension_event_router.h"
+#include "chrome/browser/extensions/extension_permissions_api_constants.h"
+#include "chrome/browser/extensions/extension_prefs.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_messages.h"
+#include "chrome/common/extensions/extension_permission_set.h"
+#include "chrome/common/extensions/url_pattern_set.h"
+#include "content/common/notification_service.h"
+#include "googleurl/src/gurl.h"
+
+
+namespace keys = extension_permissions_module_constants;
+
+namespace {
+
+enum AutoConfirmForTest {
+ DO_NOT_SKIP = 0,
+ PROCEED,
+ ABORT
+};
+AutoConfirmForTest auto_confirm_for_tests = DO_NOT_SKIP;
+
+DictionaryValue* PackPermissionsToValue(const ExtensionPermissionSet* set) {
+ DictionaryValue* value = new DictionaryValue();
+
+ // Generate the list of API permissions.
+ ListValue* apis = new ListValue();
+ ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
+ for (ExtensionAPIPermissionSet::const_iterator i = set->apis().begin();
+ i != set->apis().end(); ++i)
+ apis->Append(Value::CreateStringValue(info->GetByID(*i)->name()));
+
+ // TODO(jstritar): Include hosts once the API supports them. At that point,
+ // we could also shared this code with ExtensionPermissionSet methods in
+ // ExtensionPrefs.
+
+ value->Set(keys::kApisKey, apis);
+ return value;
+}
+
+// Creates a new ExtensionPermissionSet from its |value| and passes ownership to
+// the caller through |ptr|. Sets |bad_message| to true if the message is badly
+// formed. Returns false if the method fails to unpack a permission set.
+bool UnpackPermissionsFromValue(DictionaryValue* value,
+ scoped_refptr<ExtensionPermissionSet>* ptr,
+ bool* bad_message,
+ std::string* error) {
+ ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
+ ExtensionAPIPermissionSet apis;
+ if (value->HasKey(keys::kApisKey)) {
+ ListValue* api_list = NULL;
+ if (!value->GetList(keys::kApisKey, &api_list)) {
+ *bad_message = true;
+ return false;
+ }
+ for (size_t i = 0; i < api_list->GetSize(); ++i) {
+ std::string api_name;
+ if (!api_list->GetString(i, &api_name)) {
+ *bad_message = true;
+ return false;
+ }
+
+ ExtensionAPIPermission* permission = info->GetByName(api_name);
+ if (!permission) {
+ *error = base::StringPrintf(
+ keys::kUnknownPermissionError, api_name.c_str());
+ return false;
+ }
+ apis.insert(permission->id());
+ }
+ }
+
+ // Ignore host permissions for now.
+ URLPatternSet empty_set;
+ *ptr = new ExtensionPermissionSet(apis, empty_set, empty_set);
+ return true;
+}
+
+} // namespace
+
+ExtensionPermissionsManager::ExtensionPermissionsManager(
+ ExtensionService* extension_service)
+ : extension_service_(extension_service) {
+ RegisterWhitelist();
+}
+
+ExtensionPermissionsManager::~ExtensionPermissionsManager() {
+}
+
+void ExtensionPermissionsManager::AddPermissions(
+ const Extension* extension, const ExtensionPermissionSet* permissions) {
+ scoped_refptr<const ExtensionPermissionSet> existing(
+ extension->GetActivePermissions());
+ scoped_refptr<ExtensionPermissionSet> total(
+ ExtensionPermissionSet::CreateUnion(existing, permissions));
+ scoped_refptr<ExtensionPermissionSet> added(
+ ExtensionPermissionSet::CreateDifference(total.get(), existing));
+
+ extension_service_->UpdateActivePermissions(extension, total.get());
+
+ // Update the granted permissions so we don't auto-disable the extension.
+ extension_service_->GrantPermissions(extension);
+
+ NotifyPermissionsUpdated(extension, total.get(), added.get(), ADDED);
+}
+
+void ExtensionPermissionsManager::RemovePermissions(
+ const Extension* extension, const ExtensionPermissionSet* permissions) {
+ scoped_refptr<const ExtensionPermissionSet> existing(
+ extension->GetActivePermissions());
+ scoped_refptr<ExtensionPermissionSet> total(
+ ExtensionPermissionSet::CreateDifference(existing, permissions));
+ scoped_refptr<ExtensionPermissionSet> removed(
+ ExtensionPermissionSet::CreateDifference(existing, total.get()));
+
+ // We update the active permissions, and not the granted permissions, because
+ // the extension, not the user, removed the permissions. This allows the
+ // extension to add them again without prompting the user.
+ extension_service_->UpdateActivePermissions(extension, total.get());
+
+ NotifyPermissionsUpdated(extension, total.get(), removed.get(), REMOVED);
+}
+
+void ExtensionPermissionsManager::DispatchEvent(
+ const std::string& extension_id,
+ const char* event_name,
+ const ExtensionPermissionSet* changed_permissions) {
+ Profile* profile = extension_service_->profile();
+ if (profile && profile->GetExtensionEventRouter()) {
+ ListValue value;
+ value.Append(PackPermissionsToValue(changed_permissions));
+ std::string json_value;
+ base::JSONWriter::Write(&value, false, &json_value);
+ profile->GetExtensionEventRouter()->DispatchEventToExtension(
+ extension_id, event_name, json_value, profile, GURL());
+ }
+}
+
+void ExtensionPermissionsManager::NotifyPermissionsUpdated(
+ const Extension* extension,
+ const ExtensionPermissionSet* active,
+ const ExtensionPermissionSet* changed,
+ EventType event_type) {
+ if (!changed || changed->IsEmpty())
+ return;
+
+ UpdatedExtensionPermissionsInfo::Reason reason;
+ const char* event_name = NULL;
+
+ if (event_type == REMOVED) {
+ reason = UpdatedExtensionPermissionsInfo::REMOVED;
+ event_name = keys::kOnRemoved;
+ } else {
+ CHECK_EQ(ADDED, event_type);
+ reason = UpdatedExtensionPermissionsInfo::ADDED;
+ event_name = keys::kOnAdded;
+ }
+
+ // Notify other APIs or interested parties.
+ UpdatedExtensionPermissionsInfo info = UpdatedExtensionPermissionsInfo(
+ extension, changed, reason);
+ NotificationService::current()->Notify(
+ chrome::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED,
+ Source<Profile>(extension_service_->profile()),
+ Details<UpdatedExtensionPermissionsInfo>(&info));
+
+ // Trigger the onAdded and onRemoved events in the extension.
+ DispatchEvent(extension->id(), event_name, changed);
+
+ // Send the new permissions to the renderers.
+ for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
+ !i.IsAtEnd(); i.Advance()) {
+ RenderProcessHost* host = i.GetCurrentValue();
+ if (extension_service_->profile()->IsSameProfile(host->profile()))
+ host->Send(new ExtensionMsg_UpdatePermissions(
+ extension->id(),
+ active->apis(),
+ active->explicit_hosts(),
+ active->scriptable_hosts()));
+ }
+}
+
+void ExtensionPermissionsManager::RegisterWhitelist() {
+ // TODO(jstritar): This could be a field on ExtensionAPIPermission.
+ ExtensionAPIPermissionSet api_whitelist;
+ api_whitelist.insert(ExtensionAPIPermission::kClipboardRead);
+ api_whitelist.insert(ExtensionAPIPermission::kClipboardWrite);
+ api_whitelist.insert(ExtensionAPIPermission::kNotification);
+ api_whitelist.insert(ExtensionAPIPermission::kBookmark);
+ api_whitelist.insert(ExtensionAPIPermission::kContextMenus);
+ api_whitelist.insert(ExtensionAPIPermission::kCookie);
+ api_whitelist.insert(ExtensionAPIPermission::kDebugger);
+ api_whitelist.insert(ExtensionAPIPermission::kHistory);
+ api_whitelist.insert(ExtensionAPIPermission::kIdle);
+ api_whitelist.insert(ExtensionAPIPermission::kTab);
+ api_whitelist.insert(ExtensionAPIPermission::kManagement);
+ api_whitelist.insert(ExtensionAPIPermission::kBackground);
+ whitelist_ = new ExtensionPermissionSet(
+ api_whitelist, URLPatternSet(), URLPatternSet());
+}
+
+bool ContainsPermissionsFunction::RunImpl() {
+ DictionaryValue* args = NULL;
+ EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
+ std::string error;
+ if (!args)
+ return false;
+
+ scoped_refptr<ExtensionPermissionSet> permissions;
+ if (!UnpackPermissionsFromValue(args, &permissions, &bad_message_, &error_))
+ return false;
+ CHECK(permissions.get());
+
+ result_.reset(Value::CreateBooleanValue(
+ GetExtension()->GetActivePermissions()->Contains(*permissions)));
+ return true;
+}
+
+bool GetAllPermissionsFunction::RunImpl() {
+ result_.reset(PackPermissionsToValue(
+ GetExtension()->GetActivePermissions()));
+ return true;
+}
+
+bool RemovePermissionsFunction::RunImpl() {
+ DictionaryValue* args = NULL;
+ EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
+ if (!args)
+ return false;
+
+ scoped_refptr<ExtensionPermissionSet> permissions;
+ if (!UnpackPermissionsFromValue(args, &permissions, &bad_message_, &error_))
+ return false;
+ CHECK(permissions.get());
+
+ const Extension* extension = GetExtension();
+ ExtensionPermissionsManager* perms_manager =
+ profile()->GetExtensionService()->permissions_manager();
+ ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
+
+ // Make sure they're only trying to remove permissions supported by this API.
+ scoped_refptr<ExtensionPermissionSet> unsupported(
+ ExtensionPermissionSet::CreateDifference(
+ permissions.get(), &perms_manager->whitelist()));
+ if (unsupported->apis().size()) {
+ std::string api_name = info->GetByID(*unsupported->apis().begin())->name();
+ error_ = base::StringPrintf(keys::kNotWhitelistedError, api_name.c_str());
+ return false;
+ }
+
+ // Make sure we don't remove any required pemissions.
+ const ExtensionPermissionSet* required = extension->required_permission_set();
+ scoped_refptr<ExtensionPermissionSet> intersection(
+ ExtensionPermissionSet::CreateIntersection(permissions.get(), required));
+ if (!intersection->IsEmpty()) {
+ error_ = keys::kCantRemoveRequiredPermissionsError;
+ result_.reset(Value::CreateBooleanValue(false));
+ return false;
+ }
+
+ perms_manager->RemovePermissions(extension, permissions.get());
+ result_.reset(Value::CreateBooleanValue(true));
+ return true;
+}
+
+// static
+void RequestPermissionsFunction::SetAutoConfirmForTests(bool should_proceed) {
+ auto_confirm_for_tests = should_proceed ? PROCEED : ABORT;
+}
+
+RequestPermissionsFunction::RequestPermissionsFunction() {}
+RequestPermissionsFunction::~RequestPermissionsFunction() {}
+
+bool RequestPermissionsFunction::RunImpl() {
+ DictionaryValue* args = NULL;
+ EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
+ if (!args)
+ return false;
+
+ if (!UnpackPermissionsFromValue(
+ args, &requested_permissions_, &bad_message_, &error_))
+ return false;
+ CHECK(requested_permissions_.get());
+
+ extension_ = GetExtension();
+ ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
+ ExtensionPermissionsManager* perms_manager =
+ profile()->GetExtensionService()->permissions_manager();
+ ExtensionPrefs* prefs = profile()->GetExtensionService()->extension_prefs();
+
+ // Make sure only white listed permissions have been requested.
+ scoped_refptr<ExtensionPermissionSet> unsupported(
+ ExtensionPermissionSet::CreateDifference(
+ requested_permissions_.get(), &perms_manager->whitelist()));
+ if (unsupported->apis().size()) {
+ std::string api_name = info->GetByID(*unsupported->apis().begin())->name();
+ error_ = base::StringPrintf(keys::kNotWhitelistedError, api_name.c_str());
+ return false;
+ }
+
+ // The requested permissions must be defined as optional in the manifest.
+ if (!extension_->optional_permission_set()->Contains(
+ *requested_permissions_)) {
+ error_ = keys::kNotInOptionalPermissionsError;
+ result_.reset(Value::CreateBooleanValue(false));
+ return false;
+ }
+
+ // We don't need to prompt the user if the requested permissions are a subset
+ // of the granted permissions set.
+ const ExtensionPermissionSet* granted =
+ prefs->GetGrantedPermissions(extension_->id());
+ if (granted && granted->Contains(*requested_permissions_)) {
+ perms_manager->AddPermissions(extension_, requested_permissions_.get());
+ result_.reset(Value::CreateBooleanValue(true));
+ SendResponse(true);
+ return true;
+ }
+
+ // Filter out the granted permissions so we only prompt for new ones.
+ requested_permissions_ = ExtensionPermissionSet::CreateDifference(
+ requested_permissions_.get(), granted);
+
+ // Balanced with Release() in InstallUIProceed() and InstallUIAbort().
+ AddRef();
+
+ // We don't need to show the prompt if there are no new warnings, or if
+ // we're skipping the confirmation UI. All extension types but INTERNAL
+ // are allowed to silently increase their permission level.
+ if (auto_confirm_for_tests == PROCEED ||
+ requested_permissions_->GetWarningMessages().size() == 0) {
+ InstallUIProceed();
+ } else if (auto_confirm_for_tests == ABORT) {
+ // Pretend the user clicked cancel.
+ InstallUIAbort(true);
+ } else {
+ CHECK_EQ(DO_NOT_SKIP, auto_confirm_for_tests);
+ install_ui_.reset(new ExtensionInstallUI(profile()));
+ install_ui_->ConfirmPermissions(
+ this, extension_, requested_permissions_.get());
+ }
+
+ return true;
+}
+
+void RequestPermissionsFunction::InstallUIProceed() {
+ ExtensionPermissionsManager* perms_manager =
+ profile()->GetExtensionService()->permissions_manager();
+
+ install_ui_.reset();
+ result_.reset(Value::CreateBooleanValue(true));
+ perms_manager->AddPermissions(extension_, requested_permissions_.get());
+
+ SendResponse(true);
+
+ Release();
+}
+
+void RequestPermissionsFunction::InstallUIAbort(bool user_initiated) {
+ install_ui_.reset();
+ result_.reset(Value::CreateBooleanValue(false));
+ requested_permissions_ = NULL;
+
+ SendResponse(true);
+ Release();
+}
diff --git a/chrome/browser/extensions/extension_permissions_api.h b/chrome/browser/extensions/extension_permissions_api.h
new file mode 100644
index 0000000..35da6ca
--- /dev/null
+++ b/chrome/browser/extensions/extension_permissions_api.h
@@ -0,0 +1,119 @@
+// 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.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_PERMISSIONS_API_H__
+#define CHROME_BROWSER_EXTENSIONS_EXTENSION_PERMISSIONS_API_H__
+#pragma once
+
+#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/browser/extensions/extension_install_ui.h"
+#include "chrome/common/extensions/extension_permission_set.h"
+#include "chrome/common/chrome_notification_types.h"
+#include "content/browser/renderer_host/render_process_host.h"
+#include "content/common/notification_service.h"
+
+namespace base {
+class DictionaryValue;
+}
+class Extension;
+class ExtensionPermissionSet;
+class ExtensionService;
+class Profile;
+
+class ExtensionPermissionsManager {
+ public:
+ explicit ExtensionPermissionsManager(ExtensionService* extension_service);
+ ~ExtensionPermissionsManager();
+
+ // Adds the set of |permissions| to the |extension|'s active permission set
+ // and sends the relevant messages and notifications. This method assumes the
+ // user has already been prompted, if necessary, for the extra permissions.
+ void AddPermissions(const Extension* extension,
+ const ExtensionPermissionSet* permissions);
+
+ // Removes the set of |permissions| from the |extension|'s active permission
+ // set and sends the relevant messages and notifications.
+ void RemovePermissions(const Extension* extension,
+ const ExtensionPermissionSet* permissions);
+
+ // Returns the list of API permissions that are supported by the optional
+ // permissions API.
+ const ExtensionPermissionSet& whitelist() const { return *whitelist_; }
+
+ private:
+ enum EventType {
+ ADDED,
+ REMOVED,
+ };
+
+ // Dispatches specified event to the extension.
+ void DispatchEvent(const std::string& extension_id,
+ const char* event_name,
+ const ExtensionPermissionSet* changed_permissions);
+
+ // Issues the relevant events, messages and notifications when the permissions
+ // have changed for the |extension| (|changed| is the permission delta, while
+ // |active| is the new permission set). Specifically, this sends the
+ // EXTENSION_PERMISSIONS_UPDATED notification, the
+ // ExtensionMsg_UpdatePermissions IPC message, and fires the onAdded/onRemoved
+ // events in the extension.
+ void NotifyPermissionsUpdated(const Extension* extension,
+ const ExtensionPermissionSet* active,
+ const ExtensionPermissionSet* changed,
+ EventType event_type);
+
+ // Registers the list of APIs supported by the optional permissions API.
+ void RegisterWhitelist();
+
+ ExtensionService* extension_service_;
+ scoped_refptr<ExtensionPermissionSet> whitelist_;
+};
+
+
+// chrome.permissions.contains
+class ContainsPermissionsFunction : public SyncExtensionFunction {
+ virtual ~ContainsPermissionsFunction() {}
+ virtual bool RunImpl() OVERRIDE;
+ DECLARE_EXTENSION_FUNCTION_NAME("experimental.permissions.contains")
+};
+
+// chrome.permissions.getAll
+class GetAllPermissionsFunction : public SyncExtensionFunction {
+ virtual ~GetAllPermissionsFunction() {}
+ virtual bool RunImpl() OVERRIDE;
+ DECLARE_EXTENSION_FUNCTION_NAME("experimental.permissions.getAll")
+};
+
+// chrome.permissions.remove
+class RemovePermissionsFunction : public SyncExtensionFunction {
+ virtual ~RemovePermissionsFunction() {}
+ virtual bool RunImpl() OVERRIDE;
+ DECLARE_EXTENSION_FUNCTION_NAME("experimental.permissions.remove")
+};
+
+// chrome.permissions.request
+class RequestPermissionsFunction : public AsyncExtensionFunction,
+ public ExtensionInstallUI::Delegate {
+ public:
+ // FOR TESTS ONLY to bypass the confirmation UI.
+ static void SetAutoConfirmForTests(bool should_proceed);
+
+ RequestPermissionsFunction();
+
+ // Implementing ExtensionInstallUI::Delegate interface.
+ virtual void InstallUIProceed() OVERRIDE;
+ virtual void InstallUIAbort(bool user_initiated) OVERRIDE;
+
+ protected:
+ virtual ~RequestPermissionsFunction();
+ virtual bool RunImpl() OVERRIDE;
+
+ private:
+ scoped_ptr<ExtensionInstallUI> install_ui_;
+ scoped_refptr<ExtensionPermissionSet> requested_permissions_;
+ const Extension* extension_;
+ DECLARE_EXTENSION_FUNCTION_NAME("experimental.permissions.request")
+};
+
+#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_PERMISSIONS_API_H__
diff --git a/chrome/browser/extensions/extension_permissions_api_constants.cc b/chrome/browser/extensions/extension_permissions_api_constants.cc
new file mode 100644
index 0000000..5d75ccd
--- /dev/null
+++ b/chrome/browser/extensions/extension_permissions_api_constants.cc
@@ -0,0 +1,23 @@
+// 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 "chrome/browser/extensions/extension_permissions_api_constants.h"
+
+namespace extension_permissions_module_constants {
+
+const char kApisKey[] = "permissions";
+
+const char kCantRemoveRequiredPermissionsError[] =
+ "You cannot remove required permissions.";
+const char kNotInOptionalPermissionsError[] =
+ "Optional permissions must be listed in extension manifest.";
+const char kNotWhitelistedError[] =
+ "The optional permissions API does not support '%s'.";
+const char kUnknownPermissionError[] =
+ "'%s' is not a recognized permission.";
+
+const char kOnAdded[] = "experimental.permissions.onAdded";
+const char kOnRemoved[] = "experimental.permissions.onRemoved";
+
+}; // namespace extension_permissions_module_constants
diff --git a/chrome/browser/extensions/extension_permissions_api_constants.h b/chrome/browser/extensions/extension_permissions_api_constants.h
new file mode 100644
index 0000000..64b5116
--- /dev/null
+++ b/chrome/browser/extensions/extension_permissions_api_constants.h
@@ -0,0 +1,28 @@
+// 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.
+
+// Constants used for the Tabs API and the Windows API.
+
+#ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_PERMISSIONS_API_CONSTANTS_H_
+#define CHROME_BROWSER_EXTENSIONS_EXTENSION_PERMISSIONS_API_CONSTANTS_H_
+#pragma once
+
+namespace extension_permissions_module_constants {
+
+// Keys used in serializing permissions data and events.
+extern const char kApisKey[];
+
+// Error messages.
+extern const char kCantRemoveRequiredPermissionsError[];
+extern const char kNotInOptionalPermissionsError[];
+extern const char kNotWhitelistedError[];
+extern const char kUnknownPermissionError[];
+
+// Event names.
+extern const char kOnAdded[];
+extern const char kOnRemoved[];
+
+}; // namespace extension_permissions_module_constants
+
+#endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_PERMISSIONS_API_CONSTANTS_H_
diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc
index 334b64f..e0a8d6e 100644
--- a/chrome/browser/extensions/extension_prefs.cc
+++ b/chrome/browser/extensions/extension_prefs.cc
@@ -102,11 +102,15 @@ const char kBrowserActionVisible[] = "browser_action_visible";
// Preferences that hold which permissions the user has granted the extension.
// We explicitly keep track of these so that extensions can contain unknown
// permissions, for backwards compatibility reasons, and we can still prompt
-// the user to accept them once recognized.
-const char kPrefGrantedAPIs[] = "granted_permissions.api";
-const char kPrefGrantedExplicitHosts[] = "granted_permissions.explicit_host";
-const char kPrefGrantedScriptableHosts[] =
- "granted_permissions.scriptable_host";
+// the user to accept them once recognized. We store the active permission
+// permissions because they may differ from those defined in the manifest.
+const char kPrefActivePermissions[] = "active_permissions";
+const char kPrefGrantedPermissions[] = "granted_permissions";
+
+// The preference names for ExtensionPermissionSet values.
+const char kPrefAPIs[] = "api";
+const char kPrefExplicitHosts[] = "explicit_host";
+const char kPrefScriptableHosts[] = "scriptable_host";
// The preference names for the old granted permissions scheme.
const char kPrefOldGrantedFullAccess[] = "granted_permissions.full";
@@ -206,6 +210,10 @@ class ScopedExtensionControlledPrefUpdate : public DictionaryPrefUpdate {
DISALLOW_COPY_AND_ASSIGN(ScopedExtensionControlledPrefUpdate);
};
+std::string JoinPrefs(std::string parent, const char* child) {
+ return parent + "." + child;
+}
+
} // namespace
ExtensionPrefs::ExtensionPrefs(
@@ -423,6 +431,75 @@ void ExtensionPrefs::SetExtensionPrefURLPatternSet(
UpdateExtensionPref(extension_id, pref_key, value);
}
+ExtensionPermissionSet* ExtensionPrefs::ReadExtensionPrefPermissionSet(
+ const std::string& extension_id,
+ const std::string& pref_key) {
+ if (!GetExtensionPref(extension_id))
+ return NULL;
+
+ // Retrieve the API permissions.
+ ExtensionAPIPermissionSet apis;
+ const ListValue* api_values = NULL;
+ std::string api_pref = JoinPrefs(pref_key, kPrefAPIs);
+ if (ReadExtensionPrefList(extension_id, api_pref, &api_values)) {
+ ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
+ for (size_t i = 0; i < api_values->GetSize(); ++i) {
+ std::string permission_name;
+ if (api_values->GetString(i, &permission_name)) {
+ ExtensionAPIPermission *permission = info->GetByName(permission_name);
+ if (permission)
+ apis.insert(permission->id());
+ }
+ }
+ }
+
+ // Retrieve the explicit host permissions.
+ URLPatternSet explicit_hosts;
+ ReadExtensionPrefURLPatternSet(
+ extension_id, JoinPrefs(pref_key, kPrefExplicitHosts),
+ &explicit_hosts, Extension::kValidHostPermissionSchemes);
+
+ // Retrieve the scriptable host permissions.
+ URLPatternSet scriptable_hosts;
+ ReadExtensionPrefURLPatternSet(
+ extension_id, JoinPrefs(pref_key, kPrefScriptableHosts),
+ &scriptable_hosts, UserScript::kValidUserScriptSchemes);
+
+ return new ExtensionPermissionSet(apis, explicit_hosts, scriptable_hosts);
+}
+
+void ExtensionPrefs::SetExtensionPrefPermissionSet(
+ const std::string& extension_id,
+ const std::string& pref_key,
+ const ExtensionPermissionSet* new_value) {
+ // Set the API permissions.
+ ListValue* api_values = new ListValue();
+ ExtensionAPIPermissionSet apis = new_value->apis();
+ ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
+ std::string api_pref = JoinPrefs(pref_key, kPrefAPIs);
+ for (ExtensionAPIPermissionSet::const_iterator i = apis.begin();
+ i != apis.end(); ++i) {
+ ExtensionAPIPermission* perm = info->GetByID(*i);
+ if (perm)
+ api_values->Append(Value::CreateStringValue(perm->name()));
+ }
+ UpdateExtensionPref(extension_id, api_pref, api_values);
+
+ // Set the explicit host permissions.
+ if (!new_value->explicit_hosts().is_empty()) {
+ SetExtensionPrefURLPatternSet(extension_id,
+ JoinPrefs(pref_key, kPrefExplicitHosts),
+ new_value->explicit_hosts());
+ }
+
+ // Set the scriptable host permissions.
+ if (!new_value->scriptable_hosts().is_empty()) {
+ SetExtensionPrefURLPatternSet(extension_id,
+ JoinPrefs(pref_key, kPrefScriptableHosts),
+ new_value->scriptable_hosts());
+ }
+}
+
void ExtensionPrefs::SavePrefs() {
prefs_->ScheduleSavePersistentPrefs();
}
@@ -638,7 +715,9 @@ void ExtensionPrefs::MigratePermissions(const ExtensionIdSet& extension_ids) {
ListValue* apis = NULL;
ListValue* new_apis = NULL;
- if (ext->GetList(kPrefGrantedAPIs, &apis))
+ std::string granted_apis =
+ JoinPrefs(kPrefGrantedPermissions, kPrefAPIs);
+ if (ext->GetList(kPrefOldGrantedAPIs, &apis))
new_apis = apis->DeepCopy();
else
new_apis = new ListValue();
@@ -646,7 +725,7 @@ void ExtensionPrefs::MigratePermissions(const ExtensionIdSet& extension_ids) {
std::string plugin_name = info->GetByID(
ExtensionAPIPermission::kPlugin)->name();
new_apis->Append(Value::CreateStringValue(plugin_name));
- UpdateExtensionPref(*ext_id, kPrefGrantedAPIs, new_apis);
+ UpdateExtensionPref(*ext_id, granted_apis, new_apis);
}
// The granted permissions originally only held the effective hosts,
@@ -656,9 +735,11 @@ void ExtensionPrefs::MigratePermissions(const ExtensionIdSet& extension_ids) {
// new effective hosts will be the same, so we move them to explicit
// host permissions.
ListValue* hosts;
+ std::string explicit_hosts =
+ JoinPrefs(kPrefGrantedPermissions, kPrefExplicitHosts);
if (ext->GetList(kPrefOldGrantedHosts, &hosts)) {
UpdateExtensionPref(
- *ext_id, kPrefGrantedExplicitHosts, hosts->DeepCopy());
+ *ext_id, explicit_hosts, hosts->DeepCopy());
// We can get rid of the old one by setting it to an empty list.
UpdateExtensionPref(*ext_id, kPrefOldGrantedHosts, new ListValue());
@@ -669,39 +750,7 @@ void ExtensionPrefs::MigratePermissions(const ExtensionIdSet& extension_ids) {
ExtensionPermissionSet* ExtensionPrefs::GetGrantedPermissions(
const std::string& extension_id) {
CHECK(Extension::IdIsValid(extension_id));
-
- const DictionaryValue* ext = GetExtensionPref(extension_id);
- if (!ext)
- return NULL;
-
- // Retrieve the API permissions.
- ExtensionAPIPermissionSet apis;
- const ListValue* api_values = NULL;
- if (ReadExtensionPrefList(extension_id, kPrefGrantedAPIs, &api_values)) {
- ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
- for (size_t i = 0; i < api_values->GetSize(); ++i) {
- std::string permission_name;
- if (api_values->GetString(i, &permission_name)) {
- ExtensionAPIPermission *permission = info->GetByName(permission_name);
- if (permission)
- apis.insert(permission->id());
- }
- }
- }
-
- // Retrieve the explicit host permissions.
- URLPatternSet explicit_hosts;
- ReadExtensionPrefURLPatternSet(
- extension_id, kPrefGrantedExplicitHosts,
- &explicit_hosts, Extension::kValidHostPermissionSchemes);
-
- // Retrieve the scriptable host permissions.
- URLPatternSet scriptable_hosts;
- ReadExtensionPrefURLPatternSet(
- extension_id, kPrefGrantedScriptableHosts,
- &scriptable_hosts, UserScript::kValidUserScriptSchemes);
-
- return new ExtensionPermissionSet(apis, explicit_hosts, scriptable_hosts);
+ return ReadExtensionPrefPermissionSet(extension_id, kPrefGrantedPermissions);
}
void ExtensionPrefs::AddGrantedPermissions(
@@ -709,40 +758,30 @@ void ExtensionPrefs::AddGrantedPermissions(
const ExtensionPermissionSet* permissions) {
CHECK(Extension::IdIsValid(extension_id));
- scoped_ptr<ExtensionPermissionSet> granted_permissions(
+ scoped_refptr<ExtensionPermissionSet> granted_permissions(
GetGrantedPermissions(extension_id));
// The new granted permissions are the union of the already granted
// permissions and the newly granted permissions.
- scoped_ptr<ExtensionPermissionSet> new_perms(
+ scoped_refptr<ExtensionPermissionSet> new_perms(
ExtensionPermissionSet::CreateUnion(
permissions, granted_permissions.get()));
- // Set the API permissions.
- ListValue* api_values = new ListValue();
- ExtensionAPIPermissionSet apis = new_perms->apis();
- ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
- for (ExtensionAPIPermissionSet::const_iterator i = apis.begin();
- i != apis.end(); ++i) {
- ExtensionAPIPermission* perm = info->GetByID(*i);
- if (perm)
- api_values->Append(Value::CreateStringValue(perm->name()));
- }
- UpdateExtensionPref(extension_id, kPrefGrantedAPIs, api_values);
+ SetExtensionPrefPermissionSet(
+ extension_id, kPrefGrantedPermissions, new_perms.get());
+}
- // Set the explicit host permissions.
- if (!new_perms->explicit_hosts().is_empty()) {
- SetExtensionPrefURLPatternSet(extension_id,
- kPrefGrantedExplicitHosts,
- new_perms->explicit_hosts());
- }
+ExtensionPermissionSet* ExtensionPrefs::GetActivePermissions(
+ const std::string& extension_id) {
+ CHECK(Extension::IdIsValid(extension_id));
+ return ReadExtensionPrefPermissionSet(extension_id, kPrefActivePermissions);
+}
- // Set the scriptable host permissions.
- if (!new_perms->scriptable_hosts().is_empty()) {
- SetExtensionPrefURLPatternSet(extension_id,
- kPrefGrantedScriptableHosts,
- new_perms->scriptable_hosts());
- }
+void ExtensionPrefs::SetActivePermissions(
+ const std::string& extension_id,
+ const ExtensionPermissionSet* permissions) {
+ SetExtensionPrefPermissionSet(
+ extension_id, kPrefActivePermissions, permissions);
}
bool ExtensionPrefs::IsIncognitoEnabled(const std::string& extension_id) {
diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h
index 6b5ffd4..92f8672 100644
--- a/chrome/browser/extensions/extension_prefs.h
+++ b/chrome/browser/extensions/extension_prefs.h
@@ -187,6 +187,16 @@ class ExtensionPrefs : public ExtensionContentSettingsStore::Observer {
void AddGrantedPermissions(const std::string& extension_id,
const ExtensionPermissionSet* permissions);
+ // Gets the active permission set for the specified extension. This may
+ // differ from the permissions in the manifest due to the optional
+ // permissions API. This passes ownership of the set to the caller.
+ ExtensionPermissionSet* GetActivePermissions(
+ const std::string& extension_id);
+
+ // Sets the active |permissions| for the extension with |extension_id|.
+ void SetActivePermissions(const std::string& extension_id,
+ const ExtensionPermissionSet* permissions);
+
// Returns true if the user enabled this extension to be loaded in incognito
// mode.
bool IsIncognitoEnabled(const std::string& extension_id);
@@ -409,6 +419,18 @@ class ExtensionPrefs : public ExtensionContentSettingsStore::Observer {
const std::string& pref_key,
const URLPatternSet& new_value);
+ // Interprets |pref_key| in |extension_id|'s preferences as an
+ // ExtensionPermissionSet, and passes ownership of the set to the caller.
+ ExtensionPermissionSet* ReadExtensionPrefPermissionSet(
+ const std::string& extension_id,
+ const std::string& pref_key);
+
+ // Converts the |new_value| to its value and sets the |pref_key| pref
+ // belonging to |extension_id|.
+ void SetExtensionPrefPermissionSet(const std::string& extension_id,
+ const std::string& pref_key,
+ const ExtensionPermissionSet* new_value);
+
// Returns a dictionary for extension |id|'s prefs or NULL if it doesn't
// exist.
const base::DictionaryValue* GetExtensionPref(const std::string& id) const;
diff --git a/chrome/browser/extensions/extension_prefs_unittest.cc b/chrome/browser/extensions/extension_prefs_unittest.cc
index f582077..2ed6588 100644
--- a/chrome/browser/extensions/extension_prefs_unittest.cc
+++ b/chrome/browser/extensions/extension_prefs_unittest.cc
@@ -219,32 +219,32 @@ class ExtensionPrefsGrantedPermissions : public ExtensionPrefsTest {
ExtensionAPIPermissionSet empty_set;
URLPatternSet empty_extent;
- scoped_ptr<ExtensionPermissionSet> permissions;
- scoped_ptr<ExtensionPermissionSet> granted_permissions;
+ scoped_refptr<ExtensionPermissionSet> permissions;
+ scoped_refptr<ExtensionPermissionSet> granted_permissions;
// Make sure both granted api and host permissions start empty.
- granted_permissions.reset(
- prefs()->GetGrantedPermissions(extension_id_));
+ granted_permissions =
+ prefs()->GetGrantedPermissions(extension_id_);
EXPECT_TRUE(granted_permissions->IsEmpty());
- permissions.reset(new ExtensionPermissionSet(
- api_perm_set1_, empty_extent, empty_extent));
+ permissions = new ExtensionPermissionSet(
+ api_perm_set1_, empty_extent, empty_extent);
// Add part of the api permissions.
prefs()->AddGrantedPermissions(extension_id_, permissions.get());
- granted_permissions.reset(prefs()->GetGrantedPermissions(extension_id_));
+ granted_permissions = prefs()->GetGrantedPermissions(extension_id_);
EXPECT_TRUE(granted_permissions.get());
EXPECT_FALSE(granted_permissions->IsEmpty());
EXPECT_EQ(expected_apis, granted_permissions->apis());
EXPECT_TRUE(granted_permissions->effective_hosts().is_empty());
EXPECT_FALSE(granted_permissions->HasEffectiveFullAccess());
- granted_permissions.reset();
+ granted_permissions = NULL;
// Add part of the explicit host permissions.
- permissions.reset(new ExtensionPermissionSet(
- empty_set, ehost_perm_set1_, empty_extent));
+ permissions = new ExtensionPermissionSet(
+ empty_set, ehost_perm_set1_, empty_extent);
prefs()->AddGrantedPermissions(extension_id_, permissions.get());
- granted_permissions.reset(prefs()->GetGrantedPermissions(extension_id_));
+ granted_permissions = prefs()->GetGrantedPermissions(extension_id_);
EXPECT_FALSE(granted_permissions->IsEmpty());
EXPECT_FALSE(granted_permissions->HasEffectiveFullAccess());
EXPECT_EQ(expected_apis, granted_permissions->apis());
@@ -254,10 +254,10 @@ class ExtensionPrefsGrantedPermissions : public ExtensionPrefsTest {
granted_permissions->effective_hosts());
// Add part of the scriptable host permissions.
- permissions.reset(new ExtensionPermissionSet(
- empty_set, empty_extent, shost_perm_set1_));
+ permissions = new ExtensionPermissionSet(
+ empty_set, empty_extent, shost_perm_set1_);
prefs()->AddGrantedPermissions(extension_id_, permissions.get());
- granted_permissions.reset(prefs()->GetGrantedPermissions(extension_id_));
+ granted_permissions = prefs()->GetGrantedPermissions(extension_id_);
EXPECT_FALSE(granted_permissions->IsEmpty());
EXPECT_FALSE(granted_permissions->HasEffectiveFullAccess());
EXPECT_EQ(expected_apis, granted_permissions->apis());
@@ -271,15 +271,15 @@ class ExtensionPrefsGrantedPermissions : public ExtensionPrefsTest {
EXPECT_EQ(effective_permissions_, granted_permissions->effective_hosts());
// Add the rest of both the permissions.
- permissions.reset(new ExtensionPermissionSet(
- api_perm_set2_, ehost_perm_set2_, shost_perm_set2_));
+ permissions = new ExtensionPermissionSet(
+ api_perm_set2_, ehost_perm_set2_, shost_perm_set2_);
std::set_union(expected_apis.begin(), expected_apis.end(),
api_perm_set2_.begin(), api_perm_set2_.end(),
std::inserter(api_permissions_, api_permissions_.begin()));
prefs()->AddGrantedPermissions(extension_id_, permissions.get());
- granted_permissions.reset(prefs()->GetGrantedPermissions(extension_id_));
+ granted_permissions = prefs()->GetGrantedPermissions(extension_id_);
EXPECT_TRUE(granted_permissions.get());
EXPECT_FALSE(granted_permissions->IsEmpty());
EXPECT_EQ(api_permissions_, granted_permissions->apis());
@@ -294,7 +294,7 @@ class ExtensionPrefsGrantedPermissions : public ExtensionPrefsTest {
}
virtual void Verify() {
- scoped_ptr<ExtensionPermissionSet> permissions(
+ scoped_refptr<ExtensionPermissionSet> permissions(
prefs()->GetGrantedPermissions(extension_id_));
EXPECT_TRUE(permissions.get());
EXPECT_FALSE(permissions->HasEffectiveFullAccess());
@@ -321,6 +321,54 @@ class ExtensionPrefsGrantedPermissions : public ExtensionPrefsTest {
};
TEST_F(ExtensionPrefsGrantedPermissions, GrantedPermissions) {}
+// Tests the SetActivePermissions / GetActivePermissions functions.
+class ExtensionPrefsActivePermissions : public ExtensionPrefsTest {
+ public:
+ virtual void Initialize() {
+ extension_id_ = prefs_.AddExtensionAndReturnId("test");
+
+ ExtensionAPIPermissionSet api_perms;
+ api_perms.insert(ExtensionAPIPermission::kTab);
+ api_perms.insert(ExtensionAPIPermission::kBookmark);
+ api_perms.insert(ExtensionAPIPermission::kHistory);
+
+ URLPatternSet ehosts;
+ AddPattern(&ehosts, "http://*.google.com/*");
+ AddPattern(&ehosts, "http://example.com/*");
+ AddPattern(&ehosts, "chrome://favicon/*");
+
+ URLPatternSet shosts;
+ AddPattern(&shosts, "https://*.google.com/*");
+ AddPattern(&shosts, "http://reddit.com/r/test/*");
+
+ active_perms_ = new ExtensionPermissionSet(api_perms, ehosts, shosts);
+
+ // Make sure the active permissions start empty.
+ scoped_refptr<ExtensionPermissionSet> active(
+ prefs()->GetActivePermissions(extension_id_));
+ EXPECT_TRUE(active->IsEmpty());
+
+ // Set the active permissions.
+ prefs()->SetActivePermissions(extension_id_, active_perms_.get());
+ active = prefs()->GetActivePermissions(extension_id_);
+ EXPECT_EQ(active_perms_->apis(), active->apis());
+ EXPECT_EQ(active_perms_->explicit_hosts(), active->explicit_hosts());
+ EXPECT_EQ(active_perms_->scriptable_hosts(), active->scriptable_hosts());
+ EXPECT_EQ(*active_perms_, *active);
+ }
+
+ virtual void Verify() {
+ scoped_refptr<ExtensionPermissionSet> permissions(
+ prefs()->GetActivePermissions(extension_id_));
+ EXPECT_EQ(*active_perms_, *permissions);
+ }
+
+ private:
+ std::string extension_id_;
+ scoped_refptr<ExtensionPermissionSet> active_perms_;
+};
+TEST_F(ExtensionPrefsActivePermissions, SetAndGetActivePermissions) {}
+
// Tests the GetVersionString function.
class ExtensionPrefsVersionString : public ExtensionPrefsTest {
public:
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index 5ff972e..72667a1 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -552,6 +552,7 @@ ExtensionService::ExtensionService(Profile* profile,
show_extensions_prompts_(true),
ready_(false),
toolbar_model_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
+ permissions_manager_(ALLOW_THIS_IN_INITIALIZER_LIST(this)),
apps_promo_(profile->GetPrefs()),
event_routers_initialized_(false) {
CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
@@ -974,11 +975,13 @@ void ExtensionService::DisableExtension(const std::string& extension_id) {
void ExtensionService::GrantPermissions(const Extension* extension) {
CHECK(extension);
- // We only maintain the granted permissions prefs for INTERNAL extensions.
- CHECK_EQ(Extension::INTERNAL, extension->location());
+ // We only maintain the granted permissions prefs for extensions that can't
+ // silently increase their permissions.
+ if (extension->CanSilentlyIncreasePermissions())
+ return;
extension_prefs_->AddGrantedPermissions(extension->id(),
- extension->permission_set());
+ extension->GetActivePermissions());
}
void ExtensionService::GrantPermissionsAndEnableExtension(
@@ -991,6 +994,13 @@ void ExtensionService::GrantPermissionsAndEnableExtension(
EnableExtension(extension->id());
}
+void ExtensionService::UpdateActivePermissions(
+ const Extension* extension,
+ const ExtensionPermissionSet* permissions) {
+ extension_prefs()->SetActivePermissions(extension->id(), permissions);
+ extension->SetActivePermissions(permissions);
+}
+
void ExtensionService::LoadExtension(const FilePath& extension_path) {
BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
NewRunnableMethod(backend_.get(),
@@ -1356,7 +1366,8 @@ void ExtensionService::NotifyExtensionLoaded(const Extension* extension) {
if (host->profile()->GetOriginalProfile() ==
profile_->GetOriginalProfile()) {
host->Send(
- new ExtensionMsg_Loaded(ExtensionMsg_Loaded_Params(extension)));
+ new ExtensionMsg_Loaded(ExtensionMsg_Loaded_Params(
+ extension, extension->GetActivePermissions())));
}
}
@@ -1964,7 +1975,7 @@ void ExtensionService::AddExtension(const Extension* extension) {
// Check if the extension's privileges have changed and disable the
// extension if necessary.
- DisableIfPrivilegeIncrease(extension);
+ InitializePermissions(extension);
bool disabled = Extension::UserMayDisable(extension->location()) &&
extension_prefs_->GetExtensionState(extension->id()) ==
@@ -1985,7 +1996,35 @@ void ExtensionService::AddExtension(const Extension* extension) {
NotifyExtensionLoaded(extension);
}
-void ExtensionService::DisableIfPrivilegeIncrease(const Extension* extension) {
+void ExtensionService::InitializePermissions(const Extension* extension) {
+ // If the extension has used the optional permissions API, it will have a
+ // custom set of active permissions defined in the extension prefs. Here,
+ // we update the extension's active permissions based on the prefs.
+ scoped_refptr<ExtensionPermissionSet> active_permissions =
+ extension_prefs()->GetActivePermissions(extension->id());
+
+ if (active_permissions.get()) {
+ // We restrict the active permissions to be within the bounds defined in the
+ // extension's manifest.
+ // a) active permissions must be a subset of optional + default permissions
+ // b) active permissions must contains all default permissions
+ scoped_refptr<ExtensionPermissionSet> total_permissions =
+ ExtensionPermissionSet::CreateUnion(
+ extension->required_permission_set(),
+ extension->optional_permission_set());
+
+ // Make sure the active permissions contain no more than optional + default.
+ scoped_refptr<ExtensionPermissionSet> adjusted_active =
+ ExtensionPermissionSet::CreateIntersection(
+ total_permissions.get(), active_permissions.get());
+
+ // Make sure the active permissions contain the default permissions.
+ adjusted_active = ExtensionPermissionSet::CreateUnion(
+ extension->required_permission_set(), adjusted_active.get());
+
+ UpdateActivePermissions(extension, adjusted_active);
+ }
+
// We keep track of all permissions the user has granted each extension.
// This allows extensions to gracefully support backwards compatibility
// by including unknown permissions in their manifests. When the user
@@ -2012,13 +2051,13 @@ void ExtensionService::DisableIfPrivilegeIncrease(const Extension* extension) {
bool is_extension_upgrade = old != NULL;
bool is_privilege_increase = false;
- // We only record the granted permissions for INTERNAL extensions, since
- // they can't silently increase privileges.
- if (extension->location() == Extension::INTERNAL) {
+ // We only need to compare the granted permissions to the current permissions
+ // if the extension is not allowed to silently increase its permissions.
+ if (!extension->CanSilentlyIncreasePermissions()) {
// Add all the recognized permissions if the granted permissions list
// hasn't been initialized yet.
- scoped_ptr<ExtensionPermissionSet> granted_permissions(
- extension_prefs_->GetGrantedPermissions(extension->id()));
+ scoped_refptr<ExtensionPermissionSet> granted_permissions =
+ extension_prefs_->GetGrantedPermissions(extension->id());
CHECK(granted_permissions.get());
// Here, we check if an extension's privileges have increased in a manner
@@ -2026,7 +2065,8 @@ void ExtensionService::DisableIfPrivilegeIncrease(const Extension* extension) {
// upgraded and recognized additional privileges, or an extension upgrades
// to a version that requires additional privileges.
is_privilege_increase =
- granted_permissions->HasLessPrivilegesThan(extension->permission_set());
+ granted_permissions->HasLessPrivilegesThan(
+ extension->GetActivePermissions());
}
if (is_extension_upgrade) {
@@ -2378,7 +2418,8 @@ void ExtensionService::Observe(int type,
// Loaded extensions.
for (size_t i = 0; i < extensions_.size(); ++i) {
process->Send(new ExtensionMsg_Loaded(
- ExtensionMsg_Loaded_Params(extensions_[i])));
+ ExtensionMsg_Loaded_Params(
+ extensions_[i], extensions_[i]->GetActivePermissions())));
}
break;
}
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h
index 4c74f0a..901726f 100644
--- a/chrome/browser/extensions/extension_service.h
+++ b/chrome/browser/extensions/extension_service.h
@@ -26,6 +26,7 @@
#include "chrome/browser/extensions/extension_icon_manager.h"
#include "chrome/browser/extensions/extension_menu_manager.h"
#include "chrome/browser/extensions/extension_prefs.h"
+#include "chrome/browser/extensions/extension_permissions_api.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_toolbar_model.h"
#include "chrome/browser/extensions/extensions_quota_service.h"
@@ -320,6 +321,10 @@ class ExtensionService
// extension.
void GrantPermissionsAndEnableExtension(const Extension* extension);
+ // Sets the |extension|'s active permissions to |permissions|.
+ void UpdateActivePermissions(const Extension* extension,
+ const ExtensionPermissionSet* permissions);
+
// Loads the extension from the directory |extension_path|.
void LoadExtension(const FilePath& extension_path);
@@ -405,9 +410,9 @@ class ExtensionService
void OnExtensionInstalled(
const Extension* extension, bool from_webstore);
- // Checks if the privileges requested by |extension| have increased, and if
- // so, disables the extension and prompts the user to approve the change.
- void DisableIfPrivilegeIncrease(const Extension* extension);
+ // Initializes the |extension|'s active permission set and disables the
+ // extension if the privilege level has increased (e.g., due to an upgrade).
+ void InitializePermissions(const Extension* extension);
// Go through each extensions in pref, unload blacklisted extensions
// and update the blacklist state in pref.
@@ -468,6 +473,10 @@ class ExtensionService
return &app_notification_manager_;
}
+ ExtensionPermissionsManager* permissions_manager() {
+ return &permissions_manager_;
+ }
+
ExtensionBrowserEventRouter* browser_event_router() {
return browser_event_router_.get();
}
@@ -586,7 +595,6 @@ class ExtensionService
bool include_disabled,
bool include_terminated) const;
-
// Adds the given extension to the list of terminated extensions if
// it is not already there and unloads it.
void TrackTerminatedExtension(const Extension* extension);
@@ -708,6 +716,9 @@ class ExtensionService
// Keeps track of app notifications.
AppNotificationManager app_notification_manager_;
+ // Keeps track of extension permissions.
+ ExtensionPermissionsManager permissions_manager_;
+
// Keeps track of favicon-sized omnibox icons for extensions.
ExtensionIconManager omnibox_icon_manager_;
ExtensionIconManager omnibox_popup_icon_manager_;
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index bad22a1..c1a18d1 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -1023,7 +1023,8 @@ TEST_F(ExtensionServiceTest, LoadAllExtensionsFromDirectorySuccess) {
expected_patterns.ClearPatterns();
AddPattern(&expected_patterns, "http://*.google.com/*");
AddPattern(&expected_patterns, "https://*.google.com/*");
- EXPECT_EQ(expected_patterns, extension->permission_set()->explicit_hosts());
+ EXPECT_EQ(expected_patterns,
+ extension->GetActivePermissions()->explicit_hosts());
EXPECT_EQ(std::string(good1), loaded_[1]->id());
EXPECT_EQ(std::string("My extension 2"), loaded_[1]->name());
@@ -1364,7 +1365,7 @@ TEST_F(ExtensionServiceTest, GrantedPermissions) {
// Make sure there aren't any granted permissions before the
// extension is installed.
- scoped_ptr<ExtensionPermissionSet> known_perms(
+ scoped_refptr<ExtensionPermissionSet> known_perms(
prefs->GetGrantedPermissions(permissions_crx));
EXPECT_FALSE(known_perms.get());
@@ -1383,7 +1384,7 @@ TEST_F(ExtensionServiceTest, GrantedPermissions) {
AddPattern(&expected_host_perms, "http://*.google.com.hk/*");
AddPattern(&expected_host_perms, "http://www.example.com/*");
- known_perms.reset(prefs->GetGrantedPermissions(extension_id));
+ known_perms = prefs->GetGrantedPermissions(extension_id);
EXPECT_TRUE(known_perms.get());
EXPECT_FALSE(known_perms->IsEmpty());
EXPECT_EQ(expected_api_perms, known_perms->apis());
@@ -1412,7 +1413,7 @@ TEST_F(ExtensionServiceTest, GrantedFullAccessPermissions) {
std::string extension_id = extension->id();
ExtensionPrefs* prefs = service_->extension_prefs();
- scoped_ptr<ExtensionPermissionSet> permissions(
+ scoped_refptr<ExtensionPermissionSet> permissions(
prefs->GetGrantedPermissions(extension_id));
EXPECT_FALSE(permissions->IsEmpty());
EXPECT_TRUE(permissions->HasEffectiveFullAccess());
@@ -1477,7 +1478,7 @@ TEST_F(ExtensionServiceTest, GrantedAPIAndHostPermissions) {
ASSERT_TRUE(service_->IsExtensionEnabled(extension_id));
ASSERT_FALSE(prefs->DidExtensionEscalatePermissions(extension_id));
- scoped_ptr<ExtensionPermissionSet> current_perms(
+ scoped_refptr<ExtensionPermissionSet> current_perms(
prefs->GetGrantedPermissions(extension_id));
ASSERT_TRUE(current_perms.get());
ASSERT_FALSE(current_perms->IsEmpty());
@@ -1490,7 +1491,7 @@ TEST_F(ExtensionServiceTest, GrantedAPIAndHostPermissions) {
// updating the browser to a version which recognizes additional host
// permissions).
host_permissions.clear();
- current_perms.reset();
+ current_perms = NULL;
host_permissions.insert("http://*.google.com/*");
host_permissions.insert("https://*.google.com/*");
@@ -1519,7 +1520,7 @@ TEST_F(ExtensionServiceTest, GrantedAPIAndHostPermissions) {
ASSERT_TRUE(service_->IsExtensionEnabled(extension_id));
ASSERT_FALSE(prefs->DidExtensionEscalatePermissions(extension_id));
- current_perms.reset(prefs->GetGrantedPermissions(extension_id));
+ current_perms = prefs->GetGrantedPermissions(extension_id);
ASSERT_TRUE(current_perms.get());
ASSERT_FALSE(current_perms->IsEmpty());
ASSERT_FALSE(current_perms->HasEffectiveFullAccess());
diff --git a/chrome/browser/extensions/permissions_apitest.cc b/chrome/browser/extensions/permissions_apitest.cc
index e298a093..def0595 100644
--- a/chrome/browser/extensions/permissions_apitest.cc
+++ b/chrome/browser/extensions/permissions_apitest.cc
@@ -1,9 +1,14 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// 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 "chrome/browser/extensions/extension_apitest.h"
+#include "chrome/browser/extensions/extension_prefs.h"
+#include "chrome/browser/extensions/extension_service.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/ui/browser.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension_permission_set.h"
class ExperimentalApiTest : public ExtensionApiTest {
public:
@@ -47,3 +52,35 @@ IN_PROC_BROWSER_TEST_F(ExtensionApiTest, FaviconPermission) {
IN_PROC_BROWSER_TEST_F(ExtensionApiTest, AlwaysAllowed) {
ASSERT_TRUE(RunExtensionTest("permissions/always_allowed")) << message_;
}
+
+// Tests that the optional permissions API works correctly.
+IN_PROC_BROWSER_TEST_F(ExperimentalApiTest, OptionalPermissionsGranted) {
+ // Mark all the tested APIs as granted to bypass the confirmation UI.
+ ExtensionAPIPermissionSet apis;
+ apis.insert(ExtensionAPIPermission::kTab);
+ apis.insert(ExtensionAPIPermission::kManagement);
+ apis.insert(ExtensionAPIPermission::kPermissions);
+ scoped_refptr<ExtensionPermissionSet> granted_permissions =
+ new ExtensionPermissionSet(apis, URLPatternSet(), URLPatternSet());
+
+ ExtensionPrefs* prefs =
+ browser()->profile()->GetExtensionService()->extension_prefs();
+ prefs->AddGrantedPermissions("kjmkgkdkpedkejedfhmfcenooemhbpbo",
+ granted_permissions);
+
+ EXPECT_TRUE(RunExtensionTest("permissions/optional")) << message_;
+}
+
+// Tests that the optional permissions API works correctly.
+IN_PROC_BROWSER_TEST_F(ExperimentalApiTest, OptionalPermissionsAutoConfirm) {
+ // Rather than setting the granted permissions, set the UI autoconfirm flag
+ // and run the same tests.
+ RequestPermissionsFunction::SetAutoConfirmForTests(true);
+ EXPECT_TRUE(RunExtensionTest("permissions/optional")) << message_;
+}
+
+// Test that denying the optional permissions confirmation dialog works.
+IN_PROC_BROWSER_TEST_F(ExperimentalApiTest, OptionalPermissionsDeny) {
+ RequestPermissionsFunction::SetAutoConfirmForTests(false);
+ EXPECT_TRUE(RunExtensionTest("permissions/optional_deny")) << message_;
+}
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.h b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.h
index 8c7818d..2617a53 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.h
+++ b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.h
@@ -37,6 +37,7 @@ class Profile;
scoped_nsobject<NSString> title_;
scoped_nsobject<NSString> warnings_;
scoped_nsobject<NSString> button_;
+ scoped_nsobject<NSString> cancel_button_;
scoped_nsobject<NSString> subtitle_;
SkBitmap icon_;
}
diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm
index 1c8306a..0e79076f 100644
--- a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm
+++ b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller.mm
@@ -92,6 +92,9 @@ void OffsetControlVertically(NSControl* control, CGFloat amount) {
retain]);
button_.reset([l10n_util::GetNSString(ExtensionInstallUI::kButtonIds[type])
retain]);
+ int cancel_id = ExtensionInstallUI::kAbortButtonIds[type];
+ cancel_button_.reset([l10n_util::GetNSString(
+ cancel_id > 0 ? cancel_id : IDS_CANCEL) retain]);
// We display the warnings as a simple text string, separated by newlines.
if (!warnings.empty()) {
@@ -132,6 +135,7 @@ void OffsetControlVertically(NSControl* control, CGFloat amount) {
[titleField_ setStringValue:title_.get()];
[subtitleField_ setStringValue:subtitle_.get()];
[okButton_ setTitle:button_.get()];
+ [cancelButton_ setTitle:cancel_button_.get()];
NSImage* image = gfx::SkBitmapToNSImage(icon_);
[iconView_ setImage:image];
diff --git a/chrome/browser/ui/gtk/extensions/extension_install_dialog_gtk.cc b/chrome/browser/ui/gtk/extensions/extension_install_dialog_gtk.cc
index cd2e99a..a49bc0a 100644
--- a/chrome/browser/ui/gtk/extensions/extension_install_dialog_gtk.cc
+++ b/chrome/browser/ui/gtk/extensions/extension_install_dialog_gtk.cc
@@ -62,8 +62,11 @@ void ShowInstallDialog(GtkWindow* parent,
parent,
GTK_DIALOG_MODAL,
NULL);
- GtkWidget* close_button = gtk_dialog_add_button(GTK_DIALOG(dialog),
- GTK_STOCK_CANCEL, GTK_RESPONSE_CLOSE);
+ int cancel = ExtensionInstallUI::kAbortButtonIds[type];
+ GtkWidget* close_button = gtk_dialog_add_button(
+ GTK_DIALOG(dialog),
+ cancel > 0 ? l10n_util::GetStringUTF8(cancel).c_str(): GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CLOSE);
gtk_dialog_add_button(
GTK_DIALOG(dialog),
l10n_util::GetStringUTF8(ExtensionInstallUI::kButtonIds[type]).c_str(),
diff --git a/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc b/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
index 1bf6d8f..b5c8a1ee 100644
--- a/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
+++ b/chrome/browser/ui/views/extensions/extension_install_dialog_view.cc
@@ -275,8 +275,10 @@ std::wstring ExtensionInstallDialogView::GetDialogButtonLabel(
case MessageBoxFlags::DIALOGBUTTON_OK:
return UTF16ToWide(
l10n_util::GetStringUTF16(ExtensionInstallUI::kButtonIds[type_]));
- case MessageBoxFlags::DIALOGBUTTON_CANCEL:
- return UTF16ToWide(l10n_util::GetStringUTF16(IDS_CANCEL));
+ case MessageBoxFlags::DIALOGBUTTON_CANCEL: {
+ int id = ExtensionInstallUI::kAbortButtonIds[type_];
+ return UTF16ToWide(l10n_util::GetStringUTF16(id > 0 ? id : IDS_CANCEL));
+ }
default:
NOTREACHED();
return std::wstring();