summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjstritar@chromium.org <jstritar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-23 19:02:52 +0000
committerjstritar@chromium.org <jstritar@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-23 19:02:52 +0000
commit0d3e4a22b373147c6144b57fefdf4012823e9150 (patch)
tree6388b5763a9c434ba6c79daff407b0e4e11d3572
parente31440ac4b5ff347768ade5e2cd6e42720234ca0 (diff)
downloadchromium_src-0d3e4a22b373147c6144b57fefdf4012823e9150.zip
chromium_src-0d3e4a22b373147c6144b57fefdf4012823e9150.tar.gz
chromium_src-0d3e4a22b373147c6144b57fefdf4012823e9150.tar.bz2
Start refractoring extension permissions into ExtensionPermissionSet.
BUG=84507 TEST=*Extension* Review URL: http://codereview.chromium.org/7003098 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@90244 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/automation/automation_provider.cc2
-rw-r--r--chrome/browser/automation/testing_automation_provider.cc4
-rw-r--r--chrome/browser/background/background_application_list_model.cc7
-rw-r--r--chrome/browser/chrome_content_browser_client.cc4
-rw-r--r--chrome/browser/extensions/convert_web_app_browsertest.cc10
-rw-r--r--chrome/browser/extensions/convert_web_app_unittest.cc8
-rw-r--r--chrome/browser/extensions/crx_installer.cc7
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.cc2
-rw-r--r--chrome/browser/extensions/extension_info_map_unittest.cc10
-rw-r--r--chrome/browser/extensions/extension_management_api.cc6
-rw-r--r--chrome/browser/extensions/extension_management_browsertest.cc15
-rw-r--r--chrome/browser/extensions/extension_preference_api.cc45
-rw-r--r--chrome/browser/extensions/extension_prefs.cc221
-rw-r--r--chrome/browser/extensions/extension_prefs.h56
-rw-r--r--chrome/browser/extensions/extension_prefs_unittest.cc194
-rw-r--r--chrome/browser/extensions/extension_service.cc44
-rw-r--r--chrome/browser/extensions/extension_service_unittest.cc159
-rw-r--r--chrome/browser/extensions/extension_special_storage_policy.cc20
-rw-r--r--chrome/browser/extensions/extension_tabs_module.cc4
-rw-r--r--chrome/browser/geolocation/chrome_geolocation_permission_context.cc2
-rw-r--r--chrome/browser/profiles/profile.cc3
-rw-r--r--chrome/browser/profiles/profile_impl.cc4
-rw-r--r--chrome/browser/renderer_host/chrome_render_message_filter.cc4
-rw-r--r--chrome/chrome_common.gypi2
-rw-r--r--chrome/chrome_tests.gypi1
-rw-r--r--chrome/common/extensions/extension.cc598
-rw-r--r--chrome/common/extensions/extension.h210
-rw-r--r--chrome/common/extensions/extension_manifests_unittest.cc14
-rw-r--r--chrome/common/extensions/extension_permission_set.cc778
-rw-r--r--chrome/common/extensions/extension_permission_set.h389
-rw-r--r--chrome/common/extensions/extension_permission_set_unittest.cc941
-rw-r--r--chrome/common/extensions/extension_unittest.cc407
-rw-r--r--chrome/common/extensions/url_pattern_set.cc16
-rw-r--r--chrome/common/extensions/url_pattern_set.h6
-rw-r--r--chrome/common/extensions/url_pattern_set_unittest.cc53
-rw-r--r--chrome/renderer/extensions/bindings_utils.cc2
-rw-r--r--chrome/renderer/extensions/extension_dispatcher.cc5
37 files changed, 2722 insertions, 1531 deletions
diff --git a/chrome/browser/automation/automation_provider.cc b/chrome/browser/automation/automation_provider.cc
index 4f61688..06e73e3 100644
--- a/chrome/browser/automation/automation_provider.cc
+++ b/chrome/browser/automation/automation_provider.cc
@@ -808,6 +808,8 @@ void AutomationProvider::InstallExtensionAndGetHandle(
ExtensionInstallUI* client =
(with_ui ? new ExtensionInstallUI(profile_) : NULL);
scoped_refptr<CrxInstaller> installer(service->MakeCrxInstaller(client));
+ if (!with_ui)
+ installer->set_allow_silent_install(true);
installer->set_install_cause(extension_misc::INSTALL_CAUSE_AUTOMATION);
installer->InstallCrx(crx_path);
} else {
diff --git a/chrome/browser/automation/testing_automation_provider.cc b/chrome/browser/automation/testing_automation_provider.cc
index 5fe2218..b7b83ad 100644
--- a/chrome/browser/automation/testing_automation_provider.cc
+++ b/chrome/browser/automation/testing_automation_provider.cc
@@ -4015,7 +4015,7 @@ ListValue* GetHostPermissions(const Extension* ext, bool effective_perm) {
if (effective_perm)
pattern_list = ext->GetEffectiveHostPermissions().patterns();
else
- pattern_list = ext->host_permissions();
+ pattern_list = ext->permission_set()->explicit_hosts().patterns();
ListValue* permissions = new ListValue;
for (URLPatternList::const_iterator perm = pattern_list.begin();
@@ -4028,7 +4028,7 @@ ListValue* GetHostPermissions(const Extension* ext, bool effective_perm) {
ListValue* GetAPIPermissions(const Extension* ext) {
ListValue* permissions = new ListValue;
- std::set<std::string> perm_list = ext->api_permissions();
+ std::set<std::string> perm_list = ext->permission_set()->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_application_list_model.cc b/chrome/browser/background/background_application_list_model.cc
index f9092c1..d8512bc 100644
--- a/chrome/browser/background/background_application_list_model.cc
+++ b/chrome/browser/background/background_application_list_model.cc
@@ -99,11 +99,6 @@ void GetServiceApplications(ExtensionService* service,
ExtensionNameComparator(collator.get()));
}
-bool HasBackgroundAppPermission(
- const std::set<std::string>& api_permissions) {
- return Extension::HasApiPermission(
- api_permissions, Extension::kBackgroundPermission);
-}
} // namespace
void
@@ -250,7 +245,7 @@ int BackgroundApplicationListModel::GetPosition(
// static
bool BackgroundApplicationListModel::IsBackgroundApp(
const Extension& extension) {
- return HasBackgroundAppPermission(extension.api_permissions());
+ return extension.HasAPIPermission(ExtensionAPIPermission::kBackground);
}
void BackgroundApplicationListModel::Observe(
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index dfde2e9..8d72958 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -484,7 +484,7 @@ WebKit::WebNotificationPresenter::Permission
const Extension* extension =
io_data->GetExtensionInfoMap()->extensions().GetByURL(source_url);
if (extension &&
- extension->HasApiPermission(Extension::kNotificationPermission)) {
+ extension->HasAPIPermission(ExtensionAPIPermission::kNotification)) {
return WebKit::WebNotificationPresenter::PermissionAllowed;
}
@@ -547,7 +547,7 @@ bool ChromeContentBrowserClient::CanCreateWindow(
const Extension* extension =
io_data->GetExtensionInfoMap()->extensions().GetByURL(source_url);
return (extension &&
- extension->HasApiPermission(Extension::kBackgroundPermission));
+ extension->HasAPIPermission(ExtensionAPIPermission::kBackground));
}
return true;
}
diff --git a/chrome/browser/extensions/convert_web_app_browsertest.cc b/chrome/browser/extensions/convert_web_app_browsertest.cc
index e4985df..e923e90 100644
--- a/chrome/browser/extensions/convert_web_app_browsertest.cc
+++ b/chrome/browser/extensions/convert_web_app_browsertest.cc
@@ -70,11 +70,11 @@ IN_PROC_BROWSER_TEST_F(ExtensionFromWebAppTest, Basic) {
EXPECT_EQ(extension_misc::LAUNCH_PANEL,
installed_extension_->launch_container());
- ASSERT_EQ(2u, installed_extension_->api_permissions().size());
- EXPECT_TRUE(installed_extension_->api_permissions().find("geolocation") !=
- installed_extension_->api_permissions().end());
- EXPECT_TRUE(installed_extension_->api_permissions().find("notifications") !=
- installed_extension_->api_permissions().end());
+ ASSERT_EQ(2u, installed_extension_->permission_set()->apis().size());
+ EXPECT_TRUE(installed_extension_->HasAPIPermission(
+ ExtensionAPIPermission::kGeolocation));
+ EXPECT_TRUE(installed_extension_->HasAPIPermission(
+ ExtensionAPIPermission::kNotification));
ASSERT_EQ(3u, installed_extension_->icons().map().size());
EXPECT_EQ("icons/16.png", installed_extension_->icons().Get(
diff --git a/chrome/browser/extensions/convert_web_app_unittest.cc b/chrome/browser/extensions/convert_web_app_unittest.cc
index 551a923..4aafc4f 100644
--- a/chrome/browser/extensions/convert_web_app_unittest.cc
+++ b/chrome/browser/extensions/convert_web_app_unittest.cc
@@ -123,9 +123,9 @@ 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->api_permissions().size());
- EXPECT_TRUE(extension->HasApiPermission("geolocation"));
- EXPECT_TRUE(extension->HasApiPermission("notifications"));
+ EXPECT_EQ(2u, extension->permission_set()->apis().size());
+ EXPECT_TRUE(extension->HasAPIPermission("geolocation"));
+ EXPECT_TRUE(extension->HasAPIPermission("notifications"));
ASSERT_EQ(1u, extension->web_extent().patterns().size());
EXPECT_EQ("http://aaronboodman.com/gearpad/*",
extension->web_extent().patterns()[0].GetAsString());
@@ -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->api_permissions().size());
+ EXPECT_EQ(0u, extension->permission_set()->apis().size());
ASSERT_EQ(1u, extension->web_extent().patterns().size());
EXPECT_EQ("*://aaronboodman.com/*",
extension->web_extent().patterns()[0].GetAsString());
diff --git a/chrome/browser/extensions/crx_installer.cc b/chrome/browser/extensions/crx_installer.cc
index e772a0f..7f76e1d 100644
--- a/chrome/browser/extensions/crx_installer.cc
+++ b/chrome/browser/extensions/crx_installer.cc
@@ -546,6 +546,13 @@ void CrxInstaller::ReportSuccessFromUIThread() {
if (client_)
client_->OnInstallSuccess(extension_.get(), install_icon_.get());
+ // We update the extension's granted permissions if the user already approved
+ // the install (client_ is non NULL), or we are allowed to install this
+ // silently. We only track granted permissions for INTERNAL extensions.
+ if ((client_ || allow_silent_install_) &&
+ extension_->location() == Extension::INTERNAL)
+ frontend_weak_->GrantPermissions(extension_);
+
// Tell the frontend about the installation and hand off ownership of
// extension_ to it.
frontend_weak_->OnExtensionInstalled(extension_);
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index 2c1fe40..92aa0f7 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -563,7 +563,7 @@ ExtensionFunction* ExtensionFunctionDispatcher::CreateExtensionFunction(
return NULL;
}
- if (!extension->HasApiPermission(params.name)) {
+ if (!extension->HasAPIPermission(params.name)) {
LOG(ERROR) << "Extension " << extension->id() << " does not have "
<< "permission to function: " << params.name;
SendAccessDenied(ipc_sender, routing_id, params.request_id);
diff --git a/chrome/browser/extensions/extension_info_map_unittest.cc b/chrome/browser/extensions/extension_info_map_unittest.cc
index a355673..5df0bd1 100644
--- a/chrome/browser/extensions/extension_info_map_unittest.cc
+++ b/chrome/browser/extensions/extension_info_map_unittest.cc
@@ -138,19 +138,19 @@ TEST_F(ExtensionInfoMapTest, CheckPermissions) {
const Extension* match = info_map->extensions().GetByURL(
app->GetResourceURL("a.html"));
EXPECT_TRUE(match &&
- match->HasApiPermission(Extension::kNotificationPermission));
+ match->HasAPIPermission(ExtensionAPIPermission::kNotification));
match = info_map->extensions().GetByURL(app_url);
EXPECT_TRUE(match &&
- match->HasApiPermission(Extension::kNotificationPermission));
+ match->HasAPIPermission(ExtensionAPIPermission::kNotification));
EXPECT_FALSE(match &&
- match->HasApiPermission(Extension::kTabPermission));
+ match->HasAPIPermission(ExtensionAPIPermission::kTab));
// The extension should have the tabs permission.
match = info_map->extensions().GetByURL(extension->GetResourceURL("a.html"));
EXPECT_TRUE(match &&
- match->HasApiPermission(Extension::kTabPermission));
+ match->HasAPIPermission(ExtensionAPIPermission::kTab));
EXPECT_FALSE(match &&
- match->HasApiPermission(Extension::kNotificationPermission));
+ match->HasAPIPermission(ExtensionAPIPermission::kNotification));
// Random URL should not have any permissions.
match = info_map->extensions().GetByURL(GURL("http://evil.com/a.html"));
diff --git a/chrome/browser/extensions/extension_management_api.cc b/chrome/browser/extensions/extension_management_api.cc
index 0053b1d..b67b03f 100644
--- a/chrome/browser/extensions/extension_management_api.cc
+++ b/chrome/browser/extensions/extension_management_api.cc
@@ -91,7 +91,8 @@ static DictionaryValue* CreateExtensionInfo(const Extension& extension,
info->Set("icons", icon_list);
}
- const std::set<std::string> perms = extension.api_permissions();
+ const std::set<std::string> perms =
+ extension.permission_set()->GetAPIsAsStrings();
ListValue* permission_list = new ListValue();
if (!perms.empty()) {
std::set<std::string>::const_iterator perms_iter;
@@ -105,7 +106,8 @@ static DictionaryValue* CreateExtensionInfo(const Extension& extension,
ListValue* host_permission_list = new ListValue();
if (!extension.is_hosted_app()) {
// Skip host permissions for hosted apps.
- const URLPatternList host_perms = extension.host_permissions();
+ const URLPatternList host_perms =
+ extension.permission_set()->explicit_hosts().patterns();
if (!host_perms.empty()) {
URLPatternList::const_iterator host_perms_iter;
for (host_perms_iter = host_perms.begin();
diff --git a/chrome/browser/extensions/extension_management_browsertest.cc b/chrome/browser/extensions/extension_management_browsertest.cc
index d80f37c..e7f8004 100644
--- a/chrome/browser/extensions/extension_management_browsertest.cc
+++ b/chrome/browser/extensions/extension_management_browsertest.cc
@@ -124,6 +124,18 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallThenCancel) {
"1.0"));
}
+IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, InstallRequiresConfirm) {
+ // Installing the extension without an auto confirming UI should fail
+ // since good.crx has permissions that require approval.
+ ASSERT_TRUE(InstallExtension(test_data_dir_.AppendASCII("good.crx"), 0));
+ UninstallExtension("ldnnhddmnhbkjipkidpdiheffobcpfmf");
+
+ // And the install should succeed when the permissions are accepted.
+ ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(
+ test_data_dir_.AppendASCII("good.crx"), 1, browser()->profile()));
+ UninstallExtension("ldnnhddmnhbkjipkidpdiheffobcpfmf");
+}
+
// Tests that installing and uninstalling extensions don't crash with an
// incognito window open.
IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, Incognito) {
@@ -133,7 +145,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionManagementTest, Incognito) {
ui_test_utils::OpenURLOffTheRecord(browser()->profile(),
GURL(chrome::kChromeUIExtensionsURL));
- ASSERT_TRUE(InstallExtension(test_data_dir_.AppendASCII("good.crx"), 1));
+ ASSERT_TRUE(InstallExtensionWithUIAutoConfirm(
+ test_data_dir_.AppendASCII("good.crx"), 1, browser()->profile()));
UninstallExtension("ldnnhddmnhbkjipkidpdiheffobcpfmf");
}
diff --git a/chrome/browser/extensions/extension_preference_api.cc b/chrome/browser/extensions/extension_preference_api.cc
index 1fc7813..21b1f71 100644
--- a/chrome/browser/extensions/extension_preference_api.cc
+++ b/chrome/browser/extensions/extension_preference_api.cc
@@ -20,6 +20,7 @@
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/extension_error_utils.h"
+#include "chrome/common/extensions/extension_permission_set.h"
#include "chrome/common/pref_names.h"
#include "content/common/notification_type.h"
#include "content/common/notification_service.h"
@@ -29,7 +30,7 @@ namespace {
struct PrefMappingEntry {
const char* extension_pref;
const char* browser_pref;
- const char* permission;
+ ExtensionAPIPermission::ID permission;
};
const char kNotControllable[] = "not_controllable";
@@ -46,19 +47,19 @@ const char kOnPrefChangeFormat[] = "types.ChromeSetting.%s.onChange";
PrefMappingEntry kPrefMapping[] = {
{ "thirdPartyCookiesAllowed",
prefs::kBlockThirdPartyCookies,
- Extension::kContentSettingsPermission
+ ExtensionAPIPermission::kContentSettings
},
{ "referrersEnabled",
prefs::kEnableReferrers,
- Extension::kContentSettingsPermission
+ ExtensionAPIPermission::kContentSettings
},
{ "hyperlinkAuditingEnabled",
prefs::kEnableHyperlinkAuditing,
- Extension::kContentSettingsPermission
+ ExtensionAPIPermission::kContentSettings
},
{ "proxy",
prefs::kProxy,
- Extension::kProxyPermission
+ ExtensionAPIPermission::kProxy
},
};
@@ -130,9 +131,8 @@ class PrefMapping {
bool FindBrowserPrefForExtensionPref(const std::string& extension_pref,
std::string* browser_pref,
- std::string* permission) {
- std::map<std::string, std::pair<std::string, std::string> >::iterator it =
- mapping_.find(extension_pref);
+ ExtensionAPIPermission::ID* permission) {
+ PrefMap::iterator it = mapping_.find(extension_pref);
if (it != mapping_.end()) {
*browser_pref = it->second.first;
*permission = it->second.second;
@@ -143,9 +143,8 @@ class PrefMapping {
bool FindEventForBrowserPref(const std::string& browser_pref,
std::string* event_name,
- std::string* permission) {
- std::map<std::string, std::pair<std::string, std::string> >::iterator it =
- event_mapping_.find(browser_pref);
+ ExtensionAPIPermission::ID* permission) {
+ PrefMap::iterator it = event_mapping_.find(browser_pref);
if (it != event_mapping_.end()) {
*event_name = it->second.first;
*permission = it->second.second;
@@ -198,11 +197,15 @@ class PrefMapping {
transformers_[browser_pref] = transformer;
}
+ typedef std::map<std::string,
+ std::pair<std::string, ExtensionAPIPermission::ID> >
+ PrefMap;
+
// Mapping from extension pref keys to browser pref keys and permissions.
- std::map<std::string, std::pair<std::string, std::string> > mapping_;
+ PrefMap mapping_;
// Mapping from browser pref keys to extension event names and permissions.
- std::map<std::string, std::pair<std::string, std::string> > event_mapping_;
+ PrefMap event_mapping_;
// Mapping from browser pref keys to transformers.
std::map<std::string, PrefTransformerInterface*> transformers_;
@@ -248,7 +251,7 @@ void ExtensionPreferenceEventRouter::OnPrefChanged(
bool incognito = (pref_service != profile_->GetPrefs());
std::string event_name;
- std::string permission;
+ ExtensionAPIPermission::ID permission = ExtensionAPIPermission::kInvalid;
bool rv = PrefMapping::GetInstance()->FindEventForBrowserPref(
browser_pref, &event_name, &permission);
DCHECK(rv);
@@ -278,7 +281,7 @@ void ExtensionPreferenceEventRouter::OnPrefChanged(
std::string extension_id = (*it)->id();
// TODO(bauerb): Only iterate over registered event listeners.
if (router->ExtensionHasEventListener(extension_id, event_name) &&
- (*it)->HasApiPermission(permission) &&
+ (*it)->HasAPIPermission(permission) &&
(!incognito || extension_service->CanCrossIncognito(*it))) {
std::string level_of_control =
GetLevelOfControl(profile_, extension_id, browser_pref, incognito);
@@ -323,11 +326,11 @@ bool GetPreferenceFunction::RunImpl() {
PrefService* prefs = incognito ? profile_->GetOffTheRecordPrefs()
: profile_->GetPrefs();
std::string browser_pref;
- std::string permission;
+ ExtensionAPIPermission::ID permission = ExtensionAPIPermission::kInvalid;
EXTENSION_FUNCTION_VALIDATE(
PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref(
pref_key, &browser_pref, &permission));
- if (!GetExtension()->HasApiPermission(permission)) {
+ if (!GetExtension()->HasAPIPermission(permission)) {
error_ = ExtensionErrorUtils::FormatErrorMessage(
keys::kPermissionErrorMessage, pref_key);
return false;
@@ -397,11 +400,11 @@ bool SetPreferenceFunction::RunImpl() {
}
std::string browser_pref;
- std::string permission;
+ ExtensionAPIPermission::ID permission = ExtensionAPIPermission::kInvalid;
EXTENSION_FUNCTION_VALIDATE(
PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref(
pref_key, &browser_pref, &permission));
- if (!GetExtension()->HasApiPermission(permission)) {
+ if (!GetExtension()->HasAPIPermission(permission)) {
error_ = ExtensionErrorUtils::FormatErrorMessage(
keys::kPermissionErrorMessage, pref_key);
return false;
@@ -461,11 +464,11 @@ bool ClearPreferenceFunction::RunImpl() {
}
std::string browser_pref;
- std::string permission;
+ ExtensionAPIPermission::ID permission = ExtensionAPIPermission::kInvalid;
EXTENSION_FUNCTION_VALIDATE(
PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref(
pref_key, &browser_pref, &permission));
- if (!GetExtension()->HasApiPermission(permission)) {
+ if (!GetExtension()->HasAPIPermission(permission)) {
error_ = ExtensionErrorUtils::FormatErrorMessage(
keys::kPermissionErrorMessage, pref_key);
return false;
diff --git a/chrome/browser/extensions/extension_prefs.cc b/chrome/browser/extensions/extension_prefs.cc
index b901ba5..d7b63dc 100644
--- a/chrome/browser/extensions/extension_prefs.cc
+++ b/chrome/browser/extensions/extension_prefs.cc
@@ -67,7 +67,6 @@ const char kIdleInstallInfoCrxPath[] = "crx_path";
const char kIdleInstallInfoVersion[] = "version";
const char kIdleInstallInfoFetchTime[] = "fetch_time";
-
// A preference that, if true, will allow this extension to run in incognito
// mode.
const char kPrefIncognitoEnabled[] = "incognito";
@@ -103,9 +102,15 @@ const char kBrowserActionVisible[] = "browser_action_visible";
// 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 kPrefGrantedPermissionsAPI[] = "granted_permissions.api";
-const char kPrefGrantedPermissionsHost[] = "granted_permissions.host";
-const char kPrefGrantedPermissionsAll[] = "granted_permissions.full";
+const char kPrefGrantedAPIs[] = "granted_permissions.api";
+const char kPrefGrantedExplicitHosts[] = "granted_permissions.explicit_host";
+const char kPrefGrantedScriptableHosts[] =
+ "granted_permissions.scriptable_host";
+
+// The preference names for the old granted permissions scheme.
+const char kPrefOldGrantedFullAccess[] = "granted_permissions.full";
+const char kPrefOldGrantedHosts[] = "granted_permissions.host";
+const char kPrefOldGrantedAPIs[] = "granted_permissions.api";
// A preference that indicates when an extension was installed.
const char kPrefInstallTime[] = "install_time";
@@ -256,15 +261,6 @@ static void CleanupBadExtensionKeys(const FilePath& root_dir,
}
}
-static void ExtentToStringSet(const URLPatternSet& host_extent,
- std::set<std::string>* result) {
- URLPatternList patterns = host_extent.patterns();
- URLPatternList::const_iterator i;
-
- for (i = patterns.begin(); i != patterns.end(); ++i)
- result->insert(i->GetAsString());
-}
-
} // namespace
ExtensionPrefs::ExtensionPrefs(
@@ -438,42 +434,46 @@ bool ExtensionPrefs::ReadExtensionPrefList(
return true;
}
-bool ExtensionPrefs::ReadExtensionPrefStringSet(
+bool ExtensionPrefs::ReadExtensionPrefURLPatternSet(
const std::string& extension_id,
const std::string& pref_key,
- std::set<std::string>* result) {
+ URLPatternSet* result,
+ int valid_schemes) {
const ListValue* value = NULL;
if (!ReadExtensionPrefList(extension_id, pref_key, &value))
return false;
- result->clear();
+ result->ClearPatterns();
+ bool allow_file_access = AllowFileAccess(extension_id);
for (size_t i = 0; i < value->GetSize(); ++i) {
std::string item;
if (!value->GetString(i, &item))
return false;
- result->insert(item);
+ URLPattern pattern(valid_schemes);
+ if (pattern.Parse(item, URLPattern::PARSE_LENIENT) !=
+ URLPattern::PARSE_SUCCESS) {
+ NOTREACHED();
+ return false;
+ }
+ if (!allow_file_access && pattern.MatchesScheme(chrome::kFileScheme)) {
+ pattern.set_valid_schemes(
+ pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
+ }
+ result->AddPattern(pattern);
}
return true;
}
-void ExtensionPrefs::AddToExtensionPrefStringSet(
+void ExtensionPrefs::SetExtensionPrefURLPatternSet(
const std::string& extension_id,
const std::string& pref_key,
- const std::set<std::string>& added_value) {
- std::set<std::string> old_value;
- std::set<std::string> new_value;
- ReadExtensionPrefStringSet(extension_id, pref_key, &old_value);
-
- std::set_union(old_value.begin(), old_value.end(),
- added_value.begin(), added_value.end(),
- std::inserter(new_value, new_value.begin()));
-
+ const URLPatternSet& new_value) {
ListValue* value = new ListValue();
- for (std::set<std::string>::const_iterator iter = new_value.begin();
- iter != new_value.end(); ++iter)
- value->Append(Value::CreateStringValue(*iter));
+ for (URLPatternList::const_iterator i = new_value.patterns().begin();
+ i != new_value.patterns().end(); ++i)
+ value->AppendIfNotPresent(Value::CreateStringValue(i->GetAsString()));
UpdateExtensionPref(extension_id, pref_key, value);
}
@@ -671,72 +671,132 @@ void ExtensionPrefs::SetActiveBit(const std::string& extension_id,
Value::CreateBooleanValue(active));
}
-bool ExtensionPrefs::GetGrantedPermissions(
- const std::string& extension_id,
- bool* full_access,
- std::set<std::string>* api_permissions,
- URLPatternSet* host_extent) {
- CHECK(Extension::IdIsValid(extension_id));
+void ExtensionPrefs::MigratePermissions(const ExtensionIdSet& extension_ids) {
+ ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
+ for (ExtensionIdSet::const_iterator ext_id = extension_ids.begin();
+ ext_id != extension_ids.end(); ++ext_id) {
- const DictionaryValue* ext = GetExtensionPref(extension_id);
- if (!ext || !ext->GetBoolean(kPrefGrantedPermissionsAll, full_access))
- return false;
+ // An extension's granted permissions need to be migrated if the
+ // full_access bit is present. This bit was always present in the previous
+ // scheme and is never present now.
+ bool full_access;
+ const DictionaryValue* ext = GetExtensionPref(*ext_id);
+ if (!ext || !ext->GetBoolean(kPrefOldGrantedFullAccess, &full_access))
+ continue;
- ReadExtensionPrefStringSet(
- extension_id, kPrefGrantedPermissionsAPI, api_permissions);
+ // Remove the full access bit (empty list will get trimmed).
+ UpdateExtensionPref(
+ *ext_id, kPrefOldGrantedFullAccess, new ListValue());
+
+ // Add the plugin permission if the full access bit was set.
+ if (full_access) {
+ ListValue* apis = NULL;
+ ListValue* new_apis = NULL;
+
+ if (ext->GetList(kPrefGrantedAPIs, &apis))
+ new_apis = apis->DeepCopy();
+ else
+ new_apis = new ListValue();
+
+ std::string plugin_name = info->GetByID(
+ ExtensionAPIPermission::kPlugin)->name();
+ new_apis->Append(Value::CreateStringValue(plugin_name));
+ UpdateExtensionPref(*ext_id, kPrefGrantedAPIs, new_apis);
+ }
- std::set<std::string> host_permissions;
- ReadExtensionPrefStringSet(
- extension_id, kPrefGrantedPermissionsHost, &host_permissions);
- bool allow_file_access = AllowFileAccess(extension_id);
+ // The granted permissions originally only held the effective hosts,
+ // which are a combination of host and user script host permissions.
+ // We now maintain these lists separately. For migration purposes, it
+ // does not matter how we treat the old effective hosts as long as the
+ // new effective hosts will be the same, so we move them to explicit
+ // host permissions.
+ ListValue* hosts;
+ if (ext->GetList(kPrefOldGrantedHosts, &hosts)) {
+ UpdateExtensionPref(
+ *ext_id, kPrefGrantedExplicitHosts, hosts->DeepCopy());
+
+ // We can get rid of the old one by setting it to an empty list.
+ UpdateExtensionPref(*ext_id, kPrefOldGrantedHosts, new ListValue());
+ }
+ }
+}
- // The granted host permissions contain hosts from the manifest's
- // "permissions" array and from the content script "matches" arrays,
- // so the URLPattern needs to accept valid schemes from both types.
- for (std::set<std::string>::iterator i = host_permissions.begin();
- i != host_permissions.end(); ++i) {
- URLPattern pattern(
- Extension::kValidHostPermissionSchemes |
- UserScript::kValidUserScriptSchemes);
-
- // Parse without strict checks, so that new strict checks do not
- // fail on a pattern in an installed extension.
- if (URLPattern::PARSE_SUCCESS != pattern.Parse(
- *i, URLPattern::PARSE_LENIENT)) {
- NOTREACHED(); // Corrupt prefs? Hand editing?
- } else {
- if (!allow_file_access && pattern.MatchesScheme(chrome::kFileScheme)) {
- pattern.set_valid_schemes(
- pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
+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());
}
- host_extent->AddPattern(pattern);
}
}
- return true;
+ // 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);
}
void ExtensionPrefs::AddGrantedPermissions(
const std::string& extension_id,
- const bool full_access,
- const std::set<std::string>& api_permissions,
- const URLPatternSet& host_extent) {
+ const ExtensionPermissionSet* permissions) {
CHECK(Extension::IdIsValid(extension_id));
- UpdateExtensionPref(extension_id, kPrefGrantedPermissionsAll,
- Value::CreateBooleanValue(full_access));
-
- if (!api_permissions.empty()) {
- AddToExtensionPrefStringSet(
- extension_id, kPrefGrantedPermissionsAPI, api_permissions);
+ scoped_ptr<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(
+ 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);
- if (!host_extent.is_empty()) {
- std::set<std::string> host_permissions;
- ExtentToStringSet(host_extent, &host_permissions);
+ // Set the explicit host permissions.
+ if (!new_perms->explicit_hosts().is_empty()) {
+ SetExtensionPrefURLPatternSet(extension_id,
+ kPrefGrantedExplicitHosts,
+ new_perms->explicit_hosts());
+ }
- AddToExtensionPrefStringSet(
- extension_id, kPrefGrantedPermissionsHost, host_permissions);
+ // Set the scriptable host permissions.
+ if (!new_perms->scriptable_hosts().is_empty()) {
+ SetExtensionPrefURLPatternSet(extension_id,
+ kPrefGrantedScriptableHosts,
+ new_perms->scriptable_hosts());
}
}
@@ -1432,6 +1492,8 @@ void ExtensionPrefs::InitPrefStore() {
}
FixMissingPrefs(extension_ids);
+ MigratePermissions(extension_ids);
+
// Store extension controlled preference values in the
// |extension_pref_value_map_|, which then informs the subscribers
// (ExtensionPrefStores) about the winning values.
@@ -1489,7 +1551,6 @@ void ExtensionPrefs::InitPrefStore() {
extension_pref_value_map_->NotifyInitializationCompleted();
}
-
void ExtensionPrefs::SetExtensionControlledPref(
const std::string& extension_id,
const std::string& pref_key,
diff --git a/chrome/browser/extensions/extension_prefs.h b/chrome/browser/extensions/extension_prefs.h
index 2ea50e4..096d861 100644
--- a/chrome/browser/extensions/extension_prefs.h
+++ b/chrome/browser/extensions/extension_prefs.h
@@ -173,26 +173,17 @@ class ExtensionPrefs : public ExtensionContentSettingsStore::Observer {
bool GetActiveBit(const std::string& extension_id);
void SetActiveBit(const std::string& extension_id, bool active);
- // Gets the permissions (|api_permissions|, |host_extent| and |full_access|)
- // granted to the extension with |extension_id|. |full_access| will be true
- // if the extension has all effective permissions (like from an NPAPI plugin).
- // Returns false if the granted permissions haven't been initialized yet.
- // TODO(jstritar): Refactor the permissions into a class that encapsulates
- // all granted permissions, can be initialized from preferences or
- // a manifest file, and can be compared to each other.
- bool GetGrantedPermissions(const std::string& extension_id,
- bool* full_access,
- std::set<std::string>* api_permissions,
- URLPatternSet* host_extent);
-
- // Adds the specified |api_permissions|, |host_extent| and |full_access|
- // to the granted permissions for extension with |extension_id|.
- // |full_access| should be set to true if the extension effectively has all
- // permissions (such as by having an NPAPI plugin).
+ // Returns the granted permission set for the extension with |extension_id|,
+ // and NULL if no preferences were found for |extension_id|.
+ // This passes ownership of the returned set to the caller.
+ ExtensionPermissionSet* GetGrantedPermissions(
+ const std::string& extension_id);
+
+ // Adds |permissions| to the granted permissions set for the extension with
+ // |extension_id|. The new granted permissions set will be the union of
+ // |permissions| and the already granted permissions.
void AddGrantedPermissions(const std::string& extension_id,
- const bool full_access,
- const std::set<std::string>& api_permissions,
- const URLPatternSet& host_extent);
+ const ExtensionPermissionSet* permissions);
// Returns true if the user enabled this extension to be loaded in incognito
// mode.
@@ -393,23 +384,23 @@ class ExtensionPrefs : public ExtensionContentSettingsStore::Observer {
const std::string& pref_key,
int* out_value);
- // Reads a list pref |pref_key| from extension with id | extension_id|.
+ // Reads a list pref |pref_key| from extension with id |extension_id|.
bool ReadExtensionPrefList(const std::string& extension_id,
const std::string& pref_key,
const ListValue** out_value);
- // Reads a list pref |pref_key| as a string set from the extension with
- // id |extension_id|.
- bool ReadExtensionPrefStringSet(const std::string& extension_id,
- const std::string& pref_key,
- std::set<std::string>* result);
+ // Interprets the list pref, |pref_key| in |extension_id|'s preferences, as a
+ // URLPatternSet. The |valid_schemes| specify how to parse the URLPatterns.
+ bool ReadExtensionPrefURLPatternSet(const std::string& extension_id,
+ const std::string& pref_key,
+ URLPatternSet* result,
+ int valid_schemes);
- // Adds the |added_values| to the value of |pref_key| for the extension
- // with id |extension_id| (the new value will be the union of the existing
- // value and |added_values|).
- void AddToExtensionPrefStringSet(const std::string& extension_id,
- const std::string& pref_key,
- const std::set<std::string>& added_values);
+ // Converts |new_value| to a list of strings and sets the |pref_key| pref
+ // belonging to |extension_id|.
+ void SetExtensionPrefURLPatternSet(const std::string& extension_id,
+ const std::string& pref_key,
+ const URLPatternSet& new_value);
// Returns a dictionary for extension |id|'s prefs or NULL if it doesn't
// exist.
@@ -440,6 +431,9 @@ class ExtensionPrefs : public ExtensionContentSettingsStore::Observer {
// pref store.
void InitPrefStore();
+ // Migrates the permissions data in the pref store.
+ void MigratePermissions(const ExtensionIdSet& extension_ids);
+
// The pref service specific to this set of extension prefs. Owned by profile.
PrefService* prefs_;
diff --git a/chrome/browser/extensions/extension_prefs_unittest.cc b/chrome/browser/extensions/extension_prefs_unittest.cc
index 673044a..68faeb1 100644
--- a/chrome/browser/extensions/extension_prefs_unittest.cc
+++ b/chrome/browser/extensions/extension_prefs_unittest.cc
@@ -14,6 +14,7 @@
#include "chrome/browser/prefs/scoped_user_pref_update.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/extensions/extension_permission_set.h"
#include "content/browser/browser_thread.h"
#include "content/common/notification_details.h"
#include "content/common/notification_observer_mock.h"
@@ -43,13 +44,13 @@ static void AddPattern(URLPatternSet* extent, const std::string& pattern) {
extent->AddPattern(URLPattern(schemes, pattern));
}
-static void AssertEqualExtents(URLPatternSet* extent1,
- URLPatternSet* extent2) {
- URLPatternList patterns1 = extent1->patterns();
- URLPatternList patterns2 = extent2->patterns();
- std::set<std::string> strings1;
+static void AssertEqualExtents(const URLPatternSet& extent1,
+ const URLPatternSet& extent2) {
+ URLPatternList patterns1 = extent1.patterns();
+ URLPatternList patterns2 = extent2.patterns();
EXPECT_EQ(patterns1.size(), patterns2.size());
+ std::set<std::string> strings1;
for (size_t i = 0; i < patterns1.size(); ++i)
strings1.insert(patterns1.at(i).GetAsString());
@@ -204,100 +205,135 @@ class ExtensionPrefsGrantedPermissions : public ExtensionPrefsTest {
virtual void Initialize() {
extension_id_ = prefs_.AddExtensionAndReturnId("test");
- api_perm_set1_.insert("tabs");
- api_perm_set1_.insert("bookmarks");
- api_perm_set1_.insert("something_random");
+ api_perm_set1_.insert(ExtensionAPIPermission::kTab);
+ api_perm_set1_.insert(ExtensionAPIPermission::kBookmark);
- api_perm_set2_.insert("history");
- api_perm_set2_.insert("unknown2");
+ api_perm_set2_.insert(ExtensionAPIPermission::kHistory);
- AddPattern(&host_perm_set1_, "http://*.google.com/*");
- AddPattern(&host_perm_set1_, "http://example.com/*");
- AddPattern(&host_perm_set1_, "chrome://favicon/*");
+ AddPattern(&ehost_perm_set1_, "http://*.google.com/*");
+ AddPattern(&ehost_perm_set1_, "http://example.com/*");
+ AddPattern(&ehost_perm_set1_, "chrome://favicon/*");
- AddPattern(&host_perm_set2_, "https://*.google.com/*");
+ AddPattern(&ehost_perm_set2_, "https://*.google.com/*");
// with duplicate:
- AddPattern(&host_perm_set2_, "http://*.google.com/*");
+ AddPattern(&ehost_perm_set2_, "http://*.google.com/*");
- std::set_union(api_perm_set1_.begin(), api_perm_set1_.end(),
- api_perm_set2_.begin(), api_perm_set2_.end(),
- std::inserter(api_permissions_, api_permissions_.begin()));
+ AddPattern(&shost_perm_set1_, "http://reddit.com/r/test/*");
+ AddPattern(&shost_perm_set2_, "http://reddit.com/r/test/*");
+ AddPattern(&shost_perm_set2_, "http://somesite.com/*");
+ AddPattern(&shost_perm_set2_, "http://example.com/*");
+
+ ExtensionAPIPermissionSet expected_apis = api_perm_set1_;
+
+ AddPattern(&ehost_permissions_, "http://*.google.com/*");
+ AddPattern(&ehost_permissions_, "http://example.com/*");
+ AddPattern(&ehost_permissions_, "chrome://favicon/*");
+ AddPattern(&ehost_permissions_, "https://*.google.com/*");
- AddPattern(&host_permissions_, "http://*.google.com/*");
- AddPattern(&host_permissions_, "http://example.com/*");
- AddPattern(&host_permissions_, "chrome://favicon/*");
- AddPattern(&host_permissions_, "https://*.google.com/*");
+ AddPattern(&shost_permissions_, "http://reddit.com/r/test/*");
+ AddPattern(&shost_permissions_, "http://somesite.com/*");
+ AddPattern(&shost_permissions_, "http://example.com/*");
- std::set<std::string> empty_set;
- std::set<std::string> api_perms;
- bool full_access = false;
- URLPatternSet host_perms;
+ ExtensionAPIPermissionSet empty_set;
URLPatternSet empty_extent;
+ scoped_ptr<ExtensionPermissionSet> permissions;
+ scoped_ptr<ExtensionPermissionSet> granted_permissions;
// Make sure both granted api and host permissions start empty.
- EXPECT_FALSE(prefs()->GetGrantedPermissions(
- extension_id_, &full_access, &api_perms, &host_perms));
+ granted_permissions.reset(
+ prefs()->GetGrantedPermissions(extension_id_));
+ EXPECT_TRUE(granted_permissions->IsEmpty());
- EXPECT_TRUE(api_perms.empty());
- EXPECT_TRUE(host_perms.is_empty());
+ permissions.reset(new ExtensionPermissionSet(
+ api_perm_set1_, empty_extent, empty_extent));
// Add part of the api permissions.
- prefs()->AddGrantedPermissions(
- extension_id_, false, api_perm_set1_, empty_extent);
- EXPECT_TRUE(prefs()->GetGrantedPermissions(
- extension_id_, &full_access, &api_perms, &host_perms));
- EXPECT_EQ(api_perm_set1_, api_perms);
- EXPECT_TRUE(host_perms.is_empty());
- EXPECT_FALSE(full_access);
- host_perms.ClearPatterns();
- api_perms.clear();
-
- // Add part of the host permissions.
- prefs()->AddGrantedPermissions(
- extension_id_, false, empty_set, host_perm_set1_);
- EXPECT_TRUE(prefs()->GetGrantedPermissions(
- extension_id_, &full_access, &api_perms, &host_perms));
- EXPECT_FALSE(full_access);
- EXPECT_EQ(api_perm_set1_, api_perms);
- AssertEqualExtents(&host_perm_set1_, &host_perms);
- host_perms.ClearPatterns();
- api_perms.clear();
-
- // Add the rest of both the api and host permissions.
- prefs()->AddGrantedPermissions(extension_id_,
- true,
- api_perm_set2_,
- host_perm_set2_);
-
- EXPECT_TRUE(prefs()->GetGrantedPermissions(
- extension_id_, &full_access, &api_perms, &host_perms));
- EXPECT_TRUE(full_access);
- EXPECT_EQ(api_permissions_, api_perms);
- AssertEqualExtents(&host_permissions_, &host_perms);
+ prefs()->AddGrantedPermissions(extension_id_, permissions.get());
+ granted_permissions.reset(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();
+
+ // Add part of the explicit host permissions.
+ permissions.reset(new ExtensionPermissionSet(
+ empty_set, ehost_perm_set1_, empty_extent));
+ prefs()->AddGrantedPermissions(extension_id_, permissions.get());
+ granted_permissions.reset(prefs()->GetGrantedPermissions(extension_id_));
+ EXPECT_FALSE(granted_permissions->IsEmpty());
+ EXPECT_FALSE(granted_permissions->HasEffectiveFullAccess());
+ EXPECT_EQ(expected_apis, granted_permissions->apis());
+ AssertEqualExtents(ehost_perm_set1_,
+ granted_permissions->explicit_hosts());
+ AssertEqualExtents(ehost_perm_set1_,
+ granted_permissions->effective_hosts());
+
+ // Add part of the scriptable host permissions.
+ permissions.reset(new ExtensionPermissionSet(
+ empty_set, empty_extent, shost_perm_set1_));
+ prefs()->AddGrantedPermissions(extension_id_, permissions.get());
+ granted_permissions.reset(prefs()->GetGrantedPermissions(extension_id_));
+ EXPECT_FALSE(granted_permissions->IsEmpty());
+ EXPECT_FALSE(granted_permissions->HasEffectiveFullAccess());
+ EXPECT_EQ(expected_apis, granted_permissions->apis());
+ AssertEqualExtents(ehost_perm_set1_,
+ granted_permissions->explicit_hosts());
+ AssertEqualExtents(shost_perm_set1_,
+ granted_permissions->scriptable_hosts());
+ URLPatternSet::CreateUnion(ehost_perm_set1_, shost_perm_set1_,
+ &effective_permissions_);
+ AssertEqualExtents(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_));
+
+ 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_));
+ EXPECT_TRUE(granted_permissions.get());
+ EXPECT_FALSE(granted_permissions->IsEmpty());
+ EXPECT_EQ(api_permissions_, granted_permissions->apis());
+ AssertEqualExtents(ehost_permissions_,
+ granted_permissions->explicit_hosts());
+ AssertEqualExtents(shost_permissions_,
+ granted_permissions->scriptable_hosts());
+ effective_permissions_.ClearPatterns();
+ URLPatternSet::CreateUnion(ehost_permissions_, shost_permissions_,
+ &effective_permissions_);
+ AssertEqualExtents(effective_permissions_,
+ granted_permissions->effective_hosts());
}
virtual void Verify() {
- std::set<std::string> api_perms;
- URLPatternSet host_perms;
- bool full_access;
-
- EXPECT_TRUE(prefs()->GetGrantedPermissions(
- extension_id_, &full_access, &api_perms, &host_perms));
- EXPECT_EQ(api_permissions_, api_perms);
- EXPECT_TRUE(full_access);
- AssertEqualExtents(&host_permissions_, &host_perms);
+ scoped_ptr<ExtensionPermissionSet> permissions(
+ prefs()->GetGrantedPermissions(extension_id_));
+ EXPECT_TRUE(permissions.get());
+ EXPECT_FALSE(permissions->HasEffectiveFullAccess());
+ EXPECT_EQ(api_permissions_, permissions->apis());
+ AssertEqualExtents(ehost_permissions_, permissions->explicit_hosts());
+ AssertEqualExtents(shost_permissions_, permissions->scriptable_hosts());
}
private:
std::string extension_id_;
- std::set<std::string> api_perm_set1_;
- std::set<std::string> api_perm_set2_;
- URLPatternSet host_perm_set1_;
- URLPatternSet host_perm_set2_;
-
-
- std::set<std::string> api_permissions_;
- URLPatternSet host_permissions_;
+ ExtensionAPIPermissionSet api_perm_set1_;
+ ExtensionAPIPermissionSet api_perm_set2_;
+ URLPatternSet ehost_perm_set1_;
+ URLPatternSet ehost_perm_set2_;
+ URLPatternSet shost_perm_set1_;
+ URLPatternSet shost_perm_set2_;
+
+ ExtensionAPIPermissionSet api_permissions_;
+ URLPatternSet ehost_permissions_;
+ URLPatternSet shost_permissions_;
+ URLPatternSet effective_permissions_;
};
TEST_F(ExtensionPrefsGrantedPermissions, GrantedPermissions) {}
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc
index b5b7ae9..a8973f6 100644
--- a/chrome/browser/extensions/extension_service.cc
+++ b/chrome/browser/extensions/extension_service.cc
@@ -747,6 +747,8 @@ bool ExtensionService::UpdateExtension(
installer->set_install_source(pending_extension_info.install_source());
else if (extension)
installer->set_install_source(extension->location());
+ if (pending_extension_info.install_silently())
+ installer->set_allow_silent_install(true);
installer->set_delete_source(true);
installer->set_original_url(download_url);
installer->set_install_cause(extension_misc::INSTALL_CAUSE_UPDATE);
@@ -965,11 +967,8 @@ void ExtensionService::GrantPermissions(const Extension* extension) {
// We only maintain the granted permissions prefs for INTERNAL extensions.
CHECK_EQ(Extension::INTERNAL, extension->location());
- URLPatternSet effective_hosts = extension->GetEffectiveHostPermissions();
extension_prefs_->AddGrantedPermissions(extension->id(),
- extension->HasFullPermissions(),
- extension->api_permissions(),
- effective_hosts);
+ extension->permission_set());
}
void ExtensionService::GrantPermissionsAndEnableExtension(
@@ -1208,18 +1207,17 @@ void ExtensionService::RecordPermissionMessagesHistogram(
base::Histogram* counter = base::LinearHistogram::FactoryGet(
histogram,
1,
- Extension::PermissionMessage::ID_ENUM_BOUNDARY,
- Extension::PermissionMessage::ID_ENUM_BOUNDARY + 1,
+ ExtensionPermissionMessage::kEnumBoundary,
+ ExtensionPermissionMessage::kEnumBoundary + 1,
base::Histogram::kUmaTargetedHistogramFlag);
- std::vector<Extension::PermissionMessage> permissions =
- e->GetPermissionMessages();
+ ExtensionPermissionMessages permissions = e->GetPermissionMessages();
if (permissions.empty()) {
- counter->Add(Extension::PermissionMessage::ID_NONE);
+ counter->Add(ExtensionPermissionMessage::kNone);
} else {
- std::vector<Extension::PermissionMessage>::iterator it;
- for (it = permissions.begin(); it != permissions.end(); ++it)
- counter->Add(it->message_id());
+ for (ExtensionPermissionMessages::iterator it = permissions.begin();
+ it != permissions.end(); ++it)
+ counter->Add(it->id());
}
}
@@ -1938,10 +1936,6 @@ void ExtensionService::DisableIfPrivilegeIncrease(const Extension* extension) {
// can upgrade without requiring this user's approval.
const Extension* old = GetExtensionByIdInternal(extension->id(),
true, true, false);
- bool granted_full_access;
- std::set<std::string> granted_apis;
- URLPatternSet granted_extent;
-
bool is_extension_upgrade = old != NULL;
bool is_privilege_increase = false;
@@ -1950,23 +1944,16 @@ void ExtensionService::DisableIfPrivilegeIncrease(const Extension* extension) {
if (extension->location() == Extension::INTERNAL) {
// Add all the recognized permissions if the granted permissions list
// hasn't been initialized yet.
- if (!extension_prefs_->GetGrantedPermissions(extension->id(),
- &granted_full_access,
- &granted_apis,
- &granted_extent)) {
- GrantPermissions(extension);
- CHECK(extension_prefs_->GetGrantedPermissions(extension->id(),
- &granted_full_access,
- &granted_apis,
- &granted_extent));
- }
+ scoped_ptr<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
// that requires the user's approval. This could occur because the browser
// upgraded and recognized additional privileges, or an extension upgrades
// to a version that requires additional privileges.
- is_privilege_increase = Extension::IsPrivilegeIncrease(
- granted_full_access, granted_apis, granted_extent, extension);
+ is_privilege_increase =
+ granted_permissions->HasLessPrivilegesThan(extension->permission_set());
}
if (is_extension_upgrade) {
@@ -2023,7 +2010,6 @@ void ExtensionService::OnLoadSingleExtension(const Extension* extension) {
prompt->ShowPrompt();
return; // continues in SimpleExtensionLoadPrompt::InstallUI*
}
-
OnExtensionInstalled(extension);
}
diff --git a/chrome/browser/extensions/extension_service_unittest.cc b/chrome/browser/extensions/extension_service_unittest.cc
index 6a28563..8008828 100644
--- a/chrome/browser/extensions/extension_service_unittest.cc
+++ b/chrome/browser/extensions/extension_service_unittest.cc
@@ -114,10 +114,10 @@ static void AddPattern(URLPatternSet* extent, const std::string& pattern) {
extent->AddPattern(URLPattern(schemes, pattern));
}
-static void AssertEqualExtents(URLPatternSet* extent1,
- URLPatternSet* extent2) {
- URLPatternList patterns1 = extent1->patterns();
- URLPatternList patterns2 = extent2->patterns();
+static void AssertEqualExtents(const URLPatternSet& extent1,
+ const URLPatternSet& extent2) {
+ URLPatternList patterns1 = extent1.patterns();
+ URLPatternList patterns2 = extent2.patterns();
std::set<std::string> strings1;
EXPECT_EQ(patterns1.size(), patterns2.size());
@@ -569,7 +569,6 @@ class ExtensionServiceTest
pem_output_path));
ASSERT_TRUE(file_util::PathExists(crx_path));
-
InstallCrx(crx_path, should_succeed);
}
@@ -585,8 +584,9 @@ class ExtensionServiceTest
void StartCrxInstall(const FilePath& crx_path) {
ASSERT_TRUE(file_util::PathExists(crx_path))
<< "Path does not exist: "<< crx_path.value().c_str();
- // no client (silent install)
- scoped_refptr<CrxInstaller> installer(service_->MakeCrxInstaller(NULL));
+ scoped_refptr<CrxInstaller> installer(
+ service_->MakeCrxInstaller(NULL));
+ installer->set_allow_silent_install(true);
installer->InstallCrx(crx_path);
}
@@ -1033,7 +1033,8 @@ TEST_F(ExtensionServiceTest, LoadAllExtensionsFromDirectorySuccess) {
extension->path().AppendASCII("js_files").AppendASCII("script3.js");
ASSERT_TRUE(file_util::AbsolutePath(&expected_path));
EXPECT_TRUE(resource10.ComparePathWithDefault(expected_path));
- const URLPatternList permissions = extension->host_permissions();
+ const URLPatternList permissions =
+ extension->permission_set()->explicit_hosts().patterns();
ASSERT_EQ(2u, permissions.size());
EXPECT_EQ("http://*.google.com/*", permissions[0].GetAsString());
EXPECT_EQ("https://*.google.com/*", permissions[1].GetAsString());
@@ -1336,8 +1337,9 @@ TEST_F(ExtensionServiceTest, InstallUserScript) {
.AppendASCII("user_script_basic.user.js");
ASSERT_TRUE(file_util::PathExists(path));
- // Pass NULL to install silently.
- scoped_refptr<CrxInstaller> installer(service_->MakeCrxInstaller(NULL));
+ scoped_refptr<CrxInstaller> installer(
+ service_->MakeCrxInstaller(NULL));
+ installer->set_allow_silent_install(true);
installer->InstallUserScript(
path,
GURL("http://www.aaronboodman.com/scripts/user_script_basic.user.js"));
@@ -1371,18 +1373,14 @@ TEST_F(ExtensionServiceTest, GrantedPermissions) {
ExtensionPrefs* prefs = service_->extension_prefs();
- std::set<std::string> expected_api_perms;
- std::set<std::string> known_api_perms;
- bool full_access;
+ ExtensionAPIPermissionSet expected_api_perms;
URLPatternSet expected_host_perms;
- URLPatternSet known_host_perms;
// Make sure there aren't any granted permissions before the
// extension is installed.
- EXPECT_FALSE(prefs->GetGrantedPermissions(
- permissions_crx, &full_access, &known_api_perms, &known_host_perms));
- EXPECT_TRUE(known_api_perms.empty());
- EXPECT_TRUE(known_host_perms.is_empty());
+ scoped_ptr<ExtensionPermissionSet> known_perms(
+ prefs->GetGrantedPermissions(permissions_crx));
+ EXPECT_FALSE(known_perms.get());
PackAndInstallCrx(path, pem_path, true);
@@ -1391,23 +1389,20 @@ TEST_F(ExtensionServiceTest, GrantedPermissions) {
std::string extension_id = service_->extensions()->at(0)->id();
EXPECT_EQ(permissions_crx, extension_id);
-
// Verify that the valid API permissions have been recognized.
- expected_api_perms.insert("tabs");
+ expected_api_perms.insert(ExtensionAPIPermission::kTab);
AddPattern(&expected_host_perms, "http://*.google.com/*");
AddPattern(&expected_host_perms, "https://*.google.com/*");
AddPattern(&expected_host_perms, "http://*.google.com.hk/*");
AddPattern(&expected_host_perms, "http://www.example.com/*");
- EXPECT_TRUE(prefs->GetGrantedPermissions(extension_id,
- &full_access,
- &known_api_perms,
- &known_host_perms));
-
- EXPECT_EQ(expected_api_perms, known_api_perms);
- EXPECT_FALSE(full_access);
- AssertEqualExtents(&expected_host_perms, &known_host_perms);
+ known_perms.reset(prefs->GetGrantedPermissions(extension_id));
+ EXPECT_TRUE(known_perms.get());
+ EXPECT_FALSE(known_perms->IsEmpty());
+ EXPECT_EQ(expected_api_perms, known_perms->apis());
+ EXPECT_FALSE(known_perms->HasEffectiveFullAccess());
+ AssertEqualExtents(expected_host_perms, known_perms->effective_hosts());
}
#if !defined(OS_CHROMEOS)
@@ -1424,24 +1419,22 @@ TEST_F(ExtensionServiceTest, GrantedFullAccessPermissions) {
.AppendASCII("2");
ASSERT_TRUE(file_util::PathExists(path));
-
PackAndInstallCrx(path, true);
-
EXPECT_EQ(0u, GetErrors().size());
EXPECT_EQ(1u, service_->extensions()->size());
const Extension* extension = service_->extensions()->at(0);
std::string extension_id = extension->id();
ExtensionPrefs* prefs = service_->extension_prefs();
- bool full_access;
- std::set<std::string> api_permissions;
- URLPatternSet host_permissions;
- EXPECT_TRUE(prefs->GetGrantedPermissions(
- extension_id, &full_access, &api_permissions, &host_permissions));
+ scoped_ptr<ExtensionPermissionSet> permissions(
+ prefs->GetGrantedPermissions(extension_id));
+ EXPECT_FALSE(permissions->IsEmpty());
+ EXPECT_TRUE(permissions->HasEffectiveFullAccess());
+ EXPECT_FALSE(permissions->apis().empty());
+ EXPECT_TRUE(permissions->HasAPIPermission(ExtensionAPIPermission::kPlugin));
- EXPECT_TRUE(full_access);
- EXPECT_TRUE(api_permissions.empty());
- EXPECT_TRUE(host_permissions.is_empty());
+ // Full access implies full host access too...
+ EXPECT_TRUE(permissions->HasEffectiveAccessToAllHosts());
}
#endif
@@ -1466,23 +1459,22 @@ TEST_F(ExtensionServiceTest, GrantedAPIAndHostPermissions) {
ExtensionPrefs* prefs = service_->extension_prefs();
- std::set<std::string> expected_api_permissions;
+ ExtensionAPIPermissionSet expected_api_permissions;
URLPatternSet expected_host_permissions;
- expected_api_permissions.insert("tabs");
+ expected_api_permissions.insert(ExtensionAPIPermission::kTab);
AddPattern(&expected_host_permissions, "http://*.google.com/*");
AddPattern(&expected_host_permissions, "https://*.google.com/*");
AddPattern(&expected_host_permissions, "http://*.google.com.hk/*");
AddPattern(&expected_host_permissions, "http://www.example.com/*");
- std::set<std::string> api_permissions;
std::set<std::string> host_permissions;
// Test that the extension is disabled when an API permission is missing from
// the extension's granted api permissions preference. (This simulates
// updating the browser to a version which recognizes a new API permission).
- SetPrefStringSet(extension_id, "granted_permissions.api", api_permissions);
-
+ SetPref(extension_id, "granted_permissions.api",
+ new ListValue(), "granted_permissions.api");
service_->ReloadExtensions();
EXPECT_EQ(1u, service_->disabled_extensions()->size());
@@ -1497,35 +1489,33 @@ TEST_F(ExtensionServiceTest, GrantedAPIAndHostPermissions) {
ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::ENABLED);
ASSERT_FALSE(prefs->DidExtensionEscalatePermissions(extension_id));
- std::set<std::string> current_api_permissions;
- URLPatternSet current_host_permissions;
- bool current_full_access;
-
- ASSERT_TRUE(prefs->GetGrantedPermissions(extension_id,
- &current_full_access,
- &current_api_permissions,
- &current_host_permissions));
-
- ASSERT_FALSE(current_full_access);
- ASSERT_EQ(expected_api_permissions, current_api_permissions);
- AssertEqualExtents(&expected_host_permissions, &current_host_permissions);
+ scoped_ptr<ExtensionPermissionSet> current_perms(
+ prefs->GetGrantedPermissions(extension_id));
+ ASSERT_TRUE(current_perms.get());
+ ASSERT_FALSE(current_perms->IsEmpty());
+ ASSERT_FALSE(current_perms->HasEffectiveFullAccess());
+ ASSERT_EQ(expected_api_permissions, current_perms->apis());
+ AssertEqualExtents(expected_host_permissions,
+ current_perms->effective_hosts());
// Tests that the extension is disabled when a host permission is missing from
// the extension's granted host permissions preference. (This simulates
// updating the browser to a version which recognizes additional host
// permissions).
- api_permissions.clear();
host_permissions.clear();
- current_api_permissions.clear();
- current_host_permissions.ClearPatterns();
+ current_perms.reset();
- api_permissions.insert("tabs");
host_permissions.insert("http://*.google.com/*");
host_permissions.insert("https://*.google.com/*");
host_permissions.insert("http://*.google.com.hk/*");
- SetPrefStringSet(extension_id, "granted_permissions.api", api_permissions);
- SetPrefStringSet(extension_id, "granted_permissions.host", host_permissions);
+ ListValue* api_permissions = new ListValue();
+ api_permissions->Append(
+ Value::CreateIntegerValue(ExtensionAPIPermission::kTab));
+ SetPref(extension_id, "granted_permissions.api",
+ api_permissions, "granted_permissions.api");
+ SetPrefStringSet(
+ extension_id, "granted_permissions.scriptable_host", host_permissions);
service_->ReloadExtensions();
@@ -1541,38 +1531,13 @@ TEST_F(ExtensionServiceTest, GrantedAPIAndHostPermissions) {
ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::ENABLED);
ASSERT_FALSE(prefs->DidExtensionEscalatePermissions(extension_id));
- ASSERT_TRUE(prefs->GetGrantedPermissions(extension_id,
- &current_full_access,
- &current_api_permissions,
- &current_host_permissions));
-
- ASSERT_FALSE(current_full_access);
- ASSERT_EQ(expected_api_permissions, current_api_permissions);
- AssertEqualExtents(&expected_host_permissions, &current_host_permissions);
-
- // Tests that the granted permissions preferences are initialized when
- // migrating from the old pref schema.
- current_api_permissions.clear();
- current_host_permissions.ClearPatterns();
-
- ClearPref(extension_id, "granted_permissions");
-
- service_->ReloadExtensions();
-
- EXPECT_EQ(1u, service_->extensions()->size());
- extension = service_->extensions()->at(0);
-
- ASSERT_TRUE(prefs->GetExtensionState(extension_id) == Extension::ENABLED);
- ASSERT_FALSE(prefs->DidExtensionEscalatePermissions(extension_id));
-
- ASSERT_TRUE(prefs->GetGrantedPermissions(extension_id,
- &current_full_access,
- &current_api_permissions,
- &current_host_permissions));
-
- ASSERT_FALSE(current_full_access);
- ASSERT_EQ(expected_api_permissions, current_api_permissions);
- AssertEqualExtents(&expected_host_permissions, &current_host_permissions);
+ current_perms.reset(prefs->GetGrantedPermissions(extension_id));
+ ASSERT_TRUE(current_perms.get());
+ ASSERT_FALSE(current_perms->IsEmpty());
+ ASSERT_FALSE(current_perms->HasEffectiveFullAccess());
+ ASSERT_EQ(expected_api_permissions, current_perms->apis());
+ AssertEqualExtents(expected_host_permissions,
+ current_perms->effective_hosts());
}
// Test Packaging and installing an extension.
@@ -1834,8 +1799,8 @@ TEST_F(ExtensionServiceTest, InstallAppsWithUnlimtedStorage) {
ASSERT_EQ(1u, service_->extensions()->size());
const Extension* extension = service_->extensions()->at(0);
const std::string id1 = extension->id();
- EXPECT_TRUE(extension->HasApiPermission(
- Extension::kUnlimitedStoragePermission));
+ EXPECT_TRUE(extension->HasAPIPermission(
+ ExtensionAPIPermission::kUnlimitedStorage));
EXPECT_TRUE(extension->web_extent().MatchesURL(
extension->GetFullLaunchURL()));
const GURL origin1(extension->GetFullLaunchURL().GetOrigin());
@@ -1848,8 +1813,8 @@ TEST_F(ExtensionServiceTest, InstallAppsWithUnlimtedStorage) {
ASSERT_EQ(2u, service_->extensions()->size());
extension = service_->extensions()->at(1);
const std::string id2 = extension->id();
- EXPECT_TRUE(extension->HasApiPermission(
- Extension::kUnlimitedStoragePermission));
+ EXPECT_TRUE(extension->HasAPIPermission(
+ ExtensionAPIPermission::kUnlimitedStorage));
EXPECT_TRUE(extension->web_extent().MatchesURL(
extension->GetFullLaunchURL()));
const GURL origin2(extension->GetFullLaunchURL().GetOrigin());
diff --git a/chrome/browser/extensions/extension_special_storage_policy.cc b/chrome/browser/extensions/extension_special_storage_policy.cc
index fd3ccc4..9c95c1c 100644
--- a/chrome/browser/extensions/extension_special_storage_policy.cc
+++ b/chrome/browser/extensions/extension_special_storage_policy.cc
@@ -34,16 +34,18 @@ void ExtensionSpecialStoragePolicy::GrantRightsForExtension(
const Extension* extension) {
DCHECK(extension);
if (!extension->is_hosted_app() &&
- !extension->HasApiPermission(Extension::kUnlimitedStoragePermission) &&
- !extension->HasApiPermission(Extension::kFileBrowserHandlerPermission)) {
+ !extension->HasAPIPermission(
+ ExtensionAPIPermission::kUnlimitedStorage) &&
+ !extension->HasAPIPermission(
+ ExtensionAPIPermission::kFileBrowserHandler)) {
return;
}
base::AutoLock locker(lock_);
if (extension->is_hosted_app())
protected_apps_.Add(extension);
- if (extension->HasApiPermission(Extension::kUnlimitedStoragePermission))
+ if (extension->HasAPIPermission(ExtensionAPIPermission::kUnlimitedStorage))
unlimited_extensions_.Add(extension);
- if (extension->HasApiPermission(Extension::kFileBrowserHandlerPermission))
+ if (extension->HasAPIPermission(ExtensionAPIPermission::kFileBrowserHandler))
file_handler_extensions_.Add(extension);
}
@@ -51,16 +53,18 @@ void ExtensionSpecialStoragePolicy::RevokeRightsForExtension(
const Extension* extension) {
DCHECK(extension);
if (!extension->is_hosted_app() &&
- !extension->HasApiPermission(Extension::kUnlimitedStoragePermission) &&
- !extension->HasApiPermission(Extension::kFileBrowserHandlerPermission)) {
+ !extension->HasAPIPermission(
+ ExtensionAPIPermission::kUnlimitedStorage) &&
+ !extension->HasAPIPermission(
+ ExtensionAPIPermission::kFileBrowserHandler)) {
return;
}
base::AutoLock locker(lock_);
if (extension->is_hosted_app())
protected_apps_.Remove(extension);
- if (extension->HasApiPermission(Extension::kUnlimitedStoragePermission))
+ if (extension->HasAPIPermission(ExtensionAPIPermission::kUnlimitedStorage))
unlimited_extensions_.Remove(extension);
- if (extension->HasApiPermission(Extension::kFileBrowserHandlerPermission))
+ if (extension->HasAPIPermission(ExtensionAPIPermission::kFileBrowserHandler))
file_handler_extensions_.Remove(extension);
}
diff --git a/chrome/browser/extensions/extension_tabs_module.cc b/chrome/browser/extensions/extension_tabs_module.cc
index bfe2e70..dbe4b30 100644
--- a/chrome/browser/extensions/extension_tabs_module.cc
+++ b/chrome/browser/extensions/extension_tabs_module.cc
@@ -548,8 +548,8 @@ bool CreateWindowFunction::RunImpl() {
window_type = Browser::TYPE_POPUP;
app_name = GetExtension()->id();
} else if (type_str == keys::kWindowTypeValuePanel) {
- if (GetExtension()->HasApiPermission(
- Extension::kExperimentalPermission)) {
+ if (GetExtension()->HasAPIPermission(
+ ExtensionAPIPermission::kExperimental)) {
window_type = Browser::TYPE_PANEL;
app_name = GetExtension()->id();
} else {
diff --git a/chrome/browser/geolocation/chrome_geolocation_permission_context.cc b/chrome/browser/geolocation/chrome_geolocation_permission_context.cc
index 9b3bd60..8b8a455 100644
--- a/chrome/browser/geolocation/chrome_geolocation_permission_context.cc
+++ b/chrome/browser/geolocation/chrome_geolocation_permission_context.cc
@@ -517,7 +517,7 @@ void ChromeGeolocationPermissionContext::RequestGeolocationPermission(
const Extension* ext = extensions->GetExtensionByURL(requesting_frame);
if (!ext)
ext = extensions->GetExtensionByWebExtent(requesting_frame);
- if (ext && ext->HasApiPermission(Extension::kGeolocationPermission)) {
+ if (ext && ext->HasAPIPermission(ExtensionAPIPermission::kGeolocation)) {
ExtensionProcessManager* epm = profile_->GetExtensionProcessManager();
RenderProcessHost* process = epm->GetExtensionProcess(requesting_frame);
if (process && process->id() == render_process_id) {
diff --git a/chrome/browser/profiles/profile.cc b/chrome/browser/profiles/profile.cc
index 5c31834..bceb2a3 100644
--- a/chrome/browser/profiles/profile.cc
+++ b/chrome/browser/profiles/profile.cc
@@ -478,7 +478,8 @@ class OffTheRecordProfileImpl : public Profile,
const Extension* installed_app = GetExtensionService()->
GetInstalledAppForRenderer(renderer_child_id);
if (installed_app != NULL && installed_app->is_storage_isolated() &&
- installed_app->HasApiPermission(Extension::kExperimentalPermission)) {
+ installed_app->HasAPIPermission(
+ ExtensionAPIPermission::kExperimental)) {
return GetRequestContextForIsolatedApp(installed_app->id());
}
}
diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc
index 8718711..6b92e21 100644
--- a/chrome/browser/profiles/profile_impl.cc
+++ b/chrome/browser/profiles/profile_impl.cc
@@ -82,6 +82,7 @@
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_paths_internal.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/extension_permission_set.h"
#include "chrome/common/json_pref_store.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
@@ -883,7 +884,8 @@ net::URLRequestContextGetter* ProfileImpl::GetRequestContextForRenderProcess(
const Extension* installed_app = extension_service_->
GetInstalledAppForRenderer(renderer_child_id);
if (installed_app != NULL && installed_app->is_storage_isolated() &&
- installed_app->HasApiPermission(Extension::kExperimentalPermission)) {
+ installed_app->HasAPIPermission(
+ ExtensionAPIPermission::kExperimental)) {
return GetRequestContextForIsolatedApp(installed_app->id());
}
}
diff --git a/chrome/browser/renderer_host/chrome_render_message_filter.cc b/chrome/browser/renderer_host/chrome_render_message_filter.cc
index a43e231..ad64d4f 100644
--- a/chrome/browser/renderer_host/chrome_render_message_filter.cc
+++ b/chrome/browser/renderer_host/chrome_render_message_filter.cc
@@ -466,7 +466,7 @@ void ChromeRenderMessageFilter::OnCanTriggerClipboardRead(const GURL& url,
const Extension* extension =
context->extension_info_map()->extensions().GetByURL(url);
*allowed = extension &&
- extension->HasApiPermission(Extension::kClipboardReadPermission);
+ extension->HasAPIPermission(ExtensionAPIPermission::kClipboardRead);
}
void ChromeRenderMessageFilter::OnCanTriggerClipboardWrite(const GURL& url,
@@ -479,7 +479,7 @@ void ChromeRenderMessageFilter::OnCanTriggerClipboardWrite(const GURL& url,
context->extension_info_map()->extensions().GetByURL(url);
*allowed = url.SchemeIs(chrome::kExtensionScheme) ||
(extension &&
- extension->HasApiPermission(Extension::kClipboardWritePermission));
+ extension->HasAPIPermission(ExtensionAPIPermission::kClipboardWrite));
}
void ChromeRenderMessageFilter::OnClearPredictorCache(int* result) {
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index d35e37b..d0eef11 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -176,6 +176,8 @@
'common/extensions/extension_message_bundle.h',
'common/extensions/extension_messages.cc',
'common/extensions/extension_messages.h',
+ 'common/extensions/extension_permission_set.cc',
+ 'common/extensions/extension_permission_set.h',
'common/extensions/extension_resource.cc',
'common/extensions/extension_resource.h',
'common/extensions/extension_set.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 05e6d1a..2901662 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1889,6 +1889,7 @@
'common/extensions/extension_localization_peer_unittest.cc',
'common/extensions/extension_manifests_unittest.cc',
'common/extensions/extension_message_bundle_unittest.cc',
+ 'common/extensions/extension_permission_set_unittest.cc',
'common/extensions/extension_resource_unittest.cc',
'common/extensions/extension_set_unittest.cc',
'common/extensions/extension_unittest.cc',
diff --git a/chrome/common/extensions/extension.cc b/chrome/common/extensions/extension.cc
index 3a47efe..e98c5f0 100644
--- a/chrome/common/extensions/extension.cc
+++ b/chrome/common/extensions/extension.cc
@@ -98,50 +98,6 @@ bool IsBaseCrxKey(const std::string& key) {
return false;
}
-// Constant used to represent an undefined l10n message id.
-const int kUndefinedMessageId = -1;
-
-// Names of API modules that do not require a permission.
-const char kBrowserActionModuleName[] = "browserAction";
-const char kBrowserActionsModuleName[] = "browserActions";
-const char kDevToolsModuleName[] = "devtools";
-const char kExtensionModuleName[] = "extension";
-const char kI18NModuleName[] = "i18n";
-const char kOmniboxModuleName[] = "omnibox";
-const char kPageActionModuleName[] = "pageAction";
-const char kPageActionsModuleName[] = "pageActions";
-const char kTestModuleName[] = "test";
-const char kTypesModuleName[] = "types";
-
-// Names of modules that can be used without listing it in the permissions
-// section of the manifest.
-const char* kNonPermissionModuleNames[] = {
- kBrowserActionModuleName,
- kBrowserActionsModuleName,
- kDevToolsModuleName,
- kExtensionModuleName,
- kI18NModuleName,
- kOmniboxModuleName,
- kPageActionModuleName,
- kPageActionsModuleName,
- kTestModuleName,
- kTypesModuleName
-};
-const size_t kNumNonPermissionModuleNames =
- arraysize(kNonPermissionModuleNames);
-
-// Names of functions (within modules requiring permissions) that can be used
-// without asking for the module permission. In other words, functions you can
-// use with no permissions specified.
-const char* kNonPermissionFunctionNames[] = {
- "tabs.create",
- "tabs.onRemoved",
- "tabs.remove",
- "tabs.update",
-};
-const size_t kNumNonPermissionFunctionNames =
- arraysize(kNonPermissionFunctionNames);
-
// A singleton object containing global data needed by the extension objects.
class ExtensionConfig {
public:
@@ -149,25 +105,14 @@ class ExtensionConfig {
return Singleton<ExtensionConfig>::get();
}
- Extension::PermissionMessage::MessageId GetPermissionMessageId(
- const std::string& permission) {
- return Extension::kPermissions[permission_map_[permission]].message_id;
- }
-
Extension::ScriptingWhitelist* whitelist() { return &scripting_whitelist_; }
private:
friend struct DefaultSingletonTraits<ExtensionConfig>;
- ExtensionConfig() {
- for (size_t i = 0; i < Extension::kNumPermissions; ++i)
- permission_map_[Extension::kPermissions[i].name] = i;
- };
-
+ ExtensionConfig() { }
~ExtensionConfig() { }
- std::map<const std::string, size_t> permission_map_;
-
// A whitelist of extensions that can script anywhere. Do not add to this
// list (except in tests) without consulting the Extensions team first.
// Note: Component extensions have this right implicitly and do not need to be
@@ -175,10 +120,6 @@ class ExtensionConfig {
Extension::ScriptingWhitelist scripting_whitelist_;
};
-// Aliased to kTabPermission for purposes of API checks, but not allowed
-// in the permissions field of the manifest.
-static const char kWindowPermission[] = "windows";
-
// Rank extension locations in a way that allows
// Extension::GetHigherPriorityLocation() to compare locations.
// An extension installed from two locations will have the location
@@ -264,90 +205,6 @@ const int Extension::kPageActionIconMaxSize = 19;
const int Extension::kBrowserActionIconMaxSize = 19;
const int Extension::kSidebarIconMaxSize = 16;
-// Explicit permissions -- permission declaration required.
-const char Extension::kBackgroundPermission[] = "background";
-const char Extension::kBookmarkPermission[] = "bookmarks";
-const char Extension::kClipboardReadPermission[] = "clipboardRead";
-const char Extension::kClipboardWritePermission[] = "clipboardWrite";
-const char Extension::kContextMenusPermission[] = "contextMenus";
-const char Extension::kContentSettingsPermission[] = "contentSettings";
-const char Extension::kCookiePermission[] = "cookies";
-const char Extension::kChromePrivatePermission[] = "chromePrivate";
-const char Extension::kChromeosInfoPrivatePermission[] = "chromeosInfoPrivate";
-const char Extension::kDebuggerPermission[] = "debugger";
-const char Extension::kExperimentalPermission[] = "experimental";
-const char Extension::kFileBrowserHandlerPermission[] = "fileBrowserHandler";
-const char Extension::kFileBrowserPrivatePermission[] = "fileBrowserPrivate";
-const char Extension::kGeolocationPermission[] = "geolocation";
-const char Extension::kHistoryPermission[] = "history";
-const char Extension::kIdlePermission[] = "idle";
-const char Extension::kManagementPermission[] = "management";
-const char Extension::kMediaPlayerPrivatePermission[] = "mediaPlayerPrivate";
-const char Extension::kNotificationPermission[] = "notifications";
-const char Extension::kProxyPermission[] = "proxy";
-const char Extension::kTabPermission[] = "tabs";
-const char Extension::kUnlimitedStoragePermission[] = "unlimitedStorage";
-const char Extension::kWebstorePrivatePermission[] = "webstorePrivate";
-const char Extension::kWebSocketProxyPrivatePermission[] =
- "webSocketProxyPrivate";
-
-// In general, all permissions should have an install message.
-// See ExtensionsTest.PermissionMessages for an explanation of each
-// exception.
-const Extension::Permission Extension::kPermissions[] = {
- { kBackgroundPermission, PermissionMessage::ID_NONE },
- { kBookmarkPermission, PermissionMessage::ID_BOOKMARKS },
- { kChromePrivatePermission, PermissionMessage::ID_NONE },
- { kChromeosInfoPrivatePermission, PermissionMessage::ID_NONE },
- { kClipboardReadPermission, PermissionMessage::ID_CLIPBOARD },
- { kClipboardWritePermission, PermissionMessage::ID_NONE },
- { kContentSettingsPermission, PermissionMessage::ID_NONE },
- { kContextMenusPermission, PermissionMessage::ID_NONE },
- { kCookiePermission, PermissionMessage::ID_NONE },
- { kDebuggerPermission, PermissionMessage::ID_DEBUGGER },
- { kExperimentalPermission, PermissionMessage::ID_NONE },
- { kFileBrowserHandlerPermission, PermissionMessage::ID_NONE },
- { kFileBrowserPrivatePermission, PermissionMessage::ID_NONE },
- { kGeolocationPermission, PermissionMessage::ID_GEOLOCATION },
- { kHistoryPermission, PermissionMessage::ID_BROWSING_HISTORY },
- { kIdlePermission, PermissionMessage::ID_NONE },
- { kManagementPermission, PermissionMessage::ID_MANAGEMENT },
- { kMediaPlayerPrivatePermission, PermissionMessage::ID_NONE },
- { kNotificationPermission, PermissionMessage::ID_NONE },
- { kProxyPermission, PermissionMessage::ID_NONE },
- { kTabPermission, PermissionMessage::ID_TABS },
- { kUnlimitedStoragePermission, PermissionMessage::ID_NONE },
- { kWebSocketProxyPrivatePermission, PermissionMessage::ID_NONE },
- { kWebstorePrivatePermission, PermissionMessage::ID_NONE },
-};
-const size_t Extension::kNumPermissions = arraysize(Extension::kPermissions);
-
-const char* const Extension::kHostedAppPermissionNames[] = {
- Extension::kBackgroundPermission,
- Extension::kChromePrivatePermission,
- Extension::kClipboardReadPermission,
- Extension::kClipboardWritePermission,
- Extension::kExperimentalPermission,
- Extension::kGeolocationPermission,
- Extension::kNotificationPermission,
- Extension::kUnlimitedStoragePermission,
- Extension::kWebstorePrivatePermission,
-};
-const size_t Extension::kNumHostedAppPermissions =
- arraysize(Extension::kHostedAppPermissionNames);
-
-const char* const Extension::kComponentPrivatePermissionNames[] = {
- Extension::kFileBrowserPrivatePermission,
- Extension::kWebstorePrivatePermission,
- Extension::kMediaPlayerPrivatePermission,
- Extension::kChromeosInfoPrivatePermission,
-};
-const size_t Extension::kNumComponentPrivatePermissions =
- arraysize(Extension::kComponentPrivatePermissionNames);
-
-// We purposefully don't put this into kPermissionNames.
-const char Extension::kOldUnlimitedStoragePermission[] = "unlimited_storage";
-
const int Extension::kValidWebExtentSchemes =
URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS;
@@ -364,84 +221,6 @@ Extension::InputComponentInfo::InputComponentInfo()
Extension::InputComponentInfo::~InputComponentInfo() {}
//
-// PermissionMessage
-//
-
-// static
-Extension::PermissionMessage Extension::PermissionMessage::CreateFromMessageId(
- Extension::PermissionMessage::MessageId message_id) {
- DCHECK_GT(PermissionMessage::ID_NONE, PermissionMessage::ID_UNKNOWN);
- if (message_id <= ID_NONE)
- return PermissionMessage(message_id, string16());
-
- string16 message = l10n_util::GetStringUTF16(kMessageIds[message_id]);
- return PermissionMessage(message_id, message);
-}
-
-// static
-Extension::PermissionMessage Extension::PermissionMessage::CreateFromHostList(
- const std::vector<std::string>& hosts) {
- CHECK(hosts.size() > 0);
-
- MessageId message_id;
- string16 message;
- switch (hosts.size()) {
- case 1:
- message_id = ID_HOSTS_1;
- message = l10n_util::GetStringFUTF16(kMessageIds[message_id],
- UTF8ToUTF16(hosts[0]));
- break;
- case 2:
- message_id = ID_HOSTS_2;
- message = l10n_util::GetStringFUTF16(kMessageIds[message_id],
- UTF8ToUTF16(hosts[0]),
- UTF8ToUTF16(hosts[1]));
- break;
- case 3:
- message_id = ID_HOSTS_3;
- message = l10n_util::GetStringFUTF16(kMessageIds[message_id],
- UTF8ToUTF16(hosts[0]),
- UTF8ToUTF16(hosts[1]),
- UTF8ToUTF16(hosts[2]));
- break;
- default:
- message_id = ID_HOSTS_4_OR_MORE;
- message = l10n_util::GetStringFUTF16(
- kMessageIds[message_id],
- UTF8ToUTF16(hosts[0]),
- UTF8ToUTF16(hosts[1]),
- base::IntToString16(hosts.size() - 2));
- break;
- }
-
- return PermissionMessage(message_id, message);
-}
-
-Extension::PermissionMessage::PermissionMessage(
- Extension::PermissionMessage::MessageId message_id, string16 message)
- : message_id_(message_id),
- message_(message) {
-}
-
-const int Extension::PermissionMessage::kMessageIds[] = {
- kUndefinedMessageId, // "unknown"
- kUndefinedMessageId, // "none"
- IDS_EXTENSION_PROMPT_WARNING_BOOKMARKS,
- IDS_EXTENSION_PROMPT_WARNING_GEOLOCATION,
- IDS_EXTENSION_PROMPT_WARNING_BROWSING_HISTORY,
- IDS_EXTENSION_PROMPT_WARNING_TABS,
- IDS_EXTENSION_PROMPT_WARNING_MANAGEMENT,
- IDS_EXTENSION_PROMPT_WARNING_DEBUGGER,
- IDS_EXTENSION_PROMPT_WARNING_1_HOST,
- IDS_EXTENSION_PROMPT_WARNING_2_HOSTS,
- IDS_EXTENSION_PROMPT_WARNING_3_HOSTS,
- IDS_EXTENSION_PROMPT_WARNING_4_OR_MORE_HOSTS,
- IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS,
- IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS,
- IDS_EXTENSION_PROMPT_WARNING_CLIPBOARD
-};
-
-//
// Extension
//
@@ -491,145 +270,12 @@ Extension::Location Extension::GetHigherPriorityLocation(
return (loc1_rank > loc2_rank ? loc1 : loc2 );
}
-// static
-Extension::PermissionMessage::MessageId Extension::GetPermissionMessageId(
- const std::string& permission) {
- return ExtensionConfig::GetInstance()->GetPermissionMessageId(permission);
-}
-
-Extension::PermissionMessages Extension::GetPermissionMessages() const {
- PermissionMessages messages;
- if (!plugins().empty()) {
- messages.push_back(PermissionMessage::CreateFromMessageId(
- PermissionMessage::ID_FULL_ACCESS));
- return messages;
- }
-
- if (HasEffectiveAccessToAllHosts()) {
- messages.push_back(PermissionMessage::CreateFromMessageId(
- PermissionMessage::ID_HOSTS_ALL));
- } else {
- std::vector<std::string> hosts = GetDistinctHostsForDisplay(
- GetEffectiveHostPermissions().patterns());
- if (!hosts.empty())
- messages.push_back(PermissionMessage::CreateFromHostList(hosts));
- }
-
- std::set<PermissionMessage> simple_msgs = GetSimplePermissionMessages();
- messages.insert(messages.end(), simple_msgs.begin(), simple_msgs.end());
-
- return messages;
+ExtensionPermissionMessages Extension::GetPermissionMessages() const {
+ return permission_set_->GetPermissionMessages();
}
std::vector<string16> Extension::GetPermissionMessageStrings() const {
- std::vector<string16> messages;
- PermissionMessages permissions = GetPermissionMessages();
- for (PermissionMessages::const_iterator i = permissions.begin();
- i != permissions.end(); ++i)
- messages.push_back(i->message());
- return messages;
-}
-
-std::set<Extension::PermissionMessage>
- Extension::GetSimplePermissionMessages() const {
- std::set<PermissionMessage> messages;
- std::set<std::string>::const_iterator i;
- for (i = api_permissions().begin(); i != api_permissions().end(); ++i) {
- PermissionMessage::MessageId message_id = GetPermissionMessageId(*i);
- DCHECK_GT(PermissionMessage::ID_NONE, PermissionMessage::ID_UNKNOWN);
- if (message_id > PermissionMessage::ID_NONE)
- messages.insert(PermissionMessage::CreateFromMessageId(message_id));
- }
- return messages;
-}
-
-// static
-std::vector<std::string> Extension::GetDistinctHostsForDisplay(
- const URLPatternList& list) {
- return GetDistinctHosts(list, true);
-}
-
-// static
-bool Extension::IsElevatedHostList(
- const URLPatternList& old_list, const URLPatternList& new_list) {
- // TODO(jstritar): This is overly conservative with respect to subdomains.
- // For example, going from *.google.com to www.google.com will be
- // considered an elevation, even though it is not (http://crbug.com/65337).
-
- std::vector<std::string> new_hosts = GetDistinctHosts(new_list, false);
- std::vector<std::string> old_hosts = GetDistinctHosts(old_list, false);
-
- std::set<std::string> old_hosts_set(old_hosts.begin(), old_hosts.end());
- std::set<std::string> new_hosts_set(new_hosts.begin(), new_hosts.end());
- std::set<std::string> new_hosts_only;
-
- std::set_difference(new_hosts_set.begin(), new_hosts_set.end(),
- old_hosts_set.begin(), old_hosts_set.end(),
- std::inserter(new_hosts_only, new_hosts_only.begin()));
-
- return !new_hosts_only.empty();
-}
-
-// Helper for GetDistinctHosts(): com > net > org > everything else.
-static bool RcdBetterThan(const std::string& a, const std::string& b) {
- if (a == b)
- return false;
- if (a == "com")
- return true;
- if (a == "net")
- return b != "com";
- if (a == "org")
- return b != "com" && b != "net";
- return false;
-}
-
-// static
-std::vector<std::string> Extension::GetDistinctHosts(
- const URLPatternList& host_patterns,
- bool include_rcd) {
- // Use a vector to preserve order (also faster than a map on small sets).
- // Each item is a host split into two parts: host without RCDs and
- // current best RCD.
- typedef std::vector<std::pair<std::string, std::string> > HostVector;
- HostVector hosts_best_rcd;
- for (size_t i = 0; i < host_patterns.size(); ++i) {
- std::string host = host_patterns[i].host();
-
- // Add the subdomain wildcard back to the host, if necessary.
- if (host_patterns[i].match_subdomains())
- host = "*." + host;
-
- // If the host has an RCD, split it off so we can detect duplicates.
- std::string rcd;
- size_t reg_len = net::RegistryControlledDomainService::GetRegistryLength(
- host, false);
- if (reg_len && reg_len != std::string::npos) {
- if (include_rcd) // else leave rcd empty
- rcd = host.substr(host.size() - reg_len);
- host = host.substr(0, host.size() - reg_len);
- }
-
- // Check if we've already seen this host.
- HostVector::iterator it = hosts_best_rcd.begin();
- for (; it != hosts_best_rcd.end(); ++it) {
- if (it->first == host)
- break;
- }
- // If this host was found, replace the RCD if this one is better.
- if (it != hosts_best_rcd.end()) {
- if (include_rcd && RcdBetterThan(rcd, it->second))
- it->second = rcd;
- } else { // Previously unseen host, append it.
- hosts_best_rcd.push_back(std::make_pair(host, rcd));
- }
- }
-
- // Build up the final vector by concatenating hosts and RCDs.
- std::vector<std::string> distinct_hosts;
- for (HostVector::iterator it = hosts_best_rcd.begin();
- it != hosts_best_rcd.end(); ++it)
- distinct_hosts.push_back(it->first + it->second);
- return distinct_hosts;
+ return permission_set_->GetWarningMessages();
}
FilePath Extension::MaybeNormalizePath(const FilePath& path) {
@@ -648,16 +294,6 @@ FilePath Extension::MaybeNormalizePath(const FilePath& path) {
#endif
}
-// static
-bool Extension::IsHostedAppPermission(const std::string& str) {
- for (size_t i = 0; i < Extension::kNumHostedAppPermissions; ++i) {
- if (str == Extension::kHostedAppPermissionNames[i]) {
- return true;
- }
- }
- return false;
-}
-
const std::string Extension::VersionString() const {
return version()->GetString();
}
@@ -1624,55 +1260,6 @@ bool Extension::FormatPEMForFileOutput(const std::string& input,
}
// static
-bool Extension::IsPrivilegeIncrease(const bool granted_full_access,
- const std::set<std::string>& granted_apis,
- const URLPatternSet& granted_extent,
- const Extension* new_extension) {
- // If the extension had native code access, we don't need to go any further.
- // Things can't get any worse.
- if (granted_full_access)
- return false;
-
- // Otherwise, if the new extension has a plugin, it's a privilege increase.
- if (new_extension->HasFullPermissions())
- return true;
-
- // If the extension hadn't been granted access to all hosts in the past, then
- // see if the extension requires more host permissions.
- if (!HasEffectiveAccessToAllHosts(granted_extent, granted_apis)) {
- if (new_extension->HasEffectiveAccessToAllHosts())
- return true;
-
- const URLPatternSet new_extent =
- new_extension->GetEffectiveHostPermissions();
-
- if (IsElevatedHostList(granted_extent.patterns(), new_extent.patterns()))
- return true;
- }
-
- std::set<std::string> new_apis = new_extension->api_permissions();
- std::set<std::string> new_apis_only;
- std::set_difference(new_apis.begin(), new_apis.end(),
- granted_apis.begin(), granted_apis.end(),
- std::inserter(new_apis_only, new_apis_only.begin()));
-
- // Ignore API permissions that don't require user approval when deciding if
- // an extension has increased its privileges.
- size_t new_api_count = 0;
- for (std::set<std::string>::iterator i = new_apis_only.begin();
- i != new_apis_only.end(); ++i) {
- DCHECK_GT(PermissionMessage::ID_NONE, PermissionMessage::ID_UNKNOWN);
- if (GetPermissionMessageId(*i) > PermissionMessage::ID_NONE)
- new_api_count++;
- }
-
- if (new_api_count)
- return true;
-
- return false;
-}
-
-// static
void Extension::DecodeIcon(const Extension* extension,
Icons icon_size,
scoped_ptr<SkBitmap>* result) {
@@ -1739,6 +1326,9 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
(flags & STRICT_ERROR_CHECKS ? URLPattern::PARSE_STRICT
: URLPattern::PARSE_LENIENT);
+ // Initialize permissions with an empty, default permission set.
+ permission_set_.reset(new ExtensionPermissionSet());
+
if (source.HasKey(keys::kPublicKey)) {
std::string public_key_bytes;
if (!source.GetString(keys::kPublicKey,
@@ -2257,6 +1847,9 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
}
}
+ ExtensionAPIPermissionSet api_permissions;
+ URLPatternSet host_permissions;
+
// Initialize the permissions (optional).
if (source.HasKey(keys::kPermissions)) {
ListValue* permissions = NULL;
@@ -2274,10 +1867,13 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
return false;
}
+ ExtensionAPIPermission* permission =
+ ExtensionPermissionsInfo::GetInstance()->GetByName(permission_str);
+
// Only COMPONENT extensions can use private APIs.
// TODO(asargent) - We want a more general purpose mechanism for this,
// and better error messages. (http://crbug.com/54013)
- if (!IsComponentOnlyPermission(permission_str)
+ if (!IsComponentOnlyPermission(permission)
#ifndef NDEBUG
&& !CommandLine::ForCurrentProcess()->HasSwitch(
switches::kExposePrivateExtensionApi)
@@ -2286,31 +1882,27 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
continue;
}
- // Remap the old unlimited storage permission name.
- if (permission_str == kOldUnlimitedStoragePermission)
- permission_str = kUnlimitedStoragePermission;
-
if (web_extent().is_empty() || location() == Extension::COMPONENT) {
// Check if it's a module permission. If so, enable that permission.
- if (IsAPIPermission(permission_str)) {
+ if (permission != NULL) {
// Only allow the experimental API permission if the command line
// flag is present, or if the extension is a component of Chrome.
- if (IsDisallowedExperimentalPermission(permission_str) &&
+ if (IsDisallowedExperimentalPermission(permission->id()) &&
location() != Extension::COMPONENT) {
*error = errors::kExperimentalFlagRequired;
return false;
}
- api_permissions_.insert(permission_str);
+ api_permissions.insert(permission->id());
continue;
}
} else {
// Hosted apps only get access to a subset of the valid permissions.
- if (IsHostedAppPermission(permission_str)) {
- if (IsDisallowedExperimentalPermission(permission_str)) {
+ if (permission != NULL && permission->is_hosted_app()) {
+ if (IsDisallowedExperimentalPermission(permission->id())) {
*error = errors::kExperimentalFlagRequired;
return false;
}
- api_permissions_.insert(permission_str);
+ api_permissions.insert(permission->id());
continue;
}
}
@@ -2340,7 +1932,7 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
pattern.valid_schemes() & ~URLPattern::SCHEME_FILE);
}
- host_permissions_.push_back(pattern);
+ host_permissions.AddPattern(pattern);
}
// If it's not a host permission, then it's probably an unknown API
@@ -2365,8 +1957,7 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
if (is_hosted_app()) {
// Make sure "background" permission is set.
- if (api_permissions_.find(kBackgroundPermission) ==
- api_permissions_.end()) {
+ if (!api_permissions.count(ExtensionAPIPermission::kBackground)) {
*error = errors::kBackgroundPermissionNeeded;
return false;
}
@@ -2605,7 +2196,7 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
*error = errors::kInvalidDevToolsPage;
return false;
}
- if (!HasApiPermission(Extension::kExperimentalPermission)) {
+ if (!api_permissions.count(ExtensionAPIPermission::kExperimental)) {
*error = errors::kDevToolsExperimental;
return false;
}
@@ -2619,7 +2210,7 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
*error = errors::kInvalidSidebar;
return false;
}
- if (!HasApiPermission(Extension::kExperimentalPermission)) {
+ if (!api_permissions.count(ExtensionAPIPermission::kExperimental)) {
*error = errors::kSidebarExperimental;
return false;
}
@@ -2705,7 +2296,8 @@ bool Extension::InitFromValue(const DictionaryValue& source, int flags,
return false;
}
- InitEffectiveHostPermissions();
+ permission_set_.reset(
+ new ExtensionPermissionSet(this, api_permissions, host_permissions));
// Although |source| is passed in as a const, it's still possible to modify
// it. This is dangerous since the utility process re-uses |source| after
@@ -2896,91 +2488,37 @@ bool Extension::CanSpecifyHostPermission(const URLPattern& pattern) const {
return true;
}
-// static
-bool Extension::HasApiPermission(
- const std::set<std::string>& api_permissions,
- const std::string& function_name) {
- std::string permission_name = function_name;
-
- for (size_t i = 0; i < kNumNonPermissionFunctionNames; ++i) {
- if (permission_name == kNonPermissionFunctionNames[i])
- return true;
- }
-
- // See if this is a function or event name first and strip out the package.
- // Functions will be of the form package.function
- // Events will be of the form package/id or package.optional.stuff
- size_t separator = function_name.find_first_of("./");
- if (separator != std::string::npos)
- permission_name = function_name.substr(0, separator);
-
- // windows and tabs are the same permission.
- if (permission_name == kWindowPermission)
- permission_name = Extension::kTabPermission;
-
- if (api_permissions.count(permission_name))
- return true;
-
- for (size_t i = 0; i < kNumNonPermissionModuleNames; ++i) {
- if (permission_name == kNonPermissionModuleNames[i]) {
- return true;
- }
- }
-
- return false;
+bool Extension::HasAPIPermission(
+ ExtensionAPIPermission::ID permission) const {
+ return permission_set()->HasAPIPermission(permission);
}
-bool Extension::HasHostPermission(const GURL& url) const {
- for (URLPatternList::const_iterator host = host_permissions().begin();
- host != host_permissions().end(); ++host) {
- // Non-component extensions can only access chrome://favicon and no other
- // chrome:// scheme urls.
- if (url.SchemeIs(chrome::kChromeUIScheme) &&
- url.host() != chrome::kChromeUIFaviconHost &&
- location() != Extension::COMPONENT)
- return false;
-
- if (host->MatchesURL(url))
- return true;
- }
- return false;
+bool Extension::HasAPIPermission(
+ const std::string& function_name) const {
+ return permission_set()->HasAccessToFunction(function_name);
}
-void Extension::InitEffectiveHostPermissions() {
- // Some APIs effectively grant access to every site. New ones should be
- // added here. (I'm looking at you, network API)
- if (HasApiPermission(api_permissions_, kProxyPermission) ||
- !devtools_url_.is_empty()) {
- URLPattern all_urls(URLPattern::SCHEME_ALL);
- all_urls.set_match_all_urls(true);
- effective_host_permissions_.AddPattern(all_urls);
- return;
- }
-
- for (URLPatternList::const_iterator host = host_permissions().begin();
- host != host_permissions().end(); ++host)
- effective_host_permissions_.AddPattern(*host);
+const URLPatternSet& Extension::GetEffectiveHostPermissions() const {
+ return permission_set()->effective_hosts();
+}
- for (UserScriptList::const_iterator content_script =
- content_scripts().begin();
- content_script != content_scripts().end(); ++content_script) {
- URLPatternList::const_iterator pattern =
- content_script->url_patterns().begin();
- for (; pattern != content_script->url_patterns().end(); ++pattern)
- effective_host_permissions_.AddPattern(*pattern);
- }
+bool Extension::HasHostPermission(const GURL& url) const {
+ if (url.SchemeIs(chrome::kChromeUIScheme) &&
+ url.host() != chrome::kChromeUIFaviconHost &&
+ location() != Extension::COMPONENT)
+ return false;
+ return permission_set()->HasExplicitAccessToOrigin(url);
}
-bool Extension::IsComponentOnlyPermission(const std::string& permission) const {
+bool Extension::IsComponentOnlyPermission(
+ const ExtensionAPIPermission* api) const {
if (location() == Extension::COMPONENT)
return true;
- // Non-component extensions are not allowed to access private apis.
- for (size_t i = 0; i < Extension::kNumComponentPrivatePermissions; ++i) {
- if (permission == Extension::kComponentPrivatePermissionNames[i])
- return false;
- }
- return true;
+ if (api == NULL)
+ return true;
+
+ return !api->is_component_only();
}
bool Extension::HasMultipleUISurfaces() const {
@@ -3025,10 +2563,8 @@ bool Extension::CanExecuteScriptOnPage(const GURL& page_url,
// Otherwise, see if this extension has permission to execute script
// programmatically on pages.
- for (size_t i = 0; i < host_permissions_.size(); ++i) {
- if (host_permissions_[i].MatchesURL(page_url))
- return true;
- }
+ if (permission_set()->HasExplicitAccessToOrigin(page_url))
+ return true;
if (error) {
*error = ExtensionErrorUtils::FormatErrorMessage(errors::kCannotAccessPage,
@@ -3038,28 +2574,12 @@ bool Extension::CanExecuteScriptOnPage(const GURL& page_url,
return false;
}
-// static
-bool Extension::HasEffectiveAccessToAllHosts(
- const URLPatternSet& effective_host_permissions,
- const std::set<std::string>& api_permissions) {
- const URLPatternList patterns = effective_host_permissions.patterns();
- for (URLPatternList::const_iterator host = patterns.begin();
- host != patterns.end(); ++host) {
- if (host->match_all_urls() ||
- (host->match_subdomains() && host->host().empty()))
- return true;
- }
-
- return false;
-}
-
bool Extension::HasEffectiveAccessToAllHosts() const {
- return HasEffectiveAccessToAllHosts(GetEffectiveHostPermissions(),
- api_permissions());
+ return permission_set_->HasEffectiveAccessToAllHosts();
}
bool Extension::HasFullPermissions() const {
- return !plugins().empty();
+ return permission_set_->HasEffectiveFullAccess();
}
bool Extension::ShowConfigureContextMenus() const {
@@ -3071,21 +2591,12 @@ bool Extension::ShowConfigureContextMenus() const {
}
bool Extension::IsDisallowedExperimentalPermission(
- const std::string& permission_str) const {
- return permission_str == Extension::kExperimentalPermission &&
+ ExtensionAPIPermission::ID permission) const {
+ return permission == ExtensionAPIPermission::kExperimental &&
!CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableExperimentalExtensionApis);
}
-bool Extension::IsAPIPermission(const std::string& str) const {
- for (size_t i = 0; i < Extension::kNumPermissions; ++i) {
- if (str == Extension::kPermissions[i].name) {
- return true;
- }
- }
- return false;
-}
-
bool Extension::CanExecuteScriptEverywhere() const {
if (location() == Extension::COMPONENT
#ifndef NDEBUG
@@ -3161,7 +2672,8 @@ ExtensionInfo::~ExtensionInfo() {}
UninstalledExtensionInfo::UninstalledExtensionInfo(
const Extension& extension)
: extension_id(extension.id()),
- extension_api_permissions(extension.api_permissions()),
+ extension_api_permissions(
+ extension.permission_set()->GetAPIsAsStrings()),
extension_type(extension.GetType()),
update_url(extension.update_url()) {}
diff --git a/chrome/common/extensions/extension.h b/chrome/common/extensions/extension.h
index 6624268..7e584d7 100644
--- a/chrome/common/extensions/extension.h
+++ b/chrome/common/extensions/extension.h
@@ -18,6 +18,7 @@
#include "base/memory/scoped_ptr.h"
#include "chrome/common/extensions/extension_constants.h"
#include "chrome/common/extensions/extension_icon_set.h"
+#include "chrome/common/extensions/extension_permission_set.h"
#include "chrome/common/extensions/user_script.h"
#include "chrome/common/extensions/url_pattern.h"
#include "chrome/common/extensions/url_pattern_set.h"
@@ -142,80 +143,6 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
std::string gender;
};
- // When prompting the user to install or approve permissions, we display
- // messages describing the effects of the permissions and not the permissions
- // themselves. Each PermissionMessage represents one of the messages that is
- // shown to the user.
- class PermissionMessage {
- public:
- // Do not reorder or add new enumerations in this list. If you need to add a
- // new enum, add it just prior to ID_ENUM_BOUNDARY and enter its l10n
- // message in kMessageIds.
- enum MessageId {
- ID_UNKNOWN,
- ID_NONE,
- ID_BOOKMARKS,
- ID_GEOLOCATION,
- ID_BROWSING_HISTORY,
- ID_TABS,
- ID_MANAGEMENT,
- ID_DEBUGGER,
- ID_HOSTS_1,
- ID_HOSTS_2,
- ID_HOSTS_3,
- ID_HOSTS_4_OR_MORE,
- ID_HOSTS_ALL,
- ID_FULL_ACCESS,
- ID_CLIPBOARD,
- ID_ENUM_BOUNDARY
- };
-
- // Creates a permission message with the given |message_id| and initializes
- // its message to the appropriate value.
- static PermissionMessage CreateFromMessageId(MessageId message_id);
-
- // Creates the corresponding permission message for a list of hosts. This
- // method exists because the hosts are presented as one message that depends
- // on what and how many hosts there are.
- static PermissionMessage CreateFromHostList(
- const std::vector<std::string>& hosts);
-
- // Gets the id of the permission message, which can be used in UMA
- // histograms.
- MessageId message_id() const { return message_id_; }
-
- // Gets a localized message describing this permission. Please note that
- // the message will be empty for message types TYPE_NONE and TYPE_UNKNOWN.
- const string16& message() const { return message_; }
-
- // Comparator to work with std::set.
- bool operator<(const PermissionMessage& that) const {
- return message_id_ < that.message_id_;
- }
-
- private:
- PermissionMessage(MessageId message_id, string16 message_);
-
- // The index of the id in the array is its enum value. The first two values
- // are non-existent message ids to act as placeholders for "unknown" and
- // "none".
- // Note: Do not change the order of the items in this list since they
- // are used in a histogram. The order must match the MessageId order.
- static const int kMessageIds[];
-
- MessageId message_id_;
- string16 message_;
- };
-
- typedef std::vector<PermissionMessage> PermissionMessages;
-
- // A permission is defined by its |name| (what is used in the manifest),
- // and the |message_id| that's used by install/update UI.
- struct Permission {
- const char* const name;
- const PermissionMessage::MessageId message_id;
- };
-
enum InitFromValueFlags {
NO_FLAGS = 0,
@@ -256,38 +183,15 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// its install source should be set to GetHigherPriorityLocation(A, B).
static Location GetHigherPriorityLocation(Location loc1, Location loc2);
- // Get's the install message id for |permission|. Returns
- // MessageId::TYPE_NONE if none exists.
- static PermissionMessage::MessageId GetPermissionMessageId(
- const std::string& permission);
-
// Returns the full list of permission messages that this extension
// should display at install time.
- PermissionMessages GetPermissionMessages() const;
+ ExtensionPermissionMessages GetPermissionMessages() const;
// Returns the full list of permission messages that this extension
// should display at install time. The messages are returned as strings
// for convenience.
std::vector<string16> GetPermissionMessageStrings() const;
- // Returns the distinct hosts that should be displayed in the install UI
- // for the URL patterns |list|. This discards some of the detail that is
- // present in the manifest to make it as easy as possible to process by
- // users. In particular we disregard the scheme and path components of
- // URLPatterns and de-dupe the result, which includes filtering out common
- // hosts with differing RCDs (aka Registry Controlled Domains, most of which
- // are Top Level Domains but also include exceptions like co.uk).
- // NOTE: when de-duping hosts the preferred RCD will be returned, given this
- // order of preference: .com, .net, .org, first in list.
- static std::vector<std::string> GetDistinctHostsForDisplay(
- const URLPatternList& list);
-
- // Compares two URLPatternLists for security equality by returning whether
- // the URL patterns in |new_list| contain additional distinct hosts compared
- // to |old_list|.
- static bool IsElevatedHostList(
- const URLPatternList& old_list, const URLPatternList& new_list);
-
// Icon sizes used by the extension system.
static const int kIconSizes[];
@@ -296,56 +200,12 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
static const int kBrowserActionIconMaxSize;
static const int kSidebarIconMaxSize;
- // Each permission is a module that the extension is permitted to use.
- //
- // NOTE: To add a new permission, define it here, and add an entry to
- // Extension::kPermissions.
- static const char kBackgroundPermission[];
- static const char kBookmarkPermission[];
- static const char kClipboardReadPermission[];
- static const char kClipboardWritePermission[];
- static const char kContentSettingsPermission[];
- static const char kContextMenusPermission[];
- static const char kCookiePermission[];
- static const char kChromePrivatePermission[];
- static const char kChromeosInfoPrivatePermission[];
- static const char kDebuggerPermission[];
- static const char kExperimentalPermission[];
- static const char kFileBrowserHandlerPermission[];
- static const char kFileBrowserPrivatePermission[];
- static const char kGeolocationPermission[];
- static const char kHistoryPermission[];
- static const char kIdlePermission[];
- static const char kManagementPermission[];
- static const char kMediaPlayerPrivatePermission[];
- static const char kNotificationPermission[];
- static const char kProxyPermission[];
- static const char kTabPermission[];
- static const char kUnlimitedStoragePermission[];
- static const char kWebstorePrivatePermission[];
- static const char kWebSocketProxyPrivatePermission[];
-
- static const Permission kPermissions[];
- static const size_t kNumPermissions;
- static const char* const kHostedAppPermissionNames[];
- static const size_t kNumHostedAppPermissions;
- static const char* const kComponentPrivatePermissionNames[];
- static const size_t kNumComponentPrivatePermissions;
-
- // The old name for the unlimited storage permission, which is deprecated but
- // still accepted as meaning the same thing as kUnlimitedStoragePermission.
- static const char kOldUnlimitedStoragePermission[];
-
// Valid schemes for web extent URLPatterns.
static const int kValidWebExtentSchemes;
// Valid schemes for host permission URLPatterns.
static const int kValidHostPermissionSchemes;
- // Returns true if the string is one of the known hosted app permissions (see
- // kHostedAppPermissionNames).
- static bool IsHostedAppPermission(const std::string& permission);
-
// The name of the manifest inside an extension.
static const FilePath::CharType kManifestFilename[];
@@ -455,14 +315,6 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
std::string* output,
bool is_public);
- // Determine whether |new_extension| has increased privileges compared to
- // its previously granted permissions, specified by |granted_apis|,
- // |granted_extent| and |granted_full_access|.
- static bool IsPrivilegeIncrease(const bool granted_full_access,
- const std::set<std::string>& granted_apis,
- const URLPatternSet& granted_extent,
- const Extension* new_extension);
-
// Given an extension and icon size, read it if present and decode it into
// result. In the browser process, this will DCHECK if not called on the
// file thread. To easily load extension images on the UI thread, see
@@ -497,24 +349,10 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
static void SetScriptingWhitelist(const ScriptingWhitelist& whitelist);
static const ScriptingWhitelist* GetScriptingWhitelist();
- // Returns true if the extension has the specified API permission.
- static bool HasApiPermission(const std::set<std::string>& api_permissions,
- const std::string& function_name);
-
- // Whether the |effective_host_permissions| and |api_permissions| include
- // effective access to all hosts. See the non-static version of the method
- // for more details.
- static bool HasEffectiveAccessToAllHosts(
- const URLPatternSet& effective_host_permissions,
- const std::set<std::string>& api_permissions);
+ bool HasAPIPermission(ExtensionAPIPermission::ID permission) const;
+ bool HasAPIPermission(const std::string& function_name) const;
- bool HasApiPermission(const std::string& function_name) const {
- return HasApiPermission(this->api_permissions(), function_name);
- }
-
- const URLPatternSet& GetEffectiveHostPermissions() const {
- return effective_host_permissions_;
- }
+ const URLPatternSet& GetEffectiveHostPermissions() const;
// Whether or not the extension is allowed permission for a URL pattern from
// the manifest. http, https, and chrome://favicon/ is allowed for all
@@ -630,10 +468,9 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
const GURL& options_url() const { return options_url_; }
const GURL& devtools_url() const { return devtools_url_; }
const std::vector<GURL>& toolstrips() const { return toolstrips_; }
- const std::set<std::string>& api_permissions() const {
- return api_permissions_;
+ const ExtensionPermissionSet* permission_set() const {
+ return permission_set_.get();
}
- const URLPatternList& host_permissions() const { return host_permissions_; }
const GURL& update_url() const { return update_url_; }
const ExtensionIconSet& icons() const { return icons_; }
const DictionaryValue* manifest_value() const {
@@ -766,10 +603,6 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
ExtensionSidebarDefaults* LoadExtensionSidebarDefaults(
const DictionaryValue* sidebar, std::string* error);
- // Calculates the effective host permissions from the permissions and content
- // script petterns.
- void InitEffectiveHostPermissions();
-
// Returns true if the extension has more than one "UI surface". For example,
// an extension that has a browser action and a page action.
bool HasMultipleUISurfaces() const;
@@ -780,21 +613,12 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// Only allow the experimental API permission if the command line
// flag is present.
- bool IsDisallowedExperimentalPermission(const std::string& permission) const;
-
- // Returns true if the string is one of the known api permissions (see
- // kPermissions).
- bool IsAPIPermission(const std::string& permission) const;
+ bool IsDisallowedExperimentalPermission(
+ ExtensionAPIPermission::ID permission) const;
// Returns true if this is a component, or we are not attempting to access a
// component-private permission.
- bool IsComponentOnlyPermission(const std::string& permission) const;
-
- // The set of unique API install messages that the extension has.
- // NOTE: This only includes messages related to permissions declared in the
- // "permissions" key in the manifest. Permissions implied from other features
- // of the manifest, like plugins and content scripts are not included.
- std::set<PermissionMessage> GetSimplePermissionMessages() const;
+ bool IsComponentOnlyPermission(const ExtensionAPIPermission* api) const;
// Cached images for this extension. This should only be touched on the UI
// thread.
@@ -825,15 +649,8 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// Defines the set of URLs in the extension's web content.
URLPatternSet extent_;
- // The set of host permissions that the extension effectively has access to,
- // which is a merge of host_permissions_ and all of the match patterns in
- // any content scripts the extension has. This is used to determine which
- // URLs have the ability to load an extension's resources via embedded
- // chrome-extension: URLs (see extension_protocols.cc).
- URLPatternSet effective_host_permissions_;
-
- // The set of module-level APIs this extension can use.
- std::set<std::string> api_permissions_;
+ // The set of permissions that the extension effectively has access to.
+ scoped_ptr<ExtensionPermissionSet> permission_set_;
// The icons for the extension.
ExtensionIconSet icons_;
@@ -909,9 +726,6 @@ class Extension : public base::RefCountedThreadSafe<Extension> {
// Whether the extension is a theme.
bool is_theme_;
- // The sites this extension has permission to talk to (using XHR, etc).
- URLPatternList host_permissions_;
-
// The homepage for this extension. Useful if it is not hosted by Google and
// therefore does not have a Gallery URL.
GURL homepage_url_;
diff --git a/chrome/common/extensions/extension_manifests_unittest.cc b/chrome/common/extensions/extension_manifests_unittest.cc
index e2a2d76..7a7122a 100644
--- a/chrome/common/extensions/extension_manifests_unittest.cc
+++ b/chrome/common/extensions/extension_manifests_unittest.cc
@@ -296,8 +296,8 @@ TEST_F(ExtensionManifestTest, UpdateUrls) {
TEST_F(ExtensionManifestTest, OldUnlimitedStoragePermission) {
scoped_refptr<Extension> extension = LoadStrictAndExpectSuccess(
"old_unlimited_storage.json");
- EXPECT_TRUE(extension->HasApiPermission(
- Extension::kUnlimitedStoragePermission));
+ EXPECT_TRUE(extension->HasAPIPermission(
+ ExtensionAPIPermission::kUnlimitedStorage));
}
TEST_F(ExtensionManifestTest, ValidApp) {
@@ -620,14 +620,18 @@ TEST_F(ExtensionManifestTest, AllowUnrecognizedPermissions) {
ListValue *permissions = new ListValue();
manifest->Set(keys::kPermissions, permissions);
- for (size_t i = 0; i < Extension::kNumPermissions; i++) {
- const char* name = Extension::kPermissions[i].name;
+ ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
+ ExtensionAPIPermissionSet api_perms = info->GetAll();
+ for (ExtensionAPIPermissionSet::iterator i = api_perms.begin();
+ i != api_perms.end(); ++i) {
+ ExtensionAPIPermission* permission = info->GetByID(*i);
+ const char* name = permission->name();
StringValue* p = new StringValue(name);
permissions->Clear();
permissions->Append(p);
std::string message_name = base::StringPrintf("permission-%s", name);
- if (name == Extension::kExperimentalPermission) {
+ if (*i == ExtensionAPIPermission::kExperimental) {
// Experimental permission is allowed, but requires this switch.
CommandLine::ForCurrentProcess()->AppendSwitch(
switches::kEnableExperimentalExtensionApis);
diff --git a/chrome/common/extensions/extension_permission_set.cc b/chrome/common/extensions/extension_permission_set.cc
new file mode 100644
index 0000000..d87e9e3
--- /dev/null
+++ b/chrome/common/extensions/extension_permission_set.cc
@@ -0,0 +1,778 @@
+// 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/common/extensions/extension_permission_set.h"
+
+#include <algorithm>
+#include <string>
+
+#include "base/memory/singleton.h"
+#include "base/values.h"
+#include "base/string_number_conversions.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/common/extensions/extension.h"
+#include "chrome/common/extensions/extension_constants.h"
+#include "chrome/common/extensions/extension_l10n_util.h"
+#include "chrome/common/extensions/url_pattern.h"
+#include "chrome/common/extensions/url_pattern_set.h"
+#include "grit/generated_resources.h"
+#include "net/base/registry_controlled_domain.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace {
+
+// Helper for GetDistinctHosts(): com > net > org > everything else.
+bool RcdBetterThan(std::string a, std::string b) {
+ if (a == b)
+ return false;
+ if (a == "com")
+ return true;
+ if (a == "net")
+ return b != "com";
+ if (a == "org")
+ return b != "com" && b != "net";
+ return false;
+}
+
+// Names of API modules that do not require a permission.
+const char kBrowserActionModuleName[] = "browserAction";
+const char kBrowserActionsModuleName[] = "browserActions";
+const char kDevToolsModuleName[] = "devtools";
+const char kExtensionModuleName[] = "extension";
+const char kI18NModuleName[] = "i18n";
+const char kOmniboxModuleName[] = "omnibox";
+const char kPageActionModuleName[] = "pageAction";
+const char kPageActionsModuleName[] = "pageActions";
+const char kTestModuleName[] = "test";
+const char kTypesModuleName[] = "types";
+
+// Names of modules that can be used without listing it in the permissions
+// section of the manifest.
+const char* kNonPermissionModuleNames[] = {
+ kBrowserActionModuleName,
+ kBrowserActionsModuleName,
+ kDevToolsModuleName,
+ kExtensionModuleName,
+ kI18NModuleName,
+ kOmniboxModuleName,
+ kPageActionModuleName,
+ kPageActionsModuleName,
+ kTestModuleName,
+ kTypesModuleName
+};
+const size_t kNumNonPermissionModuleNames =
+ arraysize(kNonPermissionModuleNames);
+
+// Names of functions (within modules requiring permissions) that can be used
+// without asking for the module permission. In other words, functions you can
+// use with no permissions specified.
+const char* kNonPermissionFunctionNames[] = {
+ "tabs.create",
+ "tabs.onRemoved",
+ "tabs.remove",
+ "tabs.update",
+};
+const size_t kNumNonPermissionFunctionNames =
+ arraysize(kNonPermissionFunctionNames);
+
+const char kOldUnlimitedStoragePermission[] = "unlimited_storage";
+const char kWindowsPermission[] = "windows";
+
+void AddPatternsAndRemovePaths(const URLPatternSet& set, URLPatternSet* out) {
+ CHECK(out);
+ const URLPatternList& patterns = set.patterns();
+ for (size_t i = 0; i < patterns.size(); ++i) {
+ URLPattern p = patterns.at(i);
+ p.SetPath("/*");
+ out->AddPattern(p);
+ }
+}
+
+} // namespace
+
+//
+// PermissionMessage
+//
+
+// static
+ExtensionPermissionMessage ExtensionPermissionMessage::CreateFromHostList(
+ const std::vector<std::string>& hosts) {
+ CHECK(hosts.size() > 0);
+ ID message_id;
+ string16 message;
+ switch (hosts.size()) {
+ case 1:
+ message_id = kHosts1;
+ message = l10n_util::GetStringFUTF16(IDS_EXTENSION_PROMPT_WARNING_1_HOST,
+ UTF8ToUTF16(hosts[0]));
+ break;
+ case 2:
+ message_id = kHosts2;
+ message = l10n_util::GetStringFUTF16(IDS_EXTENSION_PROMPT_WARNING_2_HOSTS,
+ UTF8ToUTF16(hosts[0]),
+ UTF8ToUTF16(hosts[1]));
+ break;
+ case 3:
+ message_id = kHosts3;
+ message = l10n_util::GetStringFUTF16(IDS_EXTENSION_PROMPT_WARNING_3_HOSTS,
+ UTF8ToUTF16(hosts[0]),
+ UTF8ToUTF16(hosts[1]),
+ UTF8ToUTF16(hosts[2]));
+ break;
+ default:
+ message_id = kHosts4OrMore;
+ message = l10n_util::GetStringFUTF16(
+ IDS_EXTENSION_PROMPT_WARNING_4_OR_MORE_HOSTS,
+ UTF8ToUTF16(hosts[0]),
+ UTF8ToUTF16(hosts[1]),
+ base::IntToString16(hosts.size() - 2));
+ break;
+ }
+
+ return ExtensionPermissionMessage(message_id, message);
+}
+
+ExtensionPermissionMessage::ExtensionPermissionMessage(
+ ExtensionPermissionMessage::ID id, const string16& message)
+ : id_(id), message_(message) {
+}
+
+ExtensionPermissionMessage::~ExtensionPermissionMessage() {
+}
+
+//
+// ExtensionPermission
+//
+
+ExtensionPermissionMessage ExtensionAPIPermission::GetMessage() const {
+ return ExtensionPermissionMessage(
+ message_id_, l10n_util::GetStringUTF16(l10n_message_id_));
+}
+
+ExtensionAPIPermission::ExtensionAPIPermission(
+ ID id,
+ const char* name,
+ bool is_hosted_app,
+ bool is_component_only,
+ int l10n_message_id,
+ ExtensionPermissionMessage::ID message_id,
+ bool implies_full_access,
+ bool implies_full_url_access)
+ : id_(id),
+ name_(name),
+ implies_full_access_(implies_full_access),
+ implies_full_url_access_(implies_full_url_access),
+ is_hosted_app_(is_hosted_app),
+ is_component_only_(is_component_only),
+ l10n_message_id_(l10n_message_id),
+ message_id_(message_id) {
+}
+
+ExtensionAPIPermission::~ExtensionAPIPermission() {
+}
+
+//
+// ExtensionPermissionsInfo
+//
+
+// static
+ExtensionPermissionsInfo* ExtensionPermissionsInfo::GetInstance() {
+ return Singleton<ExtensionPermissionsInfo>::get();
+}
+
+ExtensionAPIPermission* ExtensionPermissionsInfo::GetByID(
+ ExtensionAPIPermission::ID id) {
+ IDMap::iterator i = id_map_.find(id);
+ return (i == id_map_.end()) ? NULL : i->second;
+}
+
+ExtensionAPIPermission* ExtensionPermissionsInfo::GetByName(std::string name) {
+ NameMap::iterator i = name_map_.find(name);
+ return (i == name_map_.end()) ? NULL : i->second;
+}
+
+ExtensionAPIPermissionSet ExtensionPermissionsInfo::GetAll() {
+ ExtensionAPIPermissionSet permissions;
+ for (IDMap::const_iterator i = id_map_.begin(); i != id_map_.end(); ++i)
+ permissions.insert(i->second->id());
+ return permissions;
+}
+
+ExtensionAPIPermissionSet ExtensionPermissionsInfo::GetAllByName(
+ const std::set<std::string>& permission_names) {
+ ExtensionAPIPermissionSet permissions;
+ for (std::set<std::string>::const_iterator i = permission_names.begin();
+ i != permission_names.end(); ++i) {
+ ExtensionAPIPermission* permission = GetByName(*i);
+ if (permission)
+ permissions.insert(permission->id());
+ }
+ return permissions;
+}
+
+ExtensionPermissionsInfo::~ExtensionPermissionsInfo() {
+ for (IDMap::iterator i = id_map_.begin(); i != id_map_.end(); ++i)
+ delete i->second;
+}
+
+ExtensionPermissionsInfo::ExtensionPermissionsInfo()
+ : hosted_app_permission_count_(0),
+ permission_count_(0) {
+ // Hosted app permissions
+ RegisterHostedAppPermission(
+ ExtensionAPIPermission::kBackground, "background", 0,
+ ExtensionPermissionMessage::kNone);
+ RegisterHostedAppPermission(
+ ExtensionAPIPermission::kClipboardRead, "clipboardRead",
+ IDS_EXTENSION_PROMPT_WARNING_CLIPBOARD,
+ ExtensionPermissionMessage::kClipboard);
+ RegisterHostedAppPermission(
+ ExtensionAPIPermission::kClipboardWrite, "clipboardWrite", 0,
+ ExtensionPermissionMessage::kNone);
+ RegisterHostedAppPermission(
+ ExtensionAPIPermission::kChromePrivate, "chromePrivate", 0,
+ ExtensionPermissionMessage::kNone);
+ RegisterHostedAppPermission(
+ ExtensionAPIPermission::kExperimental, "experimental", 0,
+ ExtensionPermissionMessage::kNone);
+ RegisterHostedAppPermission(
+ ExtensionAPIPermission::kGeolocation, "geolocation",
+ IDS_EXTENSION_PROMPT_WARNING_GEOLOCATION,
+ ExtensionPermissionMessage::kGeolocation);
+ RegisterHostedAppPermission(
+ ExtensionAPIPermission::kNotification, "notifications", 0,
+ ExtensionPermissionMessage::kNone);
+ RegisterHostedAppPermission(
+ ExtensionAPIPermission::kUnlimitedStorage, "unlimitedStorage", 0,
+ ExtensionPermissionMessage::kNone);
+
+ // Hosted app and private permissions.
+ RegisterPermission(
+ ExtensionAPIPermission::kWebstorePrivate, "webstorePrivate", 0,
+ ExtensionPermissionMessage::kNone,
+ true, true, false, false);
+
+ // Extension permissions.
+ RegisterExtensionPermission(
+ ExtensionAPIPermission::kBookmark, "bookmarks",
+ IDS_EXTENSION_PROMPT_WARNING_BOOKMARKS,
+ ExtensionPermissionMessage::kBookmarks);
+ RegisterExtensionPermission(
+ ExtensionAPIPermission::kContentSettings, "contentSettings", 0,
+ ExtensionPermissionMessage::kNone);
+ RegisterExtensionPermission(
+ ExtensionAPIPermission::kContextMenus, "contextMenus", 0,
+ ExtensionPermissionMessage::kNone);
+ RegisterExtensionPermission(
+ ExtensionAPIPermission::kCookie, "cookies", 0,
+ ExtensionPermissionMessage::kNone);
+ RegisterExtensionPermission(
+ ExtensionAPIPermission::kDebugger, "debugger",
+ IDS_EXTENSION_PROMPT_WARNING_DEBUGGER,
+ ExtensionPermissionMessage::kDebugger);
+ RegisterExtensionPermission(
+ ExtensionAPIPermission::kFileBrowserHandler, "fileBrowserHandler", 0,
+ ExtensionPermissionMessage::kNone);
+ RegisterExtensionPermission(
+ ExtensionAPIPermission::kHistory, "history",
+ IDS_EXTENSION_PROMPT_WARNING_BROWSING_HISTORY,
+ ExtensionPermissionMessage::kBrowsingHistory);
+ RegisterExtensionPermission(
+ ExtensionAPIPermission::kIdle, "idle", 0,
+ ExtensionPermissionMessage::kNone);
+ RegisterExtensionPermission(
+ ExtensionAPIPermission::kManagement, "management",
+ IDS_EXTENSION_PROMPT_WARNING_MANAGEMENT,
+ ExtensionPermissionMessage::kManagement);
+ RegisterExtensionPermission(
+ ExtensionAPIPermission::kTab, "tabs",
+ IDS_EXTENSION_PROMPT_WARNING_TABS,
+ ExtensionPermissionMessage::kTabs);
+ RegisterExtensionPermission(
+ ExtensionAPIPermission::kWebSocketProxyPrivate,
+ "webSocketProxyPrivate", 0,
+ ExtensionPermissionMessage::kNone);
+
+ // Private permissions
+ RegisterPrivatePermission(
+ ExtensionAPIPermission::kChromeosInfoPrivate, "chromeosInfoPrivate");
+ RegisterPrivatePermission(
+ ExtensionAPIPermission::kFileBrowserPrivate, "fileBrowserPrivate");
+ RegisterPrivatePermission(
+ ExtensionAPIPermission::kMediaPlayerPrivate, "mediaPlayerPrivate");
+
+ // Full url access permissions.
+ RegisterPermission(
+ ExtensionAPIPermission::kProxy, "proxy", 0,
+ ExtensionPermissionMessage::kNone, false, false, false, true);
+
+ RegisterPermission(
+ ExtensionAPIPermission::kDevtools, "devtools", 0,
+ ExtensionPermissionMessage::kNone, false, false, false, true);
+
+ RegisterPermission(
+ ExtensionAPIPermission::kPlugin, "plugin",
+ IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS,
+ ExtensionPermissionMessage::kFullAccess, false, false, true, true);
+
+ RegisterPermission(
+ ExtensionAPIPermission::kDefault, "default", 0,
+ ExtensionPermissionMessage::kNone, false, false, false, false);
+
+ // Register Aliases
+ RegisterAlias("unlimitedStorage", kOldUnlimitedStoragePermission);
+ RegisterAlias("tabs", kWindowsPermission);
+}
+
+void ExtensionPermissionsInfo::RegisterAlias(
+ const char* name, const char* alias) {
+ CHECK(name_map_.find(name) != name_map_.end());
+ CHECK(name_map_.find(alias) == name_map_.end());
+ name_map_[alias] = name_map_[name];
+}
+
+void ExtensionPermissionsInfo::RegisterExtensionPermission(
+ ExtensionAPIPermission::ID id,
+ const char* name,
+ int l10n_message_id,
+ ExtensionPermissionMessage::ID message_id) {
+ RegisterPermission(id, name, l10n_message_id, message_id,
+ false, false, false, false);
+}
+
+void ExtensionPermissionsInfo::RegisterHostedAppPermission(
+ ExtensionAPIPermission::ID id,
+ const char* name,
+ int l10n_message_id,
+ ExtensionPermissionMessage::ID message_id) {
+ RegisterPermission(id, name, l10n_message_id, message_id,
+ true, false, false, false);
+}
+
+void ExtensionPermissionsInfo::RegisterPrivatePermission(
+ ExtensionAPIPermission::ID id, const char* name) {
+ RegisterPermission(id, name, 0, ExtensionPermissionMessage::kNone,
+ false, true, false, false);
+}
+
+void ExtensionPermissionsInfo::RegisterPermission(
+ ExtensionAPIPermission::ID id,
+ const char* name,
+ int l10n_message_id,
+ ExtensionPermissionMessage::ID message_id,
+ bool is_hosted_app,
+ bool is_component_only,
+ bool implies_full_access,
+ bool implies_full_url_access) {
+ CHECK(id_map_.find(id) == id_map_.end());
+ CHECK(name_map_.find(name) == name_map_.end());
+
+ ExtensionAPIPermission* permission =
+ new ExtensionAPIPermission(id,
+ name,
+ is_hosted_app,
+ is_component_only,
+ l10n_message_id,
+ message_id,
+ implies_full_access,
+ implies_full_url_access);
+ id_map_[id] = permission;
+ name_map_[name] = permission;
+
+ permission_count_++;
+ if (permission->is_hosted_app())
+ hosted_app_permission_count_++;
+}
+
+//
+// ExtensionPermissionSet
+//
+
+ExtensionPermissionSet::ExtensionPermissionSet() {
+}
+
+ExtensionPermissionSet::ExtensionPermissionSet(
+ const Extension* extension,
+ const ExtensionAPIPermissionSet& apis,
+ const URLPatternSet& explicit_hosts)
+ : apis_(apis) {
+ CHECK(extension);
+ AddPatternsAndRemovePaths(explicit_hosts, &explicit_hosts_);
+ InitImplicitExtensionPermissions(extension);
+ InitEffectiveHosts();
+}
+
+ExtensionPermissionSet::ExtensionPermissionSet(
+ const ExtensionAPIPermissionSet& apis,
+ const URLPatternSet& explicit_hosts,
+ const URLPatternSet& scriptable_hosts)
+ : apis_(apis),
+ scriptable_hosts_(scriptable_hosts) {
+ AddPatternsAndRemovePaths(explicit_hosts, &explicit_hosts_);
+ InitEffectiveHosts();
+}
+
+ExtensionPermissionSet::~ExtensionPermissionSet() {
+}
+
+// static
+ExtensionPermissionSet* ExtensionPermissionSet::CreateUnion(
+ const ExtensionPermissionSet* set1,
+ const ExtensionPermissionSet* set2) {
+ ExtensionPermissionSet empty;
+ const ExtensionPermissionSet* set1_safe = (set1 == NULL) ? &empty : set1;
+ const ExtensionPermissionSet* set2_safe = (set2 == NULL) ? &empty : set2;
+
+ ExtensionAPIPermissionSet apis;
+ std::set_union(set1_safe->apis().begin(), set1_safe->apis().end(),
+ set2_safe->apis().begin(), set2_safe->apis().end(),
+ std::insert_iterator<ExtensionAPIPermissionSet>(
+ apis, apis.begin()));
+
+ URLPatternSet explicit_hosts;
+ URLPatternSet scriptable_hosts;
+ URLPatternSet::CreateUnion(set1_safe->explicit_hosts(),
+ set2_safe->explicit_hosts(),
+ &explicit_hosts);
+ URLPatternSet::CreateUnion(set1_safe->scriptable_hosts(),
+ set2_safe->scriptable_hosts(),
+ &scriptable_hosts);
+
+ return new ExtensionPermissionSet(apis, explicit_hosts, scriptable_hosts);
+}
+
+std::set<std::string> ExtensionPermissionSet::GetAPIsAsStrings() const {
+ ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
+ std::set<std::string> apis_str;
+ for (ExtensionAPIPermissionSet::const_iterator i = apis_.begin();
+ i != apis_.end(); ++i) {
+ ExtensionAPIPermission* permission = info->GetByID(*i);
+ if (permission)
+ apis_str.insert(permission->name());
+ }
+ return apis_str;
+}
+
+std::vector<std::string>
+ ExtensionPermissionSet::GetDistinctHostsForDisplay() const {
+ return GetDistinctHosts(effective_hosts_.patterns(), true);
+}
+
+ExtensionPermissionMessages
+ ExtensionPermissionSet::GetPermissionMessages() const {
+ ExtensionPermissionMessages messages;
+
+ if (HasEffectiveFullAccess()) {
+ messages.push_back(ExtensionPermissionMessage(
+ ExtensionPermissionMessage::kFullAccess,
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_FULL_ACCESS)));
+ return messages;
+ }
+
+ if (HasEffectiveAccessToAllHosts()) {
+ messages.push_back(ExtensionPermissionMessage(
+ ExtensionPermissionMessage::kHostsAll,
+ l10n_util::GetStringUTF16(IDS_EXTENSION_PROMPT_WARNING_ALL_HOSTS)));
+ } else {
+ std::vector<std::string> hosts = GetDistinctHostsForDisplay();
+ if (!hosts.empty())
+ messages.push_back(ExtensionPermissionMessage::CreateFromHostList(hosts));
+ }
+
+ std::set<ExtensionPermissionMessage> simple_msgs =
+ GetSimplePermissionMessages();
+ messages.insert(messages.end(), simple_msgs.begin(), simple_msgs.end());
+
+ return messages;
+}
+
+std::vector<string16> ExtensionPermissionSet::GetWarningMessages() const {
+ std::vector<string16> messages;
+ ExtensionPermissionMessages permissions = GetPermissionMessages();
+ for (ExtensionPermissionMessages::const_iterator i = permissions.begin();
+ i != permissions.end(); ++i)
+ messages.push_back(i->message());
+ return messages;
+}
+
+bool ExtensionPermissionSet::IsEmpty() const {
+ // Not default if any host permissions are present.
+ if (!(explicit_hosts().is_empty() && scriptable_hosts().is_empty()))
+ return false;
+
+ // Or if it has no api permissions.
+ return apis().empty();
+}
+
+bool ExtensionPermissionSet::HasAPIPermission(
+ ExtensionAPIPermission::ID permission) const {
+ return apis().find(permission) != apis().end();
+}
+
+bool ExtensionPermissionSet::HasAccessToFunction(
+ const std::string& function_name) const {
+ // TODO(jstritar): Embed this information in each permission and add a method
+ // like GrantsAccess(function_name) to ExtensionAPIPermission. A "default"
+ // permission can then handle the modules and functions that everyone can
+ // access.
+ std::string permission_name = function_name;
+
+ for (size_t i = 0; i < kNumNonPermissionFunctionNames; ++i) {
+ if (permission_name == kNonPermissionFunctionNames[i])
+ return true;
+ }
+
+ // See if this is a function or event name first and strip out the package.
+ // Functions will be of the form package.function
+ // Events will be of the form package/id or package.optional.stuff
+ size_t separator = function_name.find_first_of("./");
+ if (separator != std::string::npos)
+ permission_name = function_name.substr(0, separator);
+
+ ExtensionAPIPermission* permission =
+ ExtensionPermissionsInfo::GetInstance()->GetByName(permission_name);
+ if (permission && apis_.count(permission->id()))
+ return true;
+
+ for (size_t i = 0; i < kNumNonPermissionModuleNames; ++i) {
+ if (permission_name == kNonPermissionModuleNames[i]) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ExtensionPermissionSet::HasExplicitAccessToOrigin(
+ const GURL& origin) const {
+ return explicit_hosts().MatchesURL(origin);
+}
+
+bool ExtensionPermissionSet::HasScriptableAccessToURL(
+ const GURL& origin) const {
+ // We only need to check our host list to verify access. The host list should
+ // already reflect any special rules (such as chrome://favicon, component
+ // all hosts access, etc.).
+ return scriptable_hosts().MatchesURL(origin);
+}
+
+bool ExtensionPermissionSet::HasEffectiveAccessToAllHosts() const {
+ // There are two ways this set can have effective access to all hosts:
+ // 1) it has an <all_urls> URL pattern.
+ // 2) it has a named permission with implied full URL access.
+ const URLPatternList patterns = effective_hosts().patterns();
+ for (URLPatternList::const_iterator host = patterns.begin();
+ host != patterns.end(); ++host) {
+ if (host->match_all_urls() ||
+ (host->match_subdomains() && host->host().empty()))
+ return true;
+ }
+
+ ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
+ for (ExtensionAPIPermissionSet::const_iterator i = apis().begin();
+ i != apis().end(); ++i) {
+ ExtensionAPIPermission* permission = info->GetByID(*i);
+ if (permission->implies_full_url_access())
+ return true;
+ }
+ return false;
+}
+
+bool ExtensionPermissionSet::HasEffectiveAccessToURL(
+ const GURL& url) const {
+ return effective_hosts().MatchesURL(url);
+}
+
+bool ExtensionPermissionSet::HasEffectiveFullAccess() const {
+ ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
+ for (ExtensionAPIPermissionSet::const_iterator i = apis().begin();
+ i != apis().end(); ++i) {
+ ExtensionAPIPermission* permission = info->GetByID(*i);
+ if (permission->implies_full_access())
+ return true;
+ }
+ return false;
+}
+
+bool ExtensionPermissionSet::HasPrivatePermissions() const {
+ ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
+ for (ExtensionAPIPermissionSet::const_iterator i = apis_.begin();
+ i != apis_.end(); ++i) {
+ ExtensionAPIPermission* permission = info->GetByID(*i);
+ if (permission && permission->is_component_only())
+ return true;
+ }
+ return false;
+}
+
+bool ExtensionPermissionSet::HasLessPrivilegesThan(
+ const ExtensionPermissionSet* permissions) const {
+ // Things can't get worse than native code access.
+ if (HasEffectiveFullAccess())
+ return false;
+
+ // Otherwise, it's a privilege increase if the new one has full access.
+ if (permissions->HasEffectiveFullAccess())
+ return true;
+
+ if (HasLessHostPrivilegesThan(permissions))
+ return true;
+
+ if (HasLessAPIPrivilegesThan(permissions))
+ return true;
+
+ return false;
+}
+
+// static
+std::vector<std::string> ExtensionPermissionSet::GetDistinctHosts(
+ const URLPatternList& host_patterns, bool include_rcd) {
+ // Use a vector to preserve order (also faster than a map on small sets).
+ // Each item is a host split into two parts: host without RCDs and
+ // current best RCD.
+ typedef std::vector<std::pair<std::string, std::string> > HostVector;
+ HostVector hosts_best_rcd;
+ for (size_t i = 0; i < host_patterns.size(); ++i) {
+ std::string host = host_patterns[i].host();
+
+ // Add the subdomain wildcard back to the host, if necessary.
+ if (host_patterns[i].match_subdomains())
+ host = "*." + host;
+
+ // If the host has an RCD, split it off so we can detect duplicates.
+ std::string rcd;
+ size_t reg_len = net::RegistryControlledDomainService::GetRegistryLength(
+ host, false);
+ if (reg_len && reg_len != std::string::npos) {
+ if (include_rcd) // else leave rcd empty
+ rcd = host.substr(host.size() - reg_len);
+ host = host.substr(0, host.size() - reg_len);
+ }
+
+ // Check if we've already seen this host.
+ HostVector::iterator it = hosts_best_rcd.begin();
+ for (; it != hosts_best_rcd.end(); ++it) {
+ if (it->first == host)
+ break;
+ }
+ // If this host was found, replace the RCD if this one is better.
+ if (it != hosts_best_rcd.end()) {
+ if (include_rcd && RcdBetterThan(rcd, it->second))
+ it->second = rcd;
+ } else { // Previously unseen host, append it.
+ hosts_best_rcd.push_back(std::make_pair(host, rcd));
+ }
+ }
+
+ // Build up the final vector by concatenating hosts and RCDs.
+ std::vector<std::string> distinct_hosts;
+ for (HostVector::iterator it = hosts_best_rcd.begin();
+ it != hosts_best_rcd.end(); ++it)
+ distinct_hosts.push_back(it->first + it->second);
+ return distinct_hosts;
+}
+
+void ExtensionPermissionSet::InitEffectiveHosts() {
+ effective_hosts_.ClearPatterns();
+
+ if (HasEffectiveAccessToAllHosts()) {
+ URLPattern all_urls(URLPattern::SCHEME_ALL);
+ all_urls.set_match_all_urls(true);
+ effective_hosts_.AddPattern(all_urls);
+ return;
+ }
+
+ URLPatternSet::CreateUnion(
+ explicit_hosts(), scriptable_hosts(), &effective_hosts_);
+}
+
+void ExtensionPermissionSet::InitImplicitExtensionPermissions(
+ const Extension* extension) {
+ // Add the implied permissions.
+ if (!extension->plugins().empty())
+ apis_.insert(ExtensionAPIPermission::kPlugin);
+
+ if (!extension->devtools_url().is_empty())
+ apis_.insert(ExtensionAPIPermission::kDevtools);
+
+ // Add the scriptable hosts.
+ for (UserScriptList::const_iterator content_script =
+ extension->content_scripts().begin();
+ content_script != extension->content_scripts().end(); ++content_script) {
+ URLPatternList::const_iterator pattern =
+ content_script->url_patterns().begin();
+ for (; pattern != content_script->url_patterns().end(); ++pattern)
+ scriptable_hosts_.AddPattern(*pattern);
+ }
+}
+
+std::set<ExtensionPermissionMessage>
+ ExtensionPermissionSet::GetSimplePermissionMessages() const {
+ std::set<ExtensionPermissionMessage> messages;
+ ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
+ for (ExtensionAPIPermissionSet::const_iterator i = apis_.begin();
+ i != apis_.end(); ++i) {
+ DCHECK_GT(ExtensionPermissionMessage::kNone,
+ ExtensionPermissionMessage::kUnknown);
+ ExtensionAPIPermission* perm = info->GetByID(*i);
+ if (perm && perm->message_id() > ExtensionPermissionMessage::kNone)
+ messages.insert(perm->GetMessage());
+ }
+ return messages;
+}
+
+bool ExtensionPermissionSet::HasLessAPIPrivilegesThan(
+ const ExtensionPermissionSet* permissions) const {
+ if (permissions == NULL)
+ return false;
+
+ ExtensionAPIPermissionSet new_apis = permissions->apis_;
+ ExtensionAPIPermissionSet new_apis_only;
+ std::set_difference(new_apis.begin(), new_apis.end(),
+ apis_.begin(), apis_.end(),
+ std::inserter(new_apis_only, new_apis_only.begin()));
+
+ ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
+
+ // Ignore API permissions that don't require user approval when deciding if
+ // an extension has increased its privileges.
+ for (ExtensionAPIPermissionSet::iterator i = new_apis_only.begin();
+ i != new_apis_only.end(); ++i) {
+ ExtensionAPIPermission* perm = info->GetByID(*i);
+ if (perm && perm->message_id() > ExtensionPermissionMessage::kNone)
+ return true;
+ }
+ return false;
+}
+
+bool ExtensionPermissionSet::HasLessHostPrivilegesThan(
+ const ExtensionPermissionSet* permissions) const {
+ // If this permission set can access any host, then it can't be elevated.
+ if (HasEffectiveAccessToAllHosts())
+ return false;
+
+ // Likewise, if the other permission set has full host access, then it must be
+ // a privilege increase.
+ if (permissions->HasEffectiveAccessToAllHosts())
+ return true;
+
+ const URLPatternList old_list = effective_hosts().patterns();
+ const URLPatternList new_list = permissions->effective_hosts().patterns();
+
+ // TODO(jstritar): This is overly conservative with respect to subdomains.
+ // For example, going from *.google.com to www.google.com will be
+ // considered an elevation, even though it is not (http://crbug.com/65337).
+ std::vector<std::string> new_hosts = GetDistinctHosts(new_list, false);
+ std::vector<std::string> old_hosts = GetDistinctHosts(old_list, false);
+
+ std::set<std::string> old_hosts_set(old_hosts.begin(), old_hosts.end());
+ std::set<std::string> new_hosts_set(new_hosts.begin(), new_hosts.end());
+ std::set<std::string> new_hosts_only;
+
+ std::set_difference(new_hosts_set.begin(), new_hosts_set.end(),
+ old_hosts_set.begin(), old_hosts_set.end(),
+ std::inserter(new_hosts_only, new_hosts_only.begin()));
+
+ return !new_hosts_only.empty();
+}
diff --git a/chrome/common/extensions/extension_permission_set.h b/chrome/common/extensions/extension_permission_set.h
new file mode 100644
index 0000000..14f58a90
--- /dev/null
+++ b/chrome/common/extensions/extension_permission_set.h
@@ -0,0 +1,389 @@
+// 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_COMMON_EXTENSIONS_EXTENSION_PERMISSION_SET_H_
+#define CHROME_COMMON_EXTENSIONS_EXTENSION_PERMISSION_SET_H_
+#pragma once
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/singleton.h"
+#include "base/scoped_ptr.h"
+#include "base/string16.h"
+#include "chrome/common/extensions/url_pattern_set.h"
+
+class DictionaryValue;
+class Extension;
+class ExtensionPrefs;
+class ListValue;
+
+// When prompting the user to install or approve permissions, we display
+// messages describing the effects of the permissions rather than listing the
+// permissions themselves. Each ExtensionPermissionMessage represents one of the
+// messages shown to the user.
+class ExtensionPermissionMessage {
+ public:
+ // Do not reorder this enumeration. If you need to add a new enum, add it just
+ // prior to kEnumBoundary.
+ enum ID {
+ kUnknown,
+ kNone,
+ kBookmarks,
+ kGeolocation,
+ kBrowsingHistory,
+ kTabs,
+ kManagement,
+ kDebugger,
+ kHosts1,
+ kHosts2,
+ kHosts3,
+ kHosts4OrMore,
+ kHostsAll,
+ kFullAccess,
+ kClipboard,
+ kEnumBoundary
+ };
+
+ // Creates the corresponding permission message for a list of hosts. This is
+ // simply a convenience method around the constructor, since the messages
+ // change depending on what hosts are present.
+ static ExtensionPermissionMessage CreateFromHostList(
+ const std::vector<std::string>& hosts);
+
+ // Creates the corresponding permission message.
+ ExtensionPermissionMessage(ID id, const string16& message);
+ ~ExtensionPermissionMessage();
+
+ // Gets the id of the permission message, which can be used in UMA
+ // histograms.
+ ID id() const { return id_; }
+
+ // Gets a localized message describing this permission. Please note that
+ // the message will be empty for message types TYPE_NONE and TYPE_UNKNOWN.
+ const string16& message() const { return message_; }
+
+ // Comparator to work with std::set.
+ bool operator<(const ExtensionPermissionMessage& that) const {
+ return id_ < that.id_;
+ }
+
+ private:
+ ID id_;
+ string16 message_;
+};
+
+typedef std::vector<ExtensionPermissionMessage> ExtensionPermissionMessages;
+
+// The ExtensionAPIPermission is an immutable class that describes a single
+// named permission (API permission).
+class ExtensionAPIPermission {
+ public:
+ enum ID {
+ // Error codes.
+ kInvalid = -2,
+ kUnknown = -1,
+
+ // Default permission that every extension has implicity.
+ kDefault,
+
+ // Real permissions.
+ kBackground,
+ kBookmark,
+ kClipboardRead,
+ kClipboardWrite,
+ kContentSettings,
+ kContextMenus,
+ kCookie,
+ kChromePrivate,
+ kChromeosInfoPrivate,
+ kDebugger,
+ kExperimental,
+ kFileBrowserHandler,
+ kFileBrowserPrivate,
+ kGeolocation,
+ kHistory,
+ kIdle,
+ kManagement,
+ kMediaPlayerPrivate,
+ kNotification,
+ kProxy,
+ kTab,
+ kUnlimitedStorage,
+ kWebSocketProxyPrivate,
+ kWebstorePrivate,
+ kDevtools,
+ kPlugin,
+ kEnumBoundary
+ };
+
+ typedef std::set<ID> IDSet;
+
+ ~ExtensionAPIPermission();
+
+ // Returns the localized permission message associated with this api.
+ ExtensionPermissionMessage GetMessage() const;
+
+ ID id() const { return id_; }
+
+ // Returns the message id associated with this permission.
+ ExtensionPermissionMessage::ID message_id() const {
+ return message_id_;
+ }
+
+ // Returns the name of this permission.
+ const char* name() const { return name_; }
+
+ // Returns true if this permission implies full access (e.g., native code).
+ bool implies_full_access() const { return implies_full_access_; }
+
+ // Returns true if this permission implies full URL access.
+ bool implies_full_url_access() const { return implies_full_url_access_; }
+
+ // Returns true if this permission can be accessed by hosted apps.
+ bool is_hosted_app() const { return is_hosted_app_; }
+
+ // Returns true if this permission can only be acquired by COMPONENT
+ // extensions.
+ bool is_component_only() const { return is_component_only_; }
+
+ private:
+ // Instances should only be constructed from within ExtensionPermissionsInfo.
+ friend class ExtensionPermissionsInfo;
+
+ explicit ExtensionAPIPermission(
+ ID id,
+ const char* name,
+ bool is_hosted_app,
+ bool is_component_only,
+ int l10n_message_id,
+ ExtensionPermissionMessage::ID message_id,
+ bool implies_full_access,
+ bool implies_full_url_access);
+
+ ID id_;
+ const char* name_;
+ bool implies_full_access_;
+ bool implies_full_url_access_;
+ bool is_hosted_app_;
+ bool is_component_only_;
+ int l10n_message_id_;
+ ExtensionPermissionMessage::ID message_id_;
+};
+
+typedef std::set<ExtensionAPIPermission::ID> ExtensionAPIPermissionSet;
+
+// Singleton that holds the extension permission instances and provides static
+// methods for accessing them.
+class ExtensionPermissionsInfo {
+ public:
+ // Returns a pointer to the singleton instance.
+ static ExtensionPermissionsInfo* GetInstance();
+
+ // Returns the permission with the given |id|, and NULL if it doesn't exist.
+ ExtensionAPIPermission* GetByID(ExtensionAPIPermission::ID id);
+
+ // Returns the permission with the given |name|, and NULL if none
+ // exists.
+ ExtensionAPIPermission* GetByName(std::string name);
+
+ // Returns a set containing all valid api permission ids.
+ ExtensionAPIPermissionSet GetAll();
+
+ // Converts all the permission names in |permission_names| to permission ids.
+ ExtensionAPIPermissionSet GetAllByName(
+ const std::set<std::string>& permission_names);
+
+ // Gets the total number of API permissions available to hosted apps.
+ size_t get_hosted_app_permission_count() {
+ return hosted_app_permission_count_;
+ }
+
+ // Gets the total number of API permissions.
+ size_t get_permission_count() { return permission_count_; }
+
+ private:
+ ~ExtensionPermissionsInfo();
+ ExtensionPermissionsInfo();
+
+ // Registers an |alias| for a given permission |name|.
+ void RegisterAlias(const char* name, const char* alias);
+
+ // Registers a standard extension permission.
+ void RegisterExtensionPermission(
+ ExtensionAPIPermission::ID id,
+ const char* name,
+ int l10n_message_id,
+ ExtensionPermissionMessage::ID message_id);
+
+ // Registers a permission that can be accessed by hosted apps.
+ void RegisterHostedAppPermission(
+ ExtensionAPIPermission::ID id,
+ const char* name,
+ int l10n_message_id,
+ ExtensionPermissionMessage::ID message_id);
+
+ // Registers a permission accessible only by COMPONENT extensions.
+ void RegisterPrivatePermission(
+ ExtensionAPIPermission::ID id,
+ const char* name);
+
+ // Registers a permission with a custom set of attributes not satisfied
+ // by the other registration functions.
+ void RegisterPermission(
+ ExtensionAPIPermission::ID id,
+ const char* name,
+ int l10n_message_id,
+ ExtensionPermissionMessage::ID message_id,
+ bool is_hosted_app,
+ bool is_component_only,
+ bool implies_full_access,
+ bool implies_full_url_access);
+
+ // Maps permission ids to permissions.
+ typedef std::map<ExtensionAPIPermission::ID, ExtensionAPIPermission*> IDMap;
+
+ // Maps names and aliases to permissions.
+ typedef std::map<std::string, ExtensionAPIPermission*> NameMap;
+
+ IDMap id_map_;
+ NameMap name_map_;
+
+ size_t hosted_app_permission_count_;
+ size_t permission_count_;
+
+ friend struct DefaultSingletonTraits<ExtensionPermissionsInfo>;
+ DISALLOW_COPY_AND_ASSIGN(ExtensionPermissionsInfo);
+};
+
+// The ExtensionPermissionSet is an immutable class that encapsulates an
+// extension's permissions. The class exposes set operations for combining and
+// manipulating the permissions.
+class ExtensionPermissionSet {
+ public:
+ // Creates an empty permission set (e.g. default permissions).
+ ExtensionPermissionSet();
+
+ // Creates a new permission set based on the |extension| manifest data, and
+ // the api and host permissions (|apis| and |hosts|). The effective hosts
+ // of the newly created permission set will be inferred from the |extension|
+ // manifest, |apis| and |hosts|.
+ ExtensionPermissionSet(const Extension* extension,
+ const ExtensionAPIPermissionSet& apis,
+ const URLPatternSet& explicit_hosts);
+
+ // Creates a new permission set based on the specified data.
+ ExtensionPermissionSet(const ExtensionAPIPermissionSet& apis,
+ const URLPatternSet& explicit_hosts,
+ const URLPatternSet& scriptable_hosts);
+
+ ~ExtensionPermissionSet();
+
+ // Creates a new permission set equal to the union of |set1| and |set2|.
+ // Passes ownership of the new set to the caller.
+ static ExtensionPermissionSet* CreateUnion(
+ const ExtensionPermissionSet* set1, const ExtensionPermissionSet* set2);
+
+ // Gets the API permissions in this set as a set of strings.
+ std::set<std::string> GetAPIsAsStrings() const;
+
+ // Gets a list of the distinct hosts for displaying to the user.
+ // NOTE: do not use this for comparing permissions, since this disgards some
+ // information.
+ std::vector<std::string> GetDistinctHostsForDisplay() const;
+
+ // Gets the localized permission messages that represent this set.
+ ExtensionPermissionMessages GetPermissionMessages() const;
+
+ // Gets the localized permission messages that represent this set (represented
+ // as strings).
+ std::vector<string16> GetWarningMessages() const;
+
+ // Returns true if this is an empty set (e.g., the default permission set).
+ bool IsEmpty() const;
+
+ // Returns true if the set has the specified API permission.
+ bool HasAPIPermission(ExtensionAPIPermission::ID permission) const;
+
+ // Returns true if the permissions in this set grant access to the specified
+ // |function_name|.
+ bool HasAccessToFunction(const std::string& function_name) const;
+
+ // Returns true if this includes permission to access |origin|.
+ bool HasExplicitAccessToOrigin(const GURL& origin) const;
+
+ // Returns true if this permission set includes access to script |url|.
+ bool HasScriptableAccessToURL(const GURL& url) const;
+
+ // Returns true if this permission set includes effective access to all
+ // origins.
+ bool HasEffectiveAccessToAllHosts() const;
+
+ // Returns true if this permission set includes effective access to |url|.
+ bool HasEffectiveAccessToURL(const GURL& url) const;
+
+ // Returns ture if this permission set effectively represents full access
+ // (e.g. native code).
+ bool HasEffectiveFullAccess() const;
+
+ // Returns true if this permission set includes permissions that are
+ // restricted to internal extensions.
+ bool HasPrivatePermissions() const;
+
+ // Returns true if |permissions| has a greater privilege level than this
+ // permission set (e.g., this permission set has less permissions).
+ bool HasLessPrivilegesThan(const ExtensionPermissionSet* permissions) const;
+
+ const ExtensionAPIPermissionSet& apis() const { return apis_; }
+
+ const URLPatternSet& effective_hosts() const { return effective_hosts_; }
+
+ const URLPatternSet& explicit_hosts() const { return explicit_hosts_; }
+
+ const URLPatternSet& scriptable_hosts() const { return scriptable_hosts_; }
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(ExtensionPermissionSetTest,
+ HasLessHostPrivilegesThan);
+
+ static std::vector<std::string> GetDistinctHosts(
+ const URLPatternList& host_patterns, bool include_rcd);
+
+ // Initializes the set based on |extension|'s manifest data.
+ void InitImplicitExtensionPermissions(const Extension* extension);
+
+ // Initializes the effective host permission based on the data in this set.
+ void InitEffectiveHosts();
+
+ // Gets the permission messages for the API permissions.
+ std::set<ExtensionPermissionMessage> GetSimplePermissionMessages() const;
+
+ // Returns true if |permissions| has an elevated API privilege level than
+ // this set.
+ bool HasLessAPIPrivilegesThan(
+ const ExtensionPermissionSet* permissions) const;
+
+ // Returns true if |permissions| has more host permissions compared to this
+ // set.
+ bool HasLessHostPrivilegesThan(
+ const ExtensionPermissionSet* permissions) const;
+
+ // The api list is used when deciding if an extension can access certain
+ // extension APIs and features.
+ ExtensionAPIPermissionSet apis_;
+
+ // The list of hosts that can be accessed directly from the extension.
+ URLPatternSet explicit_hosts_;
+
+ // The list of hosts that can be scripted by content scripts.
+ URLPatternSet scriptable_hosts_;
+
+ // The list of hosts this effectively grants access to.
+ URLPatternSet effective_hosts_;
+};
+
+#endif // CHROME_COMMON_EXTENSIONS_EXTENSION_PERMISSION_SET_H_
diff --git a/chrome/common/extensions/extension_permission_set_unittest.cc b/chrome/common/extensions/extension_permission_set_unittest.cc
new file mode 100644
index 0000000..9cfa698
--- /dev/null
+++ b/chrome/common/extensions/extension_permission_set_unittest.cc
@@ -0,0 +1,941 @@
+// 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/common/extensions/extension_permission_set.h"
+
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/extensions/extension.h"
+#include "content/common/json_value_serializer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+static scoped_refptr<Extension> LoadManifest(const std::string& dir,
+ const std::string& test_file,
+ int extra_flags) {
+ FilePath path;
+ PathService::Get(chrome::DIR_TEST_DATA, &path);
+ path = path.AppendASCII("extensions")
+ .AppendASCII(dir)
+ .AppendASCII(test_file);
+
+ JSONFileValueSerializer serializer(path);
+ std::string error;
+ scoped_ptr<Value> result(serializer.Deserialize(NULL, &error));
+ if (!result.get()) {
+ EXPECT_EQ("", error);
+ return NULL;
+ }
+
+ scoped_refptr<Extension> extension = Extension::Create(
+ path.DirName(), Extension::INVALID,
+ *static_cast<DictionaryValue*>(result.get()),
+ Extension::STRICT_ERROR_CHECKS | extra_flags, &error);
+ EXPECT_TRUE(extension) << error;
+ return extension;
+}
+
+static scoped_refptr<Extension> LoadManifest(const std::string& dir,
+ const std::string& test_file) {
+ return LoadManifest(dir, test_file, Extension::NO_FLAGS);
+}
+
+void CompareLists(const std::vector<std::string>& expected,
+ const std::vector<std::string>& actual) {
+ ASSERT_EQ(expected.size(), actual.size());
+
+ for (size_t i = 0; i < expected.size(); ++i) {
+ EXPECT_EQ(expected[i], actual[i]);
+ }
+}
+
+static void AddPattern(URLPatternSet* extent, const std::string& pattern) {
+ int schemes = URLPattern::SCHEME_ALL;
+ extent->AddPattern(URLPattern(schemes, pattern));
+}
+
+static void AssertEqualExtents(const URLPatternSet& extent1,
+ const URLPatternSet& extent2) {
+ URLPatternList patterns1 = extent1.patterns();
+ URLPatternList patterns2 = extent2.patterns();
+ std::set<std::string> strings1;
+ EXPECT_EQ(patterns1.size(), patterns2.size());
+
+ for (size_t i = 0; i < patterns1.size(); ++i)
+ strings1.insert(patterns1.at(i).GetAsString());
+
+ std::set<std::string> strings2;
+ for (size_t i = 0; i < patterns2.size(); ++i)
+ strings2.insert(patterns2.at(i).GetAsString());
+
+ EXPECT_EQ(strings1, strings2);
+}
+
+} // namespace
+
+class ExtensionAPIPermissionTest : public testing::Test {
+};
+
+class ExtensionPermissionSetTest : public testing::Test {
+};
+
+
+// Tests GetByID.
+TEST(ExtensionPermissionsInfoTest, GetByID) {
+ ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
+ ExtensionAPIPermissionSet ids = info->GetAll();
+ for (ExtensionAPIPermissionSet::iterator i = ids.begin();
+ i != ids.end(); ++i) {
+ EXPECT_EQ(*i, info->GetByID(*i)->id());
+ }
+}
+
+// Tests that GetByName works with normal permission names and aliases.
+TEST(ExtensionPermissionsInfoTest, GetByName) {
+ ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
+ EXPECT_EQ(ExtensionAPIPermission::kTab, info->GetByName("tabs")->id());
+ EXPECT_EQ(ExtensionAPIPermission::kManagement,
+ info->GetByName("management")->id());
+ EXPECT_FALSE(info->GetByName("alsdkfjasldkfj"));
+}
+
+TEST(ExtensionPermissionsInfoTest, GetAll) {
+ size_t count = 0;
+ ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
+ ExtensionAPIPermissionSet apis = info->GetAll();
+ for (ExtensionAPIPermissionSet::iterator api = apis.begin();
+ api != apis.end(); ++api) {
+ // Make sure only the valid permission IDs get returned.
+ EXPECT_NE(ExtensionAPIPermission::kInvalid, *api);
+ EXPECT_NE(ExtensionAPIPermission::kUnknown, *api);
+ count++;
+ }
+ EXPECT_EQ(count, info->get_permission_count());
+}
+
+TEST(ExtensionPermissionInfoTest, GetAllByName) {
+ std::set<std::string> names;
+ names.insert("background");
+ names.insert("management");
+
+ // This is an alias of kTab
+ names.insert("windows");
+
+ // This unknown name should get dropped.
+ names.insert("sdlkfjasdlkfj");
+
+ ExtensionAPIPermissionSet expected;
+ expected.insert(ExtensionAPIPermission::kBackground);
+ expected.insert(ExtensionAPIPermission::kManagement);
+ expected.insert(ExtensionAPIPermission::kTab);
+
+ EXPECT_EQ(expected,
+ ExtensionPermissionsInfo::GetInstance()->GetAllByName(names));
+}
+
+// Tests that the aliases are properly mapped.
+TEST(ExtensionAPIPermissionTest, Aliases) {
+ ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
+ // tabs: tabs, windows
+ std::string tabs_name = "tabs";
+ EXPECT_EQ(tabs_name, info->GetByID(ExtensionAPIPermission::kTab)->name());
+ EXPECT_EQ(ExtensionAPIPermission::kTab, info->GetByName("tabs")->id());
+ EXPECT_EQ(ExtensionAPIPermission::kTab, info->GetByName("windows")->id());
+
+ // unlimitedStorage: unlimitedStorage, unlimited_storage
+ std::string storage_name = "unlimitedStorage";
+ EXPECT_EQ(storage_name, info->GetByID(
+ ExtensionAPIPermission::kUnlimitedStorage)->name());
+ EXPECT_EQ(ExtensionAPIPermission::kUnlimitedStorage,
+ info->GetByName("unlimitedStorage")->id());
+ EXPECT_EQ(ExtensionAPIPermission::kUnlimitedStorage,
+ info->GetByName("unlimited_storage")->id());
+}
+
+TEST(ExtensionAPIPermissionTest, HostedAppPermissions) {
+ ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
+ ExtensionAPIPermissionSet hosted_perms;
+ hosted_perms.insert(ExtensionAPIPermission::kBackground);
+ hosted_perms.insert(ExtensionAPIPermission::kClipboardRead);
+ hosted_perms.insert(ExtensionAPIPermission::kClipboardWrite);
+ hosted_perms.insert(ExtensionAPIPermission::kChromePrivate);
+ hosted_perms.insert(ExtensionAPIPermission::kExperimental);
+ hosted_perms.insert(ExtensionAPIPermission::kGeolocation);
+ hosted_perms.insert(ExtensionAPIPermission::kNotification);
+ hosted_perms.insert(ExtensionAPIPermission::kUnlimitedStorage);
+ hosted_perms.insert(ExtensionAPIPermission::kWebstorePrivate);
+
+ ExtensionAPIPermissionSet perms = info->GetAll();
+ size_t count = 0;
+ for (ExtensionAPIPermissionSet::iterator i = perms.begin();
+ i != perms.end(); ++i) {
+ count += hosted_perms.count(*i);
+ EXPECT_EQ(hosted_perms.count(*i) > 0, info->GetByID(*i)->is_hosted_app());
+ }
+
+ EXPECT_EQ(9u, count);
+ EXPECT_EQ(9u, info->get_hosted_app_permission_count());
+}
+
+TEST(ExtensionAPIPermissionTest, ComponentOnlyPermissions) {
+ ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
+ ExtensionAPIPermissionSet private_perms;
+ private_perms.insert(ExtensionAPIPermission::kChromeosInfoPrivate);
+ private_perms.insert(ExtensionAPIPermission::kFileBrowserPrivate);
+ private_perms.insert(ExtensionAPIPermission::kMediaPlayerPrivate);
+ private_perms.insert(ExtensionAPIPermission::kWebstorePrivate);
+
+ ExtensionAPIPermissionSet perms = info->GetAll();
+ int count = 0;
+ for (ExtensionAPIPermissionSet::iterator i = perms.begin();
+ i != perms.end(); ++i) {
+ count += private_perms.count(*i);
+ EXPECT_EQ(private_perms.count(*i) > 0,
+ info->GetByID(*i)->is_component_only());
+ }
+
+ EXPECT_EQ(4, count);
+}
+
+TEST(ExtensionPermissionSetTest, EffectiveHostPermissions) {
+ scoped_refptr<Extension> extension;
+ const ExtensionPermissionSet* permissions = NULL;
+
+ extension = LoadManifest("effective_host_permissions", "empty.json");
+ permissions = extension->permission_set();
+ EXPECT_EQ(0u, extension->GetEffectiveHostPermissions().patterns().size());
+ EXPECT_FALSE(permissions->HasEffectiveAccessToURL(
+ GURL("http://www.google.com")));
+ EXPECT_FALSE(permissions->HasEffectiveAccessToAllHosts());
+
+ extension = LoadManifest("effective_host_permissions", "one_host.json");
+ permissions = extension->permission_set();
+ EXPECT_TRUE(permissions->HasEffectiveAccessToURL(
+ GURL("http://www.google.com")));
+ EXPECT_FALSE(permissions->HasEffectiveAccessToURL(
+ GURL("https://www.google.com")));
+ EXPECT_FALSE(permissions->HasEffectiveAccessToAllHosts());
+
+ extension = LoadManifest("effective_host_permissions",
+ "one_host_wildcard.json");
+ permissions = extension->permission_set();
+ EXPECT_TRUE(permissions->HasEffectiveAccessToURL(GURL("http://google.com")));
+ EXPECT_TRUE(permissions->HasEffectiveAccessToURL(
+ GURL("http://foo.google.com")));
+ EXPECT_FALSE(permissions->HasEffectiveAccessToAllHosts());
+
+ extension = LoadManifest("effective_host_permissions", "two_hosts.json");
+ permissions = extension->permission_set();
+ EXPECT_TRUE(permissions->HasEffectiveAccessToURL(
+ GURL("http://www.google.com")));
+ EXPECT_TRUE(permissions->HasEffectiveAccessToURL(
+ GURL("http://www.reddit.com")));
+ EXPECT_FALSE(permissions->HasEffectiveAccessToAllHosts());
+
+ extension = LoadManifest("effective_host_permissions",
+ "https_not_considered.json");
+ permissions = extension->permission_set();
+ EXPECT_TRUE(permissions->HasEffectiveAccessToURL(GURL("http://google.com")));
+ EXPECT_TRUE(permissions->HasEffectiveAccessToURL(GURL("https://google.com")));
+ EXPECT_FALSE(permissions->HasEffectiveAccessToAllHosts());
+
+ extension = LoadManifest("effective_host_permissions",
+ "two_content_scripts.json");
+ permissions = extension->permission_set();
+ EXPECT_TRUE(permissions->HasEffectiveAccessToURL(GURL("http://google.com")));
+ EXPECT_TRUE(permissions->HasEffectiveAccessToURL(
+ GURL("http://www.reddit.com")));
+ EXPECT_TRUE(permissions->HasEffectiveAccessToURL(
+ GURL("http://news.ycombinator.com")));
+ EXPECT_FALSE(permissions->HasEffectiveAccessToAllHosts());
+
+ extension = LoadManifest("effective_host_permissions", "all_hosts.json");
+ permissions = extension->permission_set();
+ EXPECT_TRUE(permissions->HasEffectiveAccessToURL(GURL("http://test/")));
+ EXPECT_FALSE(permissions->HasEffectiveAccessToURL(GURL("https://test/")));
+ EXPECT_TRUE(
+ permissions->HasEffectiveAccessToURL(GURL("http://www.google.com")));
+ EXPECT_TRUE(permissions->HasEffectiveAccessToAllHosts());
+
+ extension = LoadManifest("effective_host_permissions", "all_hosts2.json");
+ permissions = extension->permission_set();
+ EXPECT_TRUE(permissions->HasEffectiveAccessToURL(GURL("http://test/")));
+ EXPECT_TRUE(
+ permissions->HasEffectiveAccessToURL(GURL("http://www.google.com")));
+ EXPECT_TRUE(permissions->HasEffectiveAccessToAllHosts());
+
+ extension = LoadManifest("effective_host_permissions", "all_hosts3.json");
+ permissions = extension->permission_set();
+ EXPECT_FALSE(permissions->HasEffectiveAccessToURL(GURL("http://test/")));
+ EXPECT_TRUE(permissions->HasEffectiveAccessToURL(GURL("https://test/")));
+ EXPECT_TRUE(
+ permissions->HasEffectiveAccessToURL(GURL("http://www.google.com")));
+ EXPECT_TRUE(permissions->HasEffectiveAccessToAllHosts());
+}
+
+TEST(ExtensionPermissionSetTest, ExplicitAccessToOrigin) {
+ ExtensionAPIPermissionSet apis;
+ URLPatternSet explicit_hosts;
+ URLPatternSet scriptable_hosts;
+
+ AddPattern(&explicit_hosts, "http://*.google.com/*");
+ // The explicit host paths should get set to /*.
+ AddPattern(&explicit_hosts, "http://www.example.com/a/particular/path/*");
+
+ ExtensionPermissionSet perm_set(apis, explicit_hosts, scriptable_hosts);
+ ASSERT_TRUE(perm_set.HasExplicitAccessToOrigin(
+ GURL("http://www.google.com/")));
+ ASSERT_TRUE(perm_set.HasExplicitAccessToOrigin(
+ GURL("http://test.google.com/")));
+ ASSERT_TRUE(perm_set.HasExplicitAccessToOrigin(
+ GURL("http://www.example.com")));
+ ASSERT_TRUE(perm_set.HasEffectiveAccessToURL(
+ GURL("http://www.example.com")));
+ ASSERT_FALSE(perm_set.HasExplicitAccessToOrigin(
+ GURL("http://test.example.com")));
+}
+
+TEST(ExtensionPermissionSetTest, CreateUnion) {
+ ExtensionAPIPermissionSet apis1;
+ ExtensionAPIPermissionSet apis2;
+ ExtensionAPIPermissionSet expected_apis;
+
+ URLPatternSet explicit_hosts1;
+ URLPatternSet explicit_hosts2;
+ URLPatternSet expected_explicit_hosts;
+
+ URLPatternSet scriptable_hosts1;
+ URLPatternSet scriptable_hosts2;
+ URLPatternSet expected_scriptable_hosts;
+
+ URLPatternSet effective_hosts;
+
+ scoped_ptr<ExtensionPermissionSet> set1;
+ scoped_ptr<ExtensionPermissionSet> set2;
+ scoped_ptr<ExtensionPermissionSet> union_set;
+
+ // Union with an empty set.
+ apis1.insert(ExtensionAPIPermission::kTab);
+ apis1.insert(ExtensionAPIPermission::kBackground);
+ expected_apis.insert(ExtensionAPIPermission::kTab);
+ expected_apis.insert(ExtensionAPIPermission::kBackground);
+
+ AddPattern(&explicit_hosts1, "http://*.google.com/*");
+ AddPattern(&expected_explicit_hosts, "http://*.google.com/*");
+ AddPattern(&effective_hosts, "http://*.google.com/*");
+
+ set1.reset(new ExtensionPermissionSet(
+ apis1, explicit_hosts1, scriptable_hosts1));
+ set2.reset(new ExtensionPermissionSet(
+ apis2, explicit_hosts2, scriptable_hosts2));
+ union_set.reset(ExtensionPermissionSet::CreateUnion(set1.get(), set2.get()));
+
+ EXPECT_FALSE(union_set->HasEffectiveFullAccess());
+ EXPECT_EQ(expected_apis, union_set->apis());
+ AssertEqualExtents(expected_explicit_hosts, union_set->explicit_hosts());
+ AssertEqualExtents(expected_scriptable_hosts, union_set->scriptable_hosts());
+ AssertEqualExtents(expected_explicit_hosts, union_set->effective_hosts());
+
+ // Now use a real second set.
+ apis2.insert(ExtensionAPIPermission::kTab);
+ apis2.insert(ExtensionAPIPermission::kProxy);
+ apis2.insert(ExtensionAPIPermission::kClipboardWrite);
+ apis2.insert(ExtensionAPIPermission::kPlugin);
+ expected_apis.insert(ExtensionAPIPermission::kTab);
+ expected_apis.insert(ExtensionAPIPermission::kProxy);
+ expected_apis.insert(ExtensionAPIPermission::kClipboardWrite);
+ expected_apis.insert(ExtensionAPIPermission::kPlugin);
+
+ AddPattern(&explicit_hosts2, "http://*.example.com/*");
+ AddPattern(&scriptable_hosts2, "http://*.google.com/*");
+ AddPattern(&expected_explicit_hosts, "http://*.example.com/*");
+ AddPattern(&expected_scriptable_hosts, "http://*.google.com/*");
+
+ effective_hosts.ClearPatterns();
+ AddPattern(&effective_hosts, "<all_urls>");
+
+ set2.reset(new ExtensionPermissionSet(
+ apis2, explicit_hosts2, scriptable_hosts2));
+ union_set.reset(ExtensionPermissionSet::CreateUnion(set1.get(), set2.get()));
+ EXPECT_TRUE(union_set->HasEffectiveFullAccess());
+ EXPECT_TRUE(union_set->HasEffectiveAccessToAllHosts());
+ EXPECT_EQ(expected_apis, union_set->apis());
+ AssertEqualExtents(expected_explicit_hosts, union_set->explicit_hosts());
+ AssertEqualExtents(expected_scriptable_hosts, union_set->scriptable_hosts());
+ AssertEqualExtents(effective_hosts, union_set->effective_hosts());
+}
+
+TEST(ExtensionPermissionSetTest, HasLessPrivilegesThan) {
+ const struct {
+ const char* base_name;
+ // Increase these sizes if you have more than 10.
+ const char* granted_apis[10];
+ const char* granted_hosts[10];
+ bool full_access;
+ bool expect_increase;
+ } kTests[] = {
+ { "allhosts1", {NULL}, {"http://*/", NULL}, false,
+ false }, // all -> all
+ { "allhosts2", {NULL}, {"http://*/", NULL}, false,
+ false }, // all -> one
+ { "allhosts3", {NULL}, {NULL}, false, true }, // one -> all
+ { "hosts1", {NULL},
+ {"http://www.google.com/", "http://www.reddit.com/", NULL}, false,
+ false }, // http://a,http://b -> http://a,http://b
+ { "hosts2", {NULL},
+ {"http://www.google.com/", "http://www.reddit.com/", NULL}, false,
+ true }, // http://a,http://b -> https://a,http://*.b
+ { "hosts3", {NULL},
+ {"http://www.google.com/", "http://www.reddit.com/", NULL}, false,
+ false }, // http://a,http://b -> http://a
+ { "hosts4", {NULL},
+ {"http://www.google.com/", NULL}, false,
+ true }, // http://a -> http://a,http://b
+ { "hosts5", {"tabs", "notifications", NULL},
+ {"http://*.example.com/", "http://*.example.com/*",
+ "http://*.example.co.uk/*", "http://*.example.com.au/*",
+ NULL}, false,
+ false }, // http://a,b,c -> http://a,b,c + https://a,b,c
+ { "hosts6", {"tabs", "notifications", NULL},
+ {"http://*.example.com/", "http://*.example.com/*", NULL}, false,
+ false }, // http://a.com -> http://a.com + http://a.co.uk
+ { "permissions1", {"tabs", NULL},
+ {NULL}, false, false }, // tabs -> tabs
+ { "permissions2", {"tabs", NULL},
+ {NULL}, false, true }, // tabs -> tabs,bookmarks
+ { "permissions3", {NULL},
+ {"http://*/*", NULL},
+ false, true }, // http://a -> http://a,tabs
+ { "permissions5", {"bookmarks", NULL},
+ {NULL}, false, true }, // bookmarks -> bookmarks,history
+#if !defined(OS_CHROMEOS) // plugins aren't allowed in ChromeOS
+ { "permissions4", {NULL},
+ {NULL}, true, false }, // plugin -> plugin,tabs
+ { "plugin1", {NULL},
+ {NULL}, true, false }, // plugin -> plugin
+ { "plugin2", {NULL},
+ {NULL}, true, false }, // plugin -> none
+ { "plugin3", {NULL},
+ {NULL}, false, true }, // none -> plugin
+#endif
+ { "storage", {NULL},
+ {NULL}, false, false }, // none -> storage
+ { "notifications", {NULL},
+ {NULL}, false, false } // none -> notifications
+ };
+
+ ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) {
+ scoped_refptr<Extension> old_extension(
+ LoadManifest("allow_silent_upgrade",
+ std::string(kTests[i].base_name) + "_old.json"));
+ scoped_refptr<Extension> new_extension(
+ LoadManifest("allow_silent_upgrade",
+ std::string(kTests[i].base_name) + "_new.json"));
+
+ ExtensionAPIPermissionSet granted_apis;
+ for (size_t j = 0; kTests[i].granted_apis[j] != NULL; ++j) {
+ granted_apis.insert(info->GetByName(kTests[i].granted_apis[j])->id());
+ }
+
+ URLPatternSet granted_hosts;
+ for (size_t j = 0; kTests[i].granted_hosts[j] != NULL; ++j)
+ AddPattern(&granted_hosts, kTests[i].granted_hosts[j]);
+
+ EXPECT_TRUE(new_extension.get()) << kTests[i].base_name << "_new.json";
+ if (!new_extension.get())
+ continue;
+
+ const ExtensionPermissionSet* old_p = old_extension->permission_set();
+ const ExtensionPermissionSet* new_p = new_extension->permission_set();
+
+ EXPECT_EQ(kTests[i].expect_increase, old_p->HasLessPrivilegesThan(new_p))
+ << kTests[i].base_name;
+ }
+}
+
+TEST(ExtensionPermissionSetTest, PermissionMessages) {
+ // Ensure that all permissions that needs to show install UI actually have
+ // strings associated with them.
+ ExtensionAPIPermissionSet skip;
+
+ skip.insert(ExtensionAPIPermission::kDefault);
+
+ // These are considered "nuisance" or "trivial" permissions that don't need
+ // a prompt.
+ skip.insert(ExtensionAPIPermission::kContextMenus);
+ skip.insert(ExtensionAPIPermission::kIdle);
+ skip.insert(ExtensionAPIPermission::kNotification);
+ skip.insert(ExtensionAPIPermission::kUnlimitedStorage);
+ skip.insert(ExtensionAPIPermission::kContentSettings);
+
+ // TODO(erikkay) add a string for this permission.
+ skip.insert(ExtensionAPIPermission::kBackground);
+
+ skip.insert(ExtensionAPIPermission::kClipboardWrite);
+
+ // The cookie permission does nothing unless you have associated host
+ // permissions.
+ skip.insert(ExtensionAPIPermission::kCookie);
+
+ // The proxy permission is warned as part of host permission checks.
+ skip.insert(ExtensionAPIPermission::kProxy);
+
+ // This permission requires explicit user action (context menu handler)
+ // so we won't prompt for it for now.
+ skip.insert(ExtensionAPIPermission::kFileBrowserHandler);
+
+ // If you've turned on the experimental command-line flag, we don't need
+ // to warn you further.
+ skip.insert(ExtensionAPIPermission::kExperimental);
+
+ // These are private.
+ skip.insert(ExtensionAPIPermission::kWebstorePrivate);
+ skip.insert(ExtensionAPIPermission::kFileBrowserPrivate);
+ skip.insert(ExtensionAPIPermission::kMediaPlayerPrivate);
+ skip.insert(ExtensionAPIPermission::kChromePrivate);
+ skip.insert(ExtensionAPIPermission::kChromeosInfoPrivate);
+ skip.insert(ExtensionAPIPermission::kWebSocketProxyPrivate);
+
+ // Warned as part of host permissions.
+ skip.insert(ExtensionAPIPermission::kDevtools);
+ ExtensionPermissionsInfo* info = ExtensionPermissionsInfo::GetInstance();
+ ExtensionAPIPermissionSet permissions = info->GetAll();
+ for (ExtensionAPIPermissionSet::const_iterator i = permissions.begin();
+ i != permissions.end(); ++i) {
+ ExtensionAPIPermission* permission = info->GetByID(*i);
+ EXPECT_TRUE(permission);
+ if (skip.count(*i)) {
+ EXPECT_EQ(ExtensionPermissionMessage::kNone, permission->message_id())
+ << "unexpected message_id for " << permission->name();
+ } else {
+ EXPECT_NE(ExtensionPermissionMessage::kNone, permission->message_id())
+ << "missing message_id for " << permission->name();
+ }
+ }
+}
+
+// Tests the default permissions (empty API permission set).
+TEST(ExtensionPermissionSetTest, DefaultFunctionAccess) {
+ const struct {
+ const char* permission_name;
+ bool expect_success;
+ } kTests[] = {
+ // Negative test.
+ { "non_existing_permission", false },
+ // Test default module/package permission.
+ { "browserAction", true },
+ { "browserActions", true },
+ { "devtools", true },
+ { "extension", true },
+ { "i18n", true },
+ { "pageAction", true },
+ { "pageActions", true },
+ { "test", true },
+ // Some negative tests.
+ { "bookmarks", false },
+ { "cookies", false },
+ { "history", false },
+ { "tabs.onUpdated", false },
+ // Make sure we find the module name after stripping '.' and '/'.
+ { "browserAction/abcd/onClick", true },
+ { "browserAction.abcd.onClick", true },
+ // Test Tabs functions.
+ { "tabs.create", true},
+ { "tabs.update", true},
+ { "tabs.getSelected", false},
+ };
+
+ ExtensionPermissionSet permissions;
+ for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) {
+ EXPECT_EQ(kTests[i].expect_success,
+ permissions.HasAccessToFunction(kTests[i].permission_name));
+ }
+}
+
+TEST(ExtensionPermissionSetTest, GetWarningMessages_ManyHosts) {
+ scoped_refptr<Extension> extension;
+
+ extension = LoadManifest("permissions", "many-hosts.json");
+ std::vector<string16> warnings =
+ extension->permission_set()->GetWarningMessages();
+ ASSERT_EQ(1u, warnings.size());
+ EXPECT_EQ("Your data on www.google.com and encrypted.google.com",
+ UTF16ToUTF8(warnings[0]));
+}
+
+TEST(ExtensionPermissionSetTest, GetWarningMessages_Plugins) {
+ scoped_refptr<Extension> extension;
+ scoped_ptr<ExtensionPermissionSet> permissions;
+
+ extension = LoadManifest("permissions", "plugins.json");
+ std::vector<string16> warnings =
+ extension->permission_set()->GetWarningMessages();
+ // We don't parse the plugins key on Chrome OS, so it should not ask for any
+ // permissions.
+#if defined(OS_CHROMEOS)
+ ASSERT_EQ(0u, warnings.size());
+#else
+ ASSERT_EQ(1u, warnings.size());
+ EXPECT_EQ("All data on your computer and the websites you visit",
+ UTF16ToUTF8(warnings[0]));
+#endif
+}
+
+TEST(ExtensionPermissionSetTest, GetDistinctHostsForDisplay) {
+ scoped_ptr<ExtensionPermissionSet> perm_set;
+ ExtensionAPIPermissionSet empty_perms;
+ std::vector<std::string> expected;
+ expected.push_back("www.foo.com");
+ expected.push_back("www.bar.com");
+ expected.push_back("www.baz.com");
+ URLPatternSet explicit_hosts;
+ URLPatternSet scriptable_hosts;
+
+ {
+ SCOPED_TRACE("no dupes");
+
+ // Simple list with no dupes.
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path"));
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.bar.com/path"));
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.baz.com/path"));
+ perm_set.reset(new ExtensionPermissionSet(
+ empty_perms, explicit_hosts, scriptable_hosts));
+ CompareLists(expected, perm_set->GetDistinctHostsForDisplay());
+ }
+
+ {
+ SCOPED_TRACE("two dupes");
+
+ // Add some dupes.
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path"));
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.baz.com/path"));
+ perm_set.reset(new ExtensionPermissionSet(
+ empty_perms, explicit_hosts, scriptable_hosts));
+ CompareLists(expected, perm_set->GetDistinctHostsForDisplay());
+ }
+
+ {
+ SCOPED_TRACE("schemes differ");
+
+ // Add a pattern that differs only by scheme. This should be filtered out.
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTPS, "https://www.bar.com/path"));
+ perm_set.reset(new ExtensionPermissionSet(
+ empty_perms, explicit_hosts, scriptable_hosts));
+ CompareLists(expected, perm_set->GetDistinctHostsForDisplay());
+ }
+
+ {
+ SCOPED_TRACE("paths differ");
+
+ // Add some dupes by path.
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.bar.com/pathypath"));
+ perm_set.reset(new ExtensionPermissionSet(
+ empty_perms, explicit_hosts, scriptable_hosts));
+ CompareLists(expected, perm_set->GetDistinctHostsForDisplay());
+ }
+
+ {
+ SCOPED_TRACE("subdomains differ");
+
+ // We don't do anything special for subdomains.
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://monkey.www.bar.com/path"));
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://bar.com/path"));
+
+ expected.push_back("monkey.www.bar.com");
+ expected.push_back("bar.com");
+
+ perm_set.reset(new ExtensionPermissionSet(
+ empty_perms, explicit_hosts, scriptable_hosts));
+ CompareLists(expected, perm_set->GetDistinctHostsForDisplay());
+ }
+
+ {
+ SCOPED_TRACE("RCDs differ");
+
+ // Now test for RCD uniquing.
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path"));
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.de/path"));
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca.us/path"));
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.net/path"));
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com.my/path"));
+
+ // This is an unknown RCD, which shouldn't be uniqued out.
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.xyzzy/path"));
+ // But it should only occur once.
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.xyzzy/path"));
+
+ expected.push_back("www.foo.xyzzy");
+
+ perm_set.reset(new ExtensionPermissionSet(
+ empty_perms, explicit_hosts, scriptable_hosts));
+ CompareLists(expected, perm_set->GetDistinctHostsForDisplay());
+ }
+
+ {
+ SCOPED_TRACE("wildcards");
+
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://*.google.com/*"));
+
+ expected.push_back("*.google.com");
+
+ perm_set.reset(new ExtensionPermissionSet(
+ empty_perms, explicit_hosts, scriptable_hosts));
+ CompareLists(expected, perm_set->GetDistinctHostsForDisplay());
+ }
+
+ {
+ SCOPED_TRACE("scriptable hosts");
+ explicit_hosts.ClearPatterns();
+ scriptable_hosts.ClearPatterns();
+ expected.clear();
+
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://*.google.com/*"));
+ scriptable_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://*.example.com/*"));
+
+ expected.push_back("*.google.com");
+ expected.push_back("*.example.com");
+
+ perm_set.reset(new ExtensionPermissionSet(
+ empty_perms, explicit_hosts, scriptable_hosts));
+ CompareLists(expected, perm_set->GetDistinctHostsForDisplay());
+ }
+}
+
+TEST(ExtensionPermissionSetTest, GetDistinctHostsForDisplay_ComIsBestRcd) {
+ scoped_ptr<ExtensionPermissionSet> perm_set;
+ ExtensionAPIPermissionSet empty_perms;
+ URLPatternSet explicit_hosts;
+ URLPatternSet scriptable_hosts;
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path"));
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.org/path"));
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.net/path"));
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path"));
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path"));
+
+ std::vector<std::string> expected;
+ expected.push_back("www.foo.com");
+ perm_set.reset(new ExtensionPermissionSet(
+ empty_perms, explicit_hosts, scriptable_hosts));
+ CompareLists(expected, perm_set->GetDistinctHostsForDisplay());
+}
+
+TEST(ExtensionPermissionSetTest, GetDistinctHostsForDisplay_NetIs2ndBestRcd) {
+ scoped_ptr<ExtensionPermissionSet> perm_set;
+ ExtensionAPIPermissionSet empty_perms;
+ URLPatternSet explicit_hosts;
+ URLPatternSet scriptable_hosts;
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path"));
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.org/path"));
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.net/path"));
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path"));
+ // No http://www.foo.com/path
+
+ std::vector<std::string> expected;
+ expected.push_back("www.foo.net");
+ perm_set.reset(new ExtensionPermissionSet(
+ empty_perms, explicit_hosts, scriptable_hosts));
+ CompareLists(expected, perm_set->GetDistinctHostsForDisplay());
+}
+
+TEST(ExtensionPermissionSetTest,
+ GetDistinctHostsForDisplay_OrgIs3rdBestRcd) {
+ scoped_ptr<ExtensionPermissionSet> perm_set;
+ ExtensionAPIPermissionSet empty_perms;
+ URLPatternSet explicit_hosts;
+ URLPatternSet scriptable_hosts;
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path"));
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.org/path"));
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
+ // No http://www.foo.net/path
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path"));
+ // No http://www.foo.com/path
+
+ std::vector<std::string> expected;
+ expected.push_back("www.foo.org");
+ perm_set.reset(new ExtensionPermissionSet(
+ empty_perms, explicit_hosts, scriptable_hosts));
+ CompareLists(expected, perm_set->GetDistinctHostsForDisplay());
+}
+
+TEST(ExtensionPermissionSetTest,
+ GetDistinctHostsForDisplay_FirstInListIs4thBestRcd) {
+ scoped_ptr<ExtensionPermissionSet> perm_set;
+ ExtensionAPIPermissionSet empty_perms;
+ URLPatternSet explicit_hosts;
+ URLPatternSet scriptable_hosts;
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path"));
+ // No http://www.foo.org/path
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
+ // No http://www.foo.net/path
+ explicit_hosts.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path"));
+ // No http://www.foo.com/path
+
+ std::vector<std::string> expected;
+ expected.push_back("www.foo.ca");
+ perm_set.reset(new ExtensionPermissionSet(
+ empty_perms, explicit_hosts, scriptable_hosts));
+ CompareLists(expected, perm_set->GetDistinctHostsForDisplay());
+}
+
+TEST(ExtensionPermissionSetTest, HasLessHostPrivilegesThan) {
+ URLPatternSet elist1;
+ URLPatternSet elist2;
+ URLPatternSet slist1;
+ URLPatternSet slist2;
+ scoped_ptr<ExtensionPermissionSet> set1;
+ scoped_ptr<ExtensionPermissionSet> set2;
+ ExtensionAPIPermissionSet empty_perms;
+ elist1.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com.hk/path"));
+ elist1.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/path"));
+
+ // Test that the host order does not matter.
+ elist2.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/path"));
+ elist2.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com.hk/path"));
+
+ set1.reset(new ExtensionPermissionSet(empty_perms, elist1, slist1));
+ set2.reset(new ExtensionPermissionSet(empty_perms, elist2, slist2));
+
+ EXPECT_FALSE(set1->HasLessHostPrivilegesThan(set2.get()));
+ EXPECT_FALSE(set2->HasLessHostPrivilegesThan(set1.get()));
+
+ // Test that paths are ignored.
+ elist2.ClearPatterns();
+ elist2.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/*"));
+ set2.reset(new ExtensionPermissionSet(empty_perms, elist2, slist2));
+ EXPECT_FALSE(set1->HasLessHostPrivilegesThan(set2.get()));
+ EXPECT_FALSE(set2->HasLessHostPrivilegesThan(set1.get()));
+
+ // Test that RCDs are ignored.
+ elist2.ClearPatterns();
+ elist2.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com.hk/*"));
+ set2.reset(new ExtensionPermissionSet(empty_perms, elist2, slist2));
+ EXPECT_FALSE(set1->HasLessHostPrivilegesThan(set2.get()));
+ EXPECT_FALSE(set2->HasLessHostPrivilegesThan(set1.get()));
+
+ // Test that subdomain wildcards are handled properly.
+ elist2.ClearPatterns();
+ elist2.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://*.google.com.hk/*"));
+ set2.reset(new ExtensionPermissionSet(empty_perms, elist2, slist2));
+ EXPECT_TRUE(set1->HasLessHostPrivilegesThan(set2.get()));
+ //TODO(jstritar): Does not match subdomains properly. http://crbug.com/65337
+ //EXPECT_FALSE(set2->HasLessHostPrivilegesThan(set1.get()));
+
+ // Test that different domains count as different hosts.
+ elist2.ClearPatterns();
+ elist2.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/path"));
+ elist2.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://www.example.org/path"));
+ set2.reset(new ExtensionPermissionSet(empty_perms, elist2, slist2));
+ EXPECT_TRUE(set1->HasLessHostPrivilegesThan(set2.get()));
+ EXPECT_FALSE(set2->HasLessHostPrivilegesThan(set1.get()));
+
+ // Test that different subdomains count as different hosts.
+ elist2.ClearPatterns();
+ elist2.AddPattern(
+ URLPattern(URLPattern::SCHEME_HTTP, "http://mail.google.com/*"));
+ set2.reset(new ExtensionPermissionSet(empty_perms, elist2, slist2));
+ EXPECT_TRUE(set1->HasLessHostPrivilegesThan(set2.get()));
+ EXPECT_TRUE(set2->HasLessHostPrivilegesThan(set1.get()));
+}
+
+TEST(ExtensionPermissionSetTest, GetAPIsAsStrings) {
+ ExtensionAPIPermissionSet apis;
+ URLPatternSet empty_set;
+
+ apis.insert(ExtensionAPIPermission::kProxy);
+ apis.insert(ExtensionAPIPermission::kBackground);
+ apis.insert(ExtensionAPIPermission::kNotification);
+ apis.insert(ExtensionAPIPermission::kTab);
+
+ ExtensionPermissionSet perm_set(apis, empty_set, empty_set);
+ std::set<std::string> api_names = perm_set.GetAPIsAsStrings();
+
+ // The result is correct if it has the same number of elements
+ // and we can convert it back to the id set.
+ EXPECT_EQ(4u, api_names.size());
+ EXPECT_EQ(apis,
+ ExtensionPermissionsInfo::GetInstance()->GetAllByName(api_names));
+}
+
+TEST(ExtensionPermissionSetTest, IsEmpty) {
+ ExtensionAPIPermissionSet empty_apis;
+ URLPatternSet empty_extent;
+
+ ExtensionPermissionSet perm_set;
+ EXPECT_TRUE(perm_set.IsEmpty());
+
+ perm_set = ExtensionPermissionSet(empty_apis, empty_extent, empty_extent);
+ EXPECT_TRUE(perm_set.IsEmpty());
+
+ ExtensionAPIPermissionSet non_empty_apis;
+ non_empty_apis.insert(ExtensionAPIPermission::kBackground);
+ perm_set = ExtensionPermissionSet(
+ non_empty_apis, empty_extent, empty_extent);
+ EXPECT_FALSE(perm_set.IsEmpty());
+
+ // Try non standard host
+ URLPatternSet non_empty_extent;
+ AddPattern(&non_empty_extent, "http://www.google.com/*");
+
+ perm_set = ExtensionPermissionSet(
+ empty_apis, non_empty_extent, empty_extent);
+ EXPECT_FALSE(perm_set.IsEmpty());
+
+ perm_set = ExtensionPermissionSet(
+ empty_apis, empty_extent, non_empty_extent);
+ EXPECT_FALSE(perm_set.IsEmpty());
+}
diff --git a/chrome/common/extensions/extension_unittest.cc b/chrome/common/extensions/extension_unittest.cc
index c74f6f8..aa8555c 100644
--- a/chrome/common/extensions/extension_unittest.cc
+++ b/chrome/common/extensions/extension_unittest.cc
@@ -42,11 +42,6 @@ void CompareLists(const std::vector<std::string>& expected,
}
}
-static void AddPattern(URLPatternSet* extent, const std::string& pattern) {
- int schemes = URLPattern::SCHEME_ALL;
- extent->AddPattern(URLPattern(schemes, pattern));
-}
-
static scoped_refptr<Extension> LoadManifestUnchecked(
const std::string& dir,
const std::string& test_file,
@@ -394,7 +389,11 @@ TEST(ExtensionTest, EffectiveHostPermissions) {
hosts = extension->GetEffectiveHostPermissions();
EXPECT_TRUE(hosts.MatchesURL(GURL("http://google.com")));
EXPECT_TRUE(hosts.MatchesURL(GURL("http://www.reddit.com")));
+ EXPECT_TRUE(extension->permission_set()->HasEffectiveAccessToURL(
+ GURL("http://www.reddit.com")));
EXPECT_TRUE(hosts.MatchesURL(GURL("http://news.ycombinator.com")));
+ EXPECT_TRUE(extension->permission_set()->HasEffectiveAccessToURL(
+ GURL("http://news.ycombinator.com")));
EXPECT_FALSE(extension->HasEffectiveAccessToAllHosts());
extension = LoadManifest("effective_host_permissions", "all_hosts.json");
@@ -418,151 +417,6 @@ TEST(ExtensionTest, EffectiveHostPermissions) {
EXPECT_TRUE(extension->HasEffectiveAccessToAllHosts());
}
-TEST(ExtensionTest, IsPrivilegeIncrease) {
- const struct {
- const char* base_name;
- // Increase these sizes if you have more than 10.
- const char* granted_apis[10];
- const char* granted_hosts[10];
- bool full_access;
- bool expect_increase;
- } kTests[] = {
- { "allhosts1", {NULL}, {"http://*/", NULL}, false,
- false }, // all -> all
- { "allhosts2", {NULL}, {"http://*/", NULL}, false,
- false }, // all -> one
- { "allhosts3", {NULL}, {NULL}, false, true }, // one -> all
- { "hosts1", {NULL},
- {"http://www.google.com/", "http://www.reddit.com/", NULL}, false,
- false }, // http://a,http://b -> http://a,http://b
- { "hosts2", {NULL},
- {"http://www.google.com/", "http://www.reddit.com/", NULL}, false,
- true }, // http://a,http://b -> https://a,http://*.b
- { "hosts3", {NULL},
- {"http://www.google.com/", "http://www.reddit.com/", NULL}, false,
- false }, // http://a,http://b -> http://a
- { "hosts4", {NULL},
- {"http://www.google.com/", NULL}, false,
- true }, // http://a -> http://a,http://b
- { "hosts5", {"tabs", "notifications", NULL},
- {"http://*.example.com/", "http://*.example.com/*",
- "http://*.example.co.uk/*", "http://*.example.com.au/*",
- NULL}, false,
- false }, // http://a,b,c -> http://a,b,c + https://a,b,c
- { "hosts6", {"tabs", "notifications", NULL},
- {"http://*.example.com/", "http://*.example.com/*", NULL}, false,
- false }, // http://a.com -> http://a.com + http://a.co.uk
- { "permissions1", {"tabs", NULL},
- {NULL}, false, false }, // tabs -> tabs
- { "permissions2", {"tabs", NULL},
- {NULL}, false, true }, // tabs -> tabs,bookmarks
- { "permissions3", {NULL},
- {"http://*/*", NULL},
- false, true }, // http://a -> http://a,tabs
- { "permissions5", {"bookmarks", NULL},
- {NULL}, false, true }, // bookmarks -> bookmarks,history
-#if !defined(OS_CHROMEOS) // plugins aren't allowed in ChromeOS
- { "permissions4", {NULL},
- {NULL}, true, false }, // plugin -> plugin,tabs
- { "plugin1", {NULL},
- {NULL}, true, false }, // plugin -> plugin
- { "plugin2", {NULL},
- {NULL}, true, false }, // plugin -> none
- { "plugin3", {NULL},
- {NULL}, false, true }, // none -> plugin
-#endif
- { "storage", {NULL},
- {NULL}, false, false }, // none -> storage
- { "notifications", {NULL},
- {NULL}, false, false } // none -> notifications
- };
-
- for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) {
- scoped_refptr<Extension> old_extension(
- LoadManifest("allow_silent_upgrade",
- std::string(kTests[i].base_name) + "_old.json"));
- scoped_refptr<Extension> new_extension(
- LoadManifest("allow_silent_upgrade",
- std::string(kTests[i].base_name) + "_new.json"));
-
- std::set<std::string> granted_apis;
- for (size_t j = 0; kTests[i].granted_apis[j] != NULL; ++j)
- granted_apis.insert(kTests[i].granted_apis[j]);
-
- URLPatternSet granted_hosts;
- for (size_t j = 0; kTests[i].granted_hosts[j] != NULL; ++j)
- AddPattern(&granted_hosts, kTests[i].granted_hosts[j]);
-
- EXPECT_TRUE(new_extension.get()) << kTests[i].base_name << "_new.json";
- if (!new_extension.get())
- continue;
-
- EXPECT_EQ(kTests[i].expect_increase,
- Extension::IsPrivilegeIncrease(kTests[i].full_access,
- granted_apis,
- granted_hosts,
- new_extension.get()))
- << kTests[i].base_name;
- }
-}
-
-TEST(ExtensionTest, PermissionMessages) {
- // Ensure that all permissions that needs to show install UI actually have
- // strings associated with them.
-
- std::set<std::string> skip;
-
- // These are considered "nuisance" or "trivial" permissions that don't need
- // a prompt.
- skip.insert(Extension::kContextMenusPermission);
- skip.insert(Extension::kIdlePermission);
- skip.insert(Extension::kNotificationPermission);
- skip.insert(Extension::kUnlimitedStoragePermission);
- skip.insert(Extension::kContentSettingsPermission);
-
- // TODO(erikkay) add a string for this permission.
- skip.insert(Extension::kBackgroundPermission);
-
- skip.insert(Extension::kClipboardWritePermission);
-
- // The cookie permission does nothing unless you have associated host
- // permissions.
- skip.insert(Extension::kCookiePermission);
-
- // The proxy permission is warned as part of host permission checks.
- skip.insert(Extension::kProxyPermission);
-
- // This permission requires explicit user action (context menu handler)
- // so we won't prompt for it for now.
- skip.insert(Extension::kFileBrowserHandlerPermission);
-
- // If you've turned on the experimental command-line flag, we don't need
- // to warn you further.
- skip.insert(Extension::kExperimentalPermission);
-
- // These are private.
- skip.insert(Extension::kWebstorePrivatePermission);
- skip.insert(Extension::kFileBrowserPrivatePermission);
- skip.insert(Extension::kMediaPlayerPrivatePermission);
- skip.insert(Extension::kChromePrivatePermission);
- skip.insert(Extension::kChromeosInfoPrivatePermission);
- skip.insert(Extension::kWebSocketProxyPrivatePermission);
-
- const Extension::PermissionMessage::MessageId ID_NONE =
- Extension::PermissionMessage::ID_NONE;
-
- for (size_t i = 0; i < Extension::kNumPermissions; ++i) {
- Extension::Permission permission = Extension::kPermissions[i];
- if (skip.count(permission.name)) {
- EXPECT_EQ(ID_NONE, permission.message_id)
- << "unexpected message_id for " << permission.name;
- } else {
- EXPECT_NE(ID_NONE, permission.message_id)
- << "missing message_id for " << permission.name;
- }
- }
-}
-
// Returns a copy of |source| resized to |size| x |size|.
static SkBitmap ResizedCopy(const SkBitmap& source, int size) {
return skia::ImageOperations::Resize(source,
@@ -687,7 +541,7 @@ TEST(ExtensionTest, ApiPermissions) {
for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTests); ++i) {
EXPECT_EQ(kTests[i].expect_success,
- extension->HasApiPermission(kTests[i].permission_name))
+ extension->HasAPIPermission(kTests[i].permission_name))
<< "Permission being tested: " << kTests[i].permission_name;
}
}
@@ -904,257 +758,6 @@ TEST_F(ExtensionScriptAndCaptureVisibleTest, Permissions) {
EXPECT_FALSE(extension->HasHostPermission(settings_url));
}
-TEST(ExtensionTest, GetDistinctHostsForDisplay) {
- std::vector<std::string> expected;
- expected.push_back("www.foo.com");
- expected.push_back("www.bar.com");
- expected.push_back("www.baz.com");
- URLPatternList actual;
-
- {
- SCOPED_TRACE("no dupes");
-
- // Simple list with no dupes.
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path"));
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.bar.com/path"));
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.baz.com/path"));
- CompareLists(expected,
- Extension::GetDistinctHostsForDisplay(actual));
- }
-
- {
- SCOPED_TRACE("two dupes");
-
- // Add some dupes.
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path"));
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.baz.com/path"));
- CompareLists(expected,
- Extension::GetDistinctHostsForDisplay(actual));
- }
-
- {
- SCOPED_TRACE("schemes differ");
-
- // Add a pattern that differs only by scheme. This should be filtered out.
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTPS, "https://www.bar.com/path"));
- CompareLists(expected,
- Extension::GetDistinctHostsForDisplay(actual));
- }
-
- {
- SCOPED_TRACE("paths differ");
-
- // Add some dupes by path.
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.bar.com/pathypath"));
- CompareLists(expected,
- Extension::GetDistinctHostsForDisplay(actual));
- }
-
- {
- SCOPED_TRACE("subdomains differ");
-
- // We don't do anything special for subdomains.
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://monkey.www.bar.com/path"));
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://bar.com/path"));
-
- expected.push_back("monkey.www.bar.com");
- expected.push_back("bar.com");
-
- CompareLists(expected,
- Extension::GetDistinctHostsForDisplay(actual));
- }
-
- {
- SCOPED_TRACE("RCDs differ");
-
- // Now test for RCD uniquing.
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path"));
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.de/path"));
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca.us/path"));
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.net/path"));
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com.my/path"));
-
- // This is an unknown RCD, which shouldn't be uniqued out.
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.xyzzy/path"));
- // But it should only occur once.
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.xyzzy/path"));
-
- expected.push_back("www.foo.xyzzy");
-
- CompareLists(expected,
- Extension::GetDistinctHostsForDisplay(actual));
- }
-
- {
- SCOPED_TRACE("wildcards");
-
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://*.google.com/*"));
-
- expected.push_back("*.google.com");
-
- CompareLists(expected,
- Extension::GetDistinctHostsForDisplay(actual));
- }
-}
-
-TEST(ExtensionTest, GetDistinctHostsForDisplay_ComIsBestRcd) {
- URLPatternList actual;
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path"));
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.org/path"));
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.net/path"));
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path"));
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.com/path"));
-
- std::vector<std::string> expected;
- expected.push_back("www.foo.com");
-
- CompareLists(expected,
- Extension::GetDistinctHostsForDisplay(actual));
-}
-
-TEST(ExtensionTest, GetDistinctHostsForDisplay_NetIs2ndBestRcd) {
- URLPatternList actual;
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path"));
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.org/path"));
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.net/path"));
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path"));
- // No http://www.foo.com/path
-
- std::vector<std::string> expected;
- expected.push_back("www.foo.net");
-
- CompareLists(expected,
- Extension::GetDistinctHostsForDisplay(actual));
-}
-
-TEST(ExtensionTest, GetDistinctHostsForDisplay_OrgIs3rdBestRcd) {
- URLPatternList actual;
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path"));
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.org/path"));
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
- // No http://www.foo.net/path
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path"));
- // No http://www.foo.com/path
-
- std::vector<std::string> expected;
- expected.push_back("www.foo.org");
-
- CompareLists(expected,
- Extension::GetDistinctHostsForDisplay(actual));
-}
-
-TEST(ExtensionTest, GetDistinctHostsForDisplay_FirstInListIs4thBestRcd) {
- URLPatternList actual;
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.ca/path"));
- // No http://www.foo.org/path
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.co.uk/path"));
- // No http://www.foo.net/path
- actual.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.foo.jp/path"));
- // No http://www.foo.com/path
-
- std::vector<std::string> expected;
- expected.push_back("www.foo.ca");
-
- CompareLists(expected,
- Extension::GetDistinctHostsForDisplay(actual));
-}
-
-TEST(ExtensionTest, IsElevatedHostList) {
- URLPatternList list1;
- URLPatternList list2;
-
- list1.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com.hk/path"));
- list1.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/path"));
-
- // Test that the host order does not matter.
- list2.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/path"));
- list2.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com.hk/path"));
-
- EXPECT_FALSE(Extension::IsElevatedHostList(list1, list2));
- EXPECT_FALSE(Extension::IsElevatedHostList(list2, list1));
-
- // Test that paths are ignored.
- list2.clear();
- list2.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/*"));
- EXPECT_FALSE(Extension::IsElevatedHostList(list1, list2));
- EXPECT_FALSE(Extension::IsElevatedHostList(list2, list1));
-
- // Test that RCDs are ignored.
- list2.clear();
- list2.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com.hk/*"));
- EXPECT_FALSE(Extension::IsElevatedHostList(list1, list2));
- EXPECT_FALSE(Extension::IsElevatedHostList(list2, list1));
-
- // Test that subdomain wildcards are handled properly.
- list2.clear();
- list2.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://*.google.com.hk/*"));
- EXPECT_TRUE(Extension::IsElevatedHostList(list1, list2));
- //TODO(jstritar): Does not match subdomains properly. http://crbug.com/65337
- //EXPECT_FALSE(Extension::IsElevatedHostList(list2, list1));
-
- // Test that different domains count as different hosts.
- list2.clear();
- list2.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.google.com/path"));
- list2.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://www.example.org/path"));
- EXPECT_TRUE(Extension::IsElevatedHostList(list1, list2));
- EXPECT_FALSE(Extension::IsElevatedHostList(list2, list1));
-
- // Test that different subdomains count as different hosts.
- list2.clear();
- list2.push_back(
- URLPattern(URLPattern::SCHEME_HTTP, "http://mail.google.com/*"));
- EXPECT_TRUE(Extension::IsElevatedHostList(list1, list2));
- EXPECT_TRUE(Extension::IsElevatedHostList(list2, list1));
-}
-
TEST(ExtensionTest, GenerateId) {
std::string result;
EXPECT_TRUE(Extension::GenerateId("", &result));
diff --git a/chrome/common/extensions/url_pattern_set.cc b/chrome/common/extensions/url_pattern_set.cc
index c8374ef..65f8635 100644
--- a/chrome/common/extensions/url_pattern_set.cc
+++ b/chrome/common/extensions/url_pattern_set.cc
@@ -7,6 +7,22 @@
#include "chrome/common/extensions/url_pattern.h"
#include "googleurl/src/gurl.h"
+// static
+void URLPatternSet::CreateUnion(const URLPatternSet& set1,
+ const URLPatternSet& set2,
+ URLPatternSet* out) {
+ const URLPatternList list1 = set1.patterns();
+ const URLPatternList list2 = set2.patterns();
+
+ out->ClearPatterns();
+
+ for (size_t i = 0; i < list1.size(); ++i)
+ out->AddPattern(list1.at(i));
+
+ for (size_t i = 0; i < list2.size(); ++i)
+ out->AddPattern(list2.at(i));
+}
+
URLPatternSet::URLPatternSet() {
}
diff --git a/chrome/common/extensions/url_pattern_set.h b/chrome/common/extensions/url_pattern_set.h
index ac50afc..2120e547 100644
--- a/chrome/common/extensions/url_pattern_set.h
+++ b/chrome/common/extensions/url_pattern_set.h
@@ -15,6 +15,12 @@ class GURL;
// Represents the set of URLs an extension uses for web content.
class URLPatternSet {
public:
+ // Clears |out| and populates the set with the union of |set1| and |set2|.
+ // NOTE: this does not discard duplicates.
+ static void CreateUnion(const URLPatternSet& set1,
+ const URLPatternSet& set2,
+ URLPatternSet* out);
+
URLPatternSet();
URLPatternSet(const URLPatternSet& rhs);
~URLPatternSet();
diff --git a/chrome/common/extensions/url_pattern_set_unittest.cc b/chrome/common/extensions/url_pattern_set_unittest.cc
index 5336410..8c05f2c 100644
--- a/chrome/common/extensions/url_pattern_set_unittest.cc
+++ b/chrome/common/extensions/url_pattern_set_unittest.cc
@@ -7,6 +7,27 @@
#include "googleurl/src/gurl.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace {
+
+static void AssertEqualExtents(const URLPatternSet& extent1,
+ const URLPatternSet& extent2) {
+ URLPatternList patterns1 = extent1.patterns();
+ URLPatternList patterns2 = extent2.patterns();
+ std::set<std::string> strings1;
+ EXPECT_EQ(patterns1.size(), patterns2.size());
+
+ for (size_t i = 0; i < patterns1.size(); ++i)
+ strings1.insert(patterns1.at(i).GetAsString());
+
+ std::set<std::string> strings2;
+ for (size_t i = 0; i < patterns2.size(); ++i)
+ strings2.insert(patterns2.at(i).GetAsString());
+
+ EXPECT_EQ(strings1, strings2);
+}
+
+} // namespace
+
static const int kAllSchemes =
URLPattern::SCHEME_HTTP |
URLPattern::SCHEME_HTTPS |
@@ -60,3 +81,35 @@ TEST(URLPatternSetTest, OverlapsWith) {
EXPECT_TRUE(extent1.OverlapsWith(extent3));
EXPECT_TRUE(extent3.OverlapsWith(extent1));
}
+
+TEST(URLPatternSetTest, CreateUnion) {
+ URLPatternSet empty_extent;
+
+ URLPatternSet extent1;
+ extent1.AddPattern(URLPattern(kAllSchemes, "http://www.google.com/f*"));
+ extent1.AddPattern(URLPattern(kAllSchemes, "http://www.yahoo.com/b*"));
+
+ URLPatternSet expected;
+ expected.AddPattern(URLPattern(kAllSchemes, "http://www.google.com/f*"));
+ expected.AddPattern(URLPattern(kAllSchemes, "http://www.yahoo.com/b*"));
+
+ // Union with an empty set.
+ URLPatternSet result;
+ URLPatternSet::CreateUnion(extent1, empty_extent, &result);
+ AssertEqualExtents(expected, result);
+
+ // Union with a real set (including a duplicate).
+ URLPatternSet extent2;
+ extent2.AddPattern(URLPattern(kAllSchemes, "http://www.reddit.com/f*"));
+ extent2.AddPattern(URLPattern(kAllSchemes, "http://www.yahoo.com/z*"));
+ extent2.AddPattern(URLPattern(kAllSchemes, "http://www.google.com/f*"));
+
+ expected.AddPattern(URLPattern(kAllSchemes, "http://www.reddit.com/f*"));
+ expected.AddPattern(URLPattern(kAllSchemes, "http://www.yahoo.com/z*"));
+ // CreateUnion does not filter out duplicates right now.
+ expected.AddPattern(URLPattern(kAllSchemes, "http://www.google.com/f*"));
+
+ result.ClearPatterns();
+ URLPatternSet::CreateUnion(extent1, extent2, &result);
+ AssertEqualExtents(expected, result);
+}
diff --git a/chrome/renderer/extensions/bindings_utils.cc b/chrome/renderer/extensions/bindings_utils.cc
index 89fa70b..0d786e7 100644
--- a/chrome/renderer/extensions/bindings_utils.cc
+++ b/chrome/renderer/extensions/bindings_utils.cc
@@ -65,7 +65,7 @@ bool ExtensionBase::CheckPermissionForCurrentContext(
const ::Extension* extension = GetExtensionForCurrentContext();
if (extension &&
extension_dispatcher_->IsExtensionActive(extension->id()) &&
- extension->HasApiPermission(function_name))
+ extension->HasAPIPermission(function_name))
return true;
static const char kMessage[] =
diff --git a/chrome/renderer/extensions/extension_dispatcher.cc b/chrome/renderer/extensions/extension_dispatcher.cc
index 370f36d..e654623 100644
--- a/chrome/renderer/extensions/extension_dispatcher.cc
+++ b/chrome/renderer/extensions/extension_dispatcher.cc
@@ -235,7 +235,7 @@ void ExtensionDispatcher::OnActivateExtension(
}
void ExtensionDispatcher::InitHostPermissions(const Extension* extension) {
- if (extension->HasApiPermission(Extension::kManagementPermission)) {
+ if (extension->HasAPIPermission(ExtensionAPIPermission::kManagement)) {
WebSecurityPolicy::addOriginAccessWhitelistEntry(
extension->url(),
WebString::fromUTF8(chrome::kChromeUIScheme),
@@ -243,7 +243,8 @@ void ExtensionDispatcher::InitHostPermissions(const Extension* extension) {
false);
}
- const URLPatternList& permissions = extension->host_permissions();
+ const URLPatternList& permissions =
+ extension->permission_set()->explicit_hosts().patterns();
for (size_t i = 0; i < permissions.size(); ++i) {
const char* schemes[] = {
chrome::kHttpScheme,