OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/extensions/permissions_updater.h" | 5 #include "chrome/browser/extensions/permissions_updater.h" |
6 | 6 |
7 #include "base/json/json_writer.h" | 7 #include "base/json/json_writer.h" |
8 #include "base/memory/ref_counted.h" | 8 #include "base/memory/ref_counted.h" |
9 #include "base/values.h" | 9 #include "base/values.h" |
10 #include "chrome/browser/chrome_notification_types.h" | 10 #include "chrome/browser/chrome_notification_types.h" |
11 #include "chrome/browser/extensions/api/permissions/permissions_api_helpers.h" | 11 #include "chrome/browser/extensions/api/permissions/permissions_api_helpers.h" |
| 12 #include "chrome/browser/extensions/extension_util.h" |
12 #include "chrome/browser/profiles/profile.h" | 13 #include "chrome/browser/profiles/profile.h" |
13 #include "chrome/common/extensions/api/permissions.h" | 14 #include "chrome/common/extensions/api/permissions.h" |
14 #include "content/public/browser/notification_observer.h" | 15 #include "content/public/browser/notification_observer.h" |
15 #include "content/public/browser/notification_registrar.h" | 16 #include "content/public/browser/notification_registrar.h" |
16 #include "content/public/browser/notification_service.h" | 17 #include "content/public/browser/notification_service.h" |
17 #include "content/public/browser/render_process_host.h" | 18 #include "content/public/browser/render_process_host.h" |
18 #include "extensions/browser/event_router.h" | 19 #include "extensions/browser/event_router.h" |
19 #include "extensions/browser/extension_prefs.h" | 20 #include "extensions/browser/extension_prefs.h" |
20 #include "extensions/common/extension.h" | 21 #include "extensions/common/extension.h" |
21 #include "extensions/common/extension_messages.h" | 22 #include "extensions/common/extension_messages.h" |
| 23 #include "extensions/common/feature_switch.h" |
22 #include "extensions/common/manifest_handlers/permissions_parser.h" | 24 #include "extensions/common/manifest_handlers/permissions_parser.h" |
23 #include "extensions/common/permissions/permission_set.h" | 25 #include "extensions/common/permissions/permission_set.h" |
24 #include "extensions/common/permissions/permissions_data.h" | 26 #include "extensions/common/permissions/permissions_data.h" |
| 27 #include "extensions/common/url_pattern.h" |
| 28 #include "extensions/common/url_pattern_set.h" |
25 | 29 |
26 using content::RenderProcessHost; | 30 using content::RenderProcessHost; |
27 using extensions::permissions_api_helpers::PackPermissionSet; | 31 using extensions::permissions_api_helpers::PackPermissionSet; |
28 | 32 |
29 namespace extensions { | 33 namespace extensions { |
30 | 34 |
31 namespace permissions = api::permissions; | 35 namespace permissions = api::permissions; |
32 | 36 |
| 37 namespace { |
| 38 |
| 39 // Returns a PermissionSet that has the active permissions of the extension, |
| 40 // bounded to its current manifest. |
| 41 scoped_refptr<const PermissionSet> GetBoundedActivePermissions( |
| 42 const Extension* extension, ExtensionPrefs* extension_prefs) { |
| 43 // If the extension has used the optional permissions API, it will have a |
| 44 // custom set of active permissions defined in the extension prefs. Here, |
| 45 // we update the extension's active permissions based on the prefs. |
| 46 scoped_refptr<const PermissionSet> active_permissions = |
| 47 extension_prefs->GetActivePermissions(extension->id()); |
| 48 if (!active_permissions) |
| 49 return extension->permissions_data()->active_permissions(); |
| 50 |
| 51 scoped_refptr<const PermissionSet> required_permissions = |
| 52 PermissionsParser::GetRequiredPermissions(extension); |
| 53 |
| 54 // We restrict the active permissions to be within the bounds defined in the |
| 55 // extension's manifest. |
| 56 // a) active permissions must be a subset of optional + default permissions |
| 57 // b) active permissions must contains all default permissions |
| 58 scoped_refptr<PermissionSet> total_permissions = PermissionSet::CreateUnion( |
| 59 required_permissions, |
| 60 PermissionsParser::GetOptionalPermissions(extension)); |
| 61 |
| 62 // Make sure the active permissions contain no more than optional + default. |
| 63 scoped_refptr<PermissionSet> adjusted_active = |
| 64 PermissionSet::CreateIntersection(total_permissions, active_permissions); |
| 65 |
| 66 // Make sure the active permissions contain the default permissions. |
| 67 adjusted_active = |
| 68 PermissionSet::CreateUnion(required_permissions, adjusted_active); |
| 69 |
| 70 return adjusted_active; |
| 71 } |
| 72 |
| 73 // Divvy up the |url patterns| between those we grant and those we do not. If |
| 74 // |withhold_permissions| is false (because the requisite feature is not |
| 75 // enabled), no permissions are withheld. |
| 76 void SegregateUrlPermissions(const URLPatternSet& url_patterns, |
| 77 bool withhold_permissions, |
| 78 URLPatternSet* granted, |
| 79 URLPatternSet* withheld) { |
| 80 for (URLPatternSet::const_iterator iter = url_patterns.begin(); |
| 81 iter != url_patterns.end(); |
| 82 ++iter) { |
| 83 if (withhold_permissions && iter->ImpliesAllHosts()) |
| 84 withheld->AddPattern(*iter); |
| 85 else |
| 86 granted->AddPattern(*iter); |
| 87 } |
| 88 } |
| 89 |
| 90 } // namespace |
| 91 |
33 PermissionsUpdater::PermissionsUpdater(content::BrowserContext* browser_context) | 92 PermissionsUpdater::PermissionsUpdater(content::BrowserContext* browser_context) |
34 : browser_context_(browser_context) { | 93 : browser_context_(browser_context) { |
35 } | 94 } |
36 | 95 |
37 PermissionsUpdater::~PermissionsUpdater() {} | 96 PermissionsUpdater::~PermissionsUpdater() {} |
38 | 97 |
39 void PermissionsUpdater::AddPermissions( | 98 void PermissionsUpdater::AddPermissions( |
40 const Extension* extension, const PermissionSet* permissions) { | 99 const Extension* extension, const PermissionSet* permissions) { |
41 scoped_refptr<const PermissionSet> existing( | 100 scoped_refptr<const PermissionSet> existing( |
42 extension->permissions_data()->active_permissions()); | 101 extension->permissions_data()->active_permissions()); |
43 scoped_refptr<PermissionSet> total( | 102 scoped_refptr<PermissionSet> total( |
44 PermissionSet::CreateUnion(existing.get(), permissions)); | 103 PermissionSet::CreateUnion(existing.get(), permissions)); |
45 scoped_refptr<PermissionSet> added( | 104 scoped_refptr<PermissionSet> added( |
46 PermissionSet::CreateDifference(total.get(), existing.get())); | 105 PermissionSet::CreateDifference(total.get(), existing.get())); |
47 | 106 |
48 SetActivePermissions(extension, total.get()); | 107 SetPermissions(extension, total, NULL); |
49 | 108 |
50 // Update the granted permissions so we don't auto-disable the extension. | 109 // Update the granted permissions so we don't auto-disable the extension. |
51 GrantActivePermissions(extension); | 110 GrantActivePermissions(extension); |
52 | 111 |
53 NotifyPermissionsUpdated(ADDED, extension, added.get()); | 112 NotifyPermissionsUpdated(ADDED, extension, added.get()); |
54 } | 113 } |
55 | 114 |
56 void PermissionsUpdater::RemovePermissions( | 115 void PermissionsUpdater::RemovePermissions( |
57 const Extension* extension, const PermissionSet* permissions) { | 116 const Extension* extension, const PermissionSet* permissions) { |
58 scoped_refptr<const PermissionSet> existing( | 117 scoped_refptr<const PermissionSet> existing( |
59 extension->permissions_data()->active_permissions()); | 118 extension->permissions_data()->active_permissions()); |
60 scoped_refptr<PermissionSet> total( | 119 scoped_refptr<PermissionSet> total( |
61 PermissionSet::CreateDifference(existing.get(), permissions)); | 120 PermissionSet::CreateDifference(existing.get(), permissions)); |
62 scoped_refptr<PermissionSet> removed( | 121 scoped_refptr<PermissionSet> removed( |
63 PermissionSet::CreateDifference(existing.get(), total.get())); | 122 PermissionSet::CreateDifference(existing.get(), total.get())); |
64 | 123 |
65 // We update the active permissions, and not the granted permissions, because | 124 // We update the active permissions, and not the granted permissions, because |
66 // the extension, not the user, removed the permissions. This allows the | 125 // the extension, not the user, removed the permissions. This allows the |
67 // extension to add them again without prompting the user. | 126 // extension to add them again without prompting the user. |
68 SetActivePermissions(extension, total.get()); | 127 SetPermissions(extension, total, NULL); |
69 | 128 |
70 NotifyPermissionsUpdated(REMOVED, extension, removed.get()); | 129 NotifyPermissionsUpdated(REMOVED, extension, removed.get()); |
71 } | 130 } |
72 | 131 |
73 void PermissionsUpdater::GrantActivePermissions(const Extension* extension) { | 132 void PermissionsUpdater::GrantActivePermissions(const Extension* extension) { |
74 CHECK(extension); | 133 CHECK(extension); |
75 | 134 |
76 // We only maintain the granted permissions prefs for INTERNAL and LOAD | 135 // We only maintain the granted permissions prefs for INTERNAL and LOAD |
77 // extensions. | 136 // extensions. |
78 if (!Manifest::IsUnpackedLocation(extension->location()) && | 137 if (!Manifest::IsUnpackedLocation(extension->location()) && |
79 extension->location() != Manifest::INTERNAL) | 138 extension->location() != Manifest::INTERNAL) |
80 return; | 139 return; |
81 | 140 |
82 ExtensionPrefs::Get(browser_context_)->AddGrantedPermissions( | 141 ExtensionPrefs::Get(browser_context_)->AddGrantedPermissions( |
83 extension->id(), | 142 extension->id(), |
84 extension->permissions_data()->active_permissions().get()); | 143 extension->permissions_data()->active_permissions().get()); |
85 } | 144 } |
86 | 145 |
87 void PermissionsUpdater::InitializeActivePermissions( | 146 void PermissionsUpdater::InitializePermissions(const Extension* extension) { |
88 const Extension* extension) { | 147 scoped_refptr<const PermissionSet> bounded_active = |
89 // If the extension has used the optional permissions API, it will have a | 148 GetBoundedActivePermissions(extension, |
90 // custom set of active permissions defined in the extension prefs. Here, | 149 ExtensionPrefs::Get(browser_context_)); |
91 // we update the extension's active permissions based on the prefs. | |
92 scoped_refptr<PermissionSet> active_permissions = | |
93 ExtensionPrefs::Get(browser_context_)->GetActivePermissions( | |
94 extension->id()); | |
95 if (!active_permissions) | |
96 return; | |
97 | 150 |
98 // We restrict the active permissions to be within the bounds defined in the | 151 // We withhold permissions iff the switch to do so is enabled, the extension |
99 // extension's manifest. | 152 // shows up in chrome:extensions (so the user can grant withheld permissions), |
100 // a) active permissions must be a subset of optional + default permissions | 153 // the extension is not part of chrome or corporate policy, and also not on |
101 // b) active permissions must contains all default permissions | 154 // the scripting whitelist. Additionally, we don't withhold if the extension |
102 scoped_refptr<PermissionSet> total_permissions = PermissionSet::CreateUnion( | 155 // has the preference to allow scripting on all urls. |
103 PermissionsParser::GetRequiredPermissions(extension), | 156 bool should_withhold_permissions = |
104 PermissionsParser::GetOptionalPermissions(extension)); | 157 FeatureSwitch::scripts_require_action()->IsEnabled() && |
| 158 extension->ShouldDisplayInExtensionSettings() && |
| 159 !Manifest::IsPolicyLocation(extension->location()) && |
| 160 !Manifest::IsComponentLocation(extension->location()) && |
| 161 !PermissionsData::CanExecuteScriptEverywhere(extension) && |
| 162 !util::AllowedScriptingOnAllUrls(extension->id(), browser_context_); |
105 | 163 |
106 // Make sure the active permissions contain no more than optional + default. | 164 URLPatternSet granted_explicit_hosts; |
107 scoped_refptr<PermissionSet> adjusted_active = | 165 URLPatternSet withheld_explicit_hosts; |
108 PermissionSet::CreateIntersection(total_permissions, active_permissions); | 166 SegregateUrlPermissions(bounded_active->explicit_hosts(), |
| 167 should_withhold_permissions, |
| 168 &granted_explicit_hosts, |
| 169 &withheld_explicit_hosts); |
109 | 170 |
110 // Make sure the active permissions contain the default permissions. | 171 URLPatternSet granted_scriptable_hosts; |
111 adjusted_active = PermissionSet::CreateUnion( | 172 URLPatternSet withheld_scriptable_hosts; |
112 PermissionsParser::GetRequiredPermissions(extension), | 173 SegregateUrlPermissions(bounded_active->scriptable_hosts(), |
113 adjusted_active); | 174 should_withhold_permissions, |
| 175 &granted_scriptable_hosts, |
| 176 &withheld_scriptable_hosts); |
114 | 177 |
115 SetActivePermissions(extension, adjusted_active); | 178 bounded_active = new PermissionSet(bounded_active->apis(), |
| 179 bounded_active->manifest_permissions(), |
| 180 granted_explicit_hosts, |
| 181 granted_scriptable_hosts); |
| 182 |
| 183 scoped_refptr<const PermissionSet> withheld = |
| 184 new PermissionSet(APIPermissionSet(), |
| 185 ManifestPermissionSet(), |
| 186 withheld_explicit_hosts, |
| 187 withheld_scriptable_hosts); |
| 188 SetPermissions(extension, bounded_active, withheld); |
116 } | 189 } |
117 | 190 |
118 void PermissionsUpdater::SetActivePermissions( | 191 void PermissionsUpdater::WithholdImpliedAllHosts(const Extension* extension) { |
119 const Extension* extension, const PermissionSet* permissions) { | 192 scoped_refptr<const PermissionSet> active = |
| 193 extension->permissions_data()->active_permissions(); |
| 194 scoped_refptr<const PermissionSet> withheld = |
| 195 extension->permissions_data()->withheld_permissions(); |
| 196 |
| 197 URLPatternSet withheld_scriptable = withheld->scriptable_hosts(); |
| 198 URLPatternSet active_scriptable; |
| 199 SegregateUrlPermissions(active->scriptable_hosts(), |
| 200 true, // withhold permissions |
| 201 &active_scriptable, |
| 202 &withheld_scriptable); |
| 203 |
| 204 URLPatternSet withheld_explicit = withheld->explicit_hosts(); |
| 205 URLPatternSet active_explicit; |
| 206 SegregateUrlPermissions(active->explicit_hosts(), |
| 207 true, // withhold permissions |
| 208 &active_explicit, |
| 209 &withheld_explicit); |
| 210 |
| 211 SetPermissions(extension, |
| 212 new PermissionSet(active->apis(), |
| 213 active->manifest_permissions(), |
| 214 active_explicit, |
| 215 active_scriptable), |
| 216 new PermissionSet(withheld->apis(), |
| 217 withheld->manifest_permissions(), |
| 218 withheld_explicit, |
| 219 withheld_scriptable)); |
| 220 // TODO(rdevlin.cronin) We should notify the observers/renderer. |
| 221 } |
| 222 |
| 223 void PermissionsUpdater::GrantWithheldImpliedAllHosts( |
| 224 const Extension* extension) { |
| 225 scoped_refptr<const PermissionSet> active = |
| 226 extension->permissions_data()->active_permissions(); |
| 227 scoped_refptr<const PermissionSet> withheld = |
| 228 extension->permissions_data()->withheld_permissions(); |
| 229 |
| 230 // Move the all-hosts permission from withheld to active. |
| 231 // We can cheat a bit here since we know that the only host permission we |
| 232 // withhold is allhosts (or something similar enough to it), so we can just |
| 233 // grant all withheld host permissions. |
| 234 URLPatternSet explicit_hosts; |
| 235 URLPatternSet::CreateUnion( |
| 236 active->explicit_hosts(), withheld->explicit_hosts(), &explicit_hosts); |
| 237 URLPatternSet scriptable_hosts; |
| 238 URLPatternSet::CreateUnion(active->scriptable_hosts(), |
| 239 withheld->scriptable_hosts(), |
| 240 &scriptable_hosts); |
| 241 |
| 242 // Since we only withhold host permissions (so far), we know that withheld |
| 243 // permissions will be empty. |
| 244 SetPermissions(extension, |
| 245 new PermissionSet(active->apis(), |
| 246 active->manifest_permissions(), |
| 247 explicit_hosts, |
| 248 scriptable_hosts), |
| 249 new PermissionSet()); |
| 250 // TODO(rdevlin.cronin) We should notify the observers/renderer. |
| 251 } |
| 252 |
| 253 void PermissionsUpdater::SetPermissions( |
| 254 const Extension* extension, |
| 255 const scoped_refptr<const PermissionSet>& active, |
| 256 scoped_refptr<const PermissionSet> withheld) { |
| 257 withheld = withheld.get() ? withheld |
| 258 : extension->permissions_data()->withheld_permissions(); |
| 259 extension->permissions_data()->SetPermissions(active, withheld); |
120 ExtensionPrefs::Get(browser_context_)->SetActivePermissions( | 260 ExtensionPrefs::Get(browser_context_)->SetActivePermissions( |
121 extension->id(), permissions); | 261 extension->id(), active.get()); |
122 extension->permissions_data()->SetActivePermissions(permissions); | |
123 } | 262 } |
124 | 263 |
125 void PermissionsUpdater::DispatchEvent( | 264 void PermissionsUpdater::DispatchEvent( |
126 const std::string& extension_id, | 265 const std::string& extension_id, |
127 const char* event_name, | 266 const char* event_name, |
128 const PermissionSet* changed_permissions) { | 267 const PermissionSet* changed_permissions) { |
129 EventRouter* event_router = EventRouter::Get(browser_context_); | 268 EventRouter* event_router = EventRouter::Get(browser_context_); |
130 if (!event_router) | 269 if (!event_router) |
131 return; | 270 return; |
132 | 271 |
(...skipping 28 matching lines...) Expand all Loading... |
161 // Notify other APIs or interested parties. | 300 // Notify other APIs or interested parties. |
162 UpdatedExtensionPermissionsInfo info = UpdatedExtensionPermissionsInfo( | 301 UpdatedExtensionPermissionsInfo info = UpdatedExtensionPermissionsInfo( |
163 extension, changed, reason); | 302 extension, changed, reason); |
164 Profile* profile = Profile::FromBrowserContext(browser_context_); | 303 Profile* profile = Profile::FromBrowserContext(browser_context_); |
165 content::NotificationService::current()->Notify( | 304 content::NotificationService::current()->Notify( |
166 chrome::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED, | 305 chrome::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED, |
167 content::Source<Profile>(profile), | 306 content::Source<Profile>(profile), |
168 content::Details<UpdatedExtensionPermissionsInfo>(&info)); | 307 content::Details<UpdatedExtensionPermissionsInfo>(&info)); |
169 | 308 |
170 ExtensionMsg_UpdatePermissions_Params params; | 309 ExtensionMsg_UpdatePermissions_Params params; |
171 params.reason_id = static_cast<int>(reason); | |
172 params.extension_id = extension->id(); | 310 params.extension_id = extension->id(); |
173 params.apis = changed->apis(); | 311 params.active_permissions = ExtensionMsg_PermissionSetStruct( |
174 params.manifest_permissions = changed->manifest_permissions(); | 312 extension->permissions_data()->active_permissions()); |
175 params.explicit_hosts = changed->explicit_hosts(); | 313 params.withheld_permissions = ExtensionMsg_PermissionSetStruct( |
176 params.scriptable_hosts = changed->scriptable_hosts(); | 314 extension->permissions_data()->withheld_permissions()); |
177 | 315 |
178 // Send the new permissions to the renderers. | 316 // Send the new permissions to the renderers. |
179 for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator()); | 317 for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator()); |
180 !i.IsAtEnd(); i.Advance()) { | 318 !i.IsAtEnd(); i.Advance()) { |
181 RenderProcessHost* host = i.GetCurrentValue(); | 319 RenderProcessHost* host = i.GetCurrentValue(); |
182 if (profile->IsSameProfile( | 320 if (profile->IsSameProfile( |
183 Profile::FromBrowserContext(host->GetBrowserContext()))) { | 321 Profile::FromBrowserContext(host->GetBrowserContext()))) { |
184 host->Send(new ExtensionMsg_UpdatePermissions(params)); | 322 host->Send(new ExtensionMsg_UpdatePermissions(params)); |
185 } | 323 } |
186 } | 324 } |
187 | 325 |
188 // Trigger the onAdded and onRemoved events in the extension. | 326 // Trigger the onAdded and onRemoved events in the extension. |
189 DispatchEvent(extension->id(), event_name, changed); | 327 DispatchEvent(extension->id(), event_name, changed); |
190 } | 328 } |
191 | 329 |
192 } // namespace extensions | 330 } // namespace extensions |
OLD | NEW |