Index: chrome/browser/extensions/permissions_updater.cc |
diff --git a/chrome/browser/extensions/permissions_updater.cc b/chrome/browser/extensions/permissions_updater.cc |
index 9d4a7b6f9dcabf2084940fc0ab69304650d20910..2c53492de960091014b74a8541a17426f1cc5ee7 100644 |
--- a/chrome/browser/extensions/permissions_updater.cc |
+++ b/chrome/browser/extensions/permissions_updater.cc |
@@ -9,6 +9,7 @@ |
#include "base/values.h" |
#include "chrome/browser/chrome_notification_types.h" |
#include "chrome/browser/extensions/api/permissions/permissions_api_helpers.h" |
+#include "chrome/browser/extensions/extension_util.h" |
#include "chrome/browser/profiles/profile.h" |
#include "chrome/common/extensions/api/permissions.h" |
#include "content/public/browser/notification_observer.h" |
@@ -19,9 +20,12 @@ |
#include "extensions/browser/extension_prefs.h" |
#include "extensions/common/extension.h" |
#include "extensions/common/extension_messages.h" |
+#include "extensions/common/feature_switch.h" |
#include "extensions/common/manifest_handlers/permissions_parser.h" |
#include "extensions/common/permissions/permission_set.h" |
#include "extensions/common/permissions/permissions_data.h" |
+#include "extensions/common/url_pattern.h" |
+#include "extensions/common/url_pattern_set.h" |
using content::RenderProcessHost; |
using extensions::permissions_api_helpers::PackPermissionSet; |
@@ -30,6 +34,61 @@ namespace extensions { |
namespace permissions = api::permissions; |
+namespace { |
+ |
+// Returns a PermissionSet that has the active permissions of the extension, |
+// bounded to its current manifest. |
+scoped_refptr<const PermissionSet> GetBoundedActivePermissions( |
+ const Extension* extension, ExtensionPrefs* extension_prefs) { |
+ // If the extension has used the optional permissions API, it will have a |
+ // custom set of active permissions defined in the extension prefs. Here, |
+ // we update the extension's active permissions based on the prefs. |
+ scoped_refptr<const PermissionSet> active_permissions = |
+ extension_prefs->GetActivePermissions(extension->id()); |
+ if (!active_permissions) |
+ return extension->permissions_data()->active_permissions(); |
+ |
+ scoped_refptr<const PermissionSet> required_permissions = |
+ PermissionsParser::GetRequiredPermissions(extension); |
+ |
+ // We restrict the active permissions to be within the bounds defined in the |
+ // extension's manifest. |
+ // a) active permissions must be a subset of optional + default permissions |
+ // b) active permissions must contains all default permissions |
+ scoped_refptr<PermissionSet> total_permissions = PermissionSet::CreateUnion( |
+ required_permissions, |
+ PermissionsParser::GetOptionalPermissions(extension)); |
+ |
+ // Make sure the active permissions contain no more than optional + default. |
+ scoped_refptr<PermissionSet> adjusted_active = |
+ PermissionSet::CreateIntersection(total_permissions, active_permissions); |
+ |
+ // Make sure the active permissions contain the default permissions. |
+ adjusted_active = |
+ PermissionSet::CreateUnion(required_permissions, adjusted_active); |
+ |
+ return adjusted_active; |
+} |
+ |
+// Divvy up the |url patterns| between those we grant and those we do not. If |
+// |withhold_permissions| is false (because the requisite feature is not |
+// enabled), no permissions are withheld. |
+void SegregateUrlPermissions(const URLPatternSet& url_patterns, |
+ bool withhold_permissions, |
+ URLPatternSet* granted, |
+ URLPatternSet* withheld) { |
+ for (URLPatternSet::const_iterator iter = url_patterns.begin(); |
+ iter != url_patterns.end(); |
+ ++iter) { |
+ if (withhold_permissions && iter->ImpliesAllHosts()) |
+ withheld->AddPattern(*iter); |
+ else |
+ granted->AddPattern(*iter); |
+ } |
+} |
+ |
+} // namespace |
+ |
PermissionsUpdater::PermissionsUpdater(content::BrowserContext* browser_context) |
: browser_context_(browser_context) { |
} |
@@ -45,7 +104,7 @@ void PermissionsUpdater::AddPermissions( |
scoped_refptr<PermissionSet> added( |
PermissionSet::CreateDifference(total.get(), existing.get())); |
- SetActivePermissions(extension, total.get()); |
+ SetPermissions(extension, total, NULL); |
// Update the granted permissions so we don't auto-disable the extension. |
GrantActivePermissions(extension); |
@@ -65,7 +124,7 @@ void PermissionsUpdater::RemovePermissions( |
// We update the active permissions, and not the granted permissions, because |
// the extension, not the user, removed the permissions. This allows the |
// extension to add them again without prompting the user. |
- SetActivePermissions(extension, total.get()); |
+ SetPermissions(extension, total, NULL); |
NotifyPermissionsUpdated(REMOVED, extension, removed.get()); |
} |
@@ -84,42 +143,121 @@ void PermissionsUpdater::GrantActivePermissions(const Extension* extension) { |
extension->permissions_data()->active_permissions().get()); |
} |
-void PermissionsUpdater::InitializeActivePermissions( |
- const Extension* extension) { |
- // If the extension has used the optional permissions API, it will have a |
- // custom set of active permissions defined in the extension prefs. Here, |
- // we update the extension's active permissions based on the prefs. |
- scoped_refptr<PermissionSet> active_permissions = |
- ExtensionPrefs::Get(browser_context_)->GetActivePermissions( |
- extension->id()); |
- if (!active_permissions) |
- return; |
- |
- // We restrict the active permissions to be within the bounds defined in the |
- // extension's manifest. |
- // a) active permissions must be a subset of optional + default permissions |
- // b) active permissions must contains all default permissions |
- scoped_refptr<PermissionSet> total_permissions = PermissionSet::CreateUnion( |
- PermissionsParser::GetRequiredPermissions(extension), |
- PermissionsParser::GetOptionalPermissions(extension)); |
- |
- // Make sure the active permissions contain no more than optional + default. |
- scoped_refptr<PermissionSet> adjusted_active = |
- PermissionSet::CreateIntersection(total_permissions, active_permissions); |
+void PermissionsUpdater::InitializePermissions(const Extension* extension) { |
+ scoped_refptr<const PermissionSet> bounded_active = |
+ GetBoundedActivePermissions(extension, |
+ ExtensionPrefs::Get(browser_context_)); |
+ |
+ // We withhold permissions iff the switch to do so is enabled, the extension |
+ // shows up in chrome:extensions (so the user can grant withheld permissions), |
+ // the extension is not part of chrome or corporate policy, and also not on |
+ // the scripting whitelist. Additionally, we don't withhold if the extension |
+ // has the preference to allow scripting on all urls. |
+ bool should_withhold_permissions = |
+ FeatureSwitch::scripts_require_action()->IsEnabled() && |
+ extension->ShouldDisplayInExtensionSettings() && |
+ !Manifest::IsPolicyLocation(extension->location()) && |
+ !Manifest::IsComponentLocation(extension->location()) && |
+ !PermissionsData::CanExecuteScriptEverywhere(extension) && |
+ !util::AllowedScriptingOnAllUrls(extension->id(), browser_context_); |
+ |
+ URLPatternSet granted_explicit_hosts; |
+ URLPatternSet withheld_explicit_hosts; |
+ SegregateUrlPermissions(bounded_active->explicit_hosts(), |
+ should_withhold_permissions, |
+ &granted_explicit_hosts, |
+ &withheld_explicit_hosts); |
+ |
+ URLPatternSet granted_scriptable_hosts; |
+ URLPatternSet withheld_scriptable_hosts; |
+ SegregateUrlPermissions(bounded_active->scriptable_hosts(), |
+ should_withhold_permissions, |
+ &granted_scriptable_hosts, |
+ &withheld_scriptable_hosts); |
+ |
+ bounded_active = new PermissionSet(bounded_active->apis(), |
+ bounded_active->manifest_permissions(), |
+ granted_explicit_hosts, |
+ granted_scriptable_hosts); |
+ |
+ scoped_refptr<const PermissionSet> withheld = |
+ new PermissionSet(APIPermissionSet(), |
+ ManifestPermissionSet(), |
+ withheld_explicit_hosts, |
+ withheld_scriptable_hosts); |
+ SetPermissions(extension, bounded_active, withheld); |
+} |
- // Make sure the active permissions contain the default permissions. |
- adjusted_active = PermissionSet::CreateUnion( |
- PermissionsParser::GetRequiredPermissions(extension), |
- adjusted_active); |
+void PermissionsUpdater::WithholdAllHosts(const Extension* extension) { |
+ scoped_refptr<const PermissionSet> active = |
+ extension->permissions_data()->active_permissions(); |
+ scoped_refptr<const PermissionSet> withheld = |
+ extension->permissions_data()->withheld_permissions(); |
+ |
+ URLPatternSet withheld_scriptable = withheld->scriptable_hosts(); |
+ URLPatternSet active_scriptable; |
+ SegregateUrlPermissions(active->scriptable_hosts(), |
+ true, // withhold permissions |
+ &active_scriptable, |
+ &withheld_scriptable); |
+ |
+ URLPatternSet withheld_explicit = withheld->explicit_hosts(); |
+ URLPatternSet active_explicit; |
+ SegregateUrlPermissions(active->explicit_hosts(), |
+ true, // withhold permissions |
+ &active_explicit, |
+ &withheld_explicit); |
+ |
+ SetPermissions(extension, |
+ new PermissionSet(active->apis(), |
+ active->manifest_permissions(), |
+ active_explicit, |
+ active_scriptable), |
+ new PermissionSet(withheld->apis(), |
+ withheld->manifest_permissions(), |
+ withheld_explicit, |
+ withheld_scriptable)); |
+ // TODO(rdevlin.cronin) We should notify the observers/renderer. |
+} |
- SetActivePermissions(extension, adjusted_active); |
+void PermissionsUpdater::GrantWithheldAllHosts(const Extension* extension) { |
+ scoped_refptr<const PermissionSet> active = |
+ extension->permissions_data()->active_permissions(); |
+ scoped_refptr<const PermissionSet> withheld = |
+ extension->permissions_data()->withheld_permissions(); |
+ |
+ // Move the all-hosts permission from withheld to active. |
+ // We can cheat a bit here since we know that the only host permission we |
+ // withhold is allhosts (or something similar enough to it), so we can just |
+ // grant all withheld host permissions. |
+ URLPatternSet explicit_hosts; |
+ URLPatternSet::CreateUnion( |
+ active->explicit_hosts(), withheld->explicit_hosts(), &explicit_hosts); |
+ URLPatternSet scriptable_hosts; |
+ URLPatternSet::CreateUnion(active->scriptable_hosts(), |
+ withheld->scriptable_hosts(), |
+ &scriptable_hosts); |
+ |
+ // Since we only withhold host permissions (so far), we know that withheld |
+ // permissions will be empty. |
+ SetPermissions(extension, |
+ new PermissionSet(active->apis(), |
+ active->manifest_permissions(), |
+ explicit_hosts, |
+ scriptable_hosts), |
+ new PermissionSet()); |
+ // TODO(rdevlin.cronin) We should notify the observers/renderer. |
} |
-void PermissionsUpdater::SetActivePermissions( |
- const Extension* extension, const PermissionSet* permissions) { |
+void PermissionsUpdater::SetPermissions( |
+ const Extension* extension, |
+ scoped_refptr<const PermissionSet> active, |
+ scoped_refptr<const PermissionSet> withheld) { |
+ withheld = withheld.get() ? withheld |
+ : extension->permissions_data()->withheld_permissions(); |
+ extension->permissions_data()->SetPermissions(active, withheld); |
ExtensionPrefs::Get(browser_context_)->SetActivePermissions( |
- extension->id(), permissions); |
- extension->permissions_data()->SetActivePermissions(permissions); |
+ extension->id(), active); |
} |
void PermissionsUpdater::DispatchEvent( |
@@ -168,12 +306,11 @@ void PermissionsUpdater::NotifyPermissionsUpdated( |
content::Details<UpdatedExtensionPermissionsInfo>(&info)); |
ExtensionMsg_UpdatePermissions_Params params; |
- params.reason_id = static_cast<int>(reason); |
params.extension_id = extension->id(); |
- params.apis = changed->apis(); |
- params.manifest_permissions = changed->manifest_permissions(); |
- params.explicit_hosts = changed->explicit_hosts(); |
- params.scriptable_hosts = changed->scriptable_hosts(); |
+ params.active_permissions = ExtensionMsg_PermissionSetStruct( |
+ extension->permissions_data()->active_permissions()); |
+ params.withheld_permissions = ExtensionMsg_PermissionSetStruct( |
+ extension->permissions_data()->withheld_permissions()); |
// Send the new permissions to the renderers. |
for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator()); |