blob: 9741d9b02e99c3c5377e9e30c0955f0ea9624175 [file] [log] [blame]
[email protected]c333e792012-01-06 16:57:391// 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
3// found in the LICENSE file.
4
5#include "chrome/browser/extensions/permissions_updater.h"
6
7#include "base/json/json_writer.h"
8#include "base/memory/ref_counted.h"
9#include "base/values.h"
[email protected]76aeb1772012-01-20 22:14:1610#include "chrome/browser/extensions/api/permissions/permissions_api_helpers.h"
[email protected]c333e792012-01-06 16:57:3911#include "chrome/browser/extensions/extension_event_router.h"
[email protected]c333e792012-01-06 16:57:3912#include "chrome/browser/extensions/extension_prefs.h"
13#include "chrome/browser/extensions/extension_service.h"
14#include "chrome/browser/profiles/profile.h"
[email protected]b70a2d92012-06-28 19:51:2115#include "chrome/browser/signin/token_service.h"
16#include "chrome/browser/signin/token_service_factory.h"
[email protected]15f08dd2012-01-27 07:29:4817#include "chrome/common/extensions/api/permissions.h"
[email protected]c333e792012-01-06 16:57:3918#include "chrome/common/chrome_notification_types.h"
19#include "chrome/common/extensions/extension.h"
20#include "chrome/common/extensions/extension_messages.h"
[email protected]b70a2d92012-06-28 19:51:2121#include "chrome/common/net/gaia/oauth2_mint_token_flow.h"
[email protected]c333e792012-01-06 16:57:3922#include "content/public/browser/notification_service.h"
23#include "content/public/browser/render_process_host.h"
24
25using content::RenderProcessHost;
[email protected]15f08dd2012-01-27 07:29:4826using extensions::permissions_api_helpers::PackPermissionSet;
[email protected]b70a2d92012-06-28 19:51:2127using extensions::PermissionSet;
[email protected]c333e792012-01-06 16:57:3928
29namespace extensions {
30
31namespace {
32
33const char kOnAdded[] = "permissions.onAdded";
34const char kOnRemoved[] = "permissions.onRemoved";
35
36}
37
38PermissionsUpdater::PermissionsUpdater(Profile* profile)
39 : profile_(profile) {}
40
41PermissionsUpdater::~PermissionsUpdater() {}
42
43void PermissionsUpdater::AddPermissions(
[email protected]c2e66e12012-06-27 06:27:0644 const Extension* extension, const PermissionSet* permissions) {
45 scoped_refptr<const PermissionSet> existing(
[email protected]c333e792012-01-06 16:57:3946 extension->GetActivePermissions());
[email protected]c2e66e12012-06-27 06:27:0647 scoped_refptr<PermissionSet> total(
48 PermissionSet::CreateUnion(existing, permissions));
49 scoped_refptr<PermissionSet> added(
50 PermissionSet::CreateDifference(total.get(), existing));
[email protected]c333e792012-01-06 16:57:3951
52 UpdateActivePermissions(extension, total.get());
53
54 // Update the granted permissions so we don't auto-disable the extension.
[email protected]b70a2d92012-06-28 19:51:2155 GrantActivePermissions(extension, false);
[email protected]c333e792012-01-06 16:57:3956
57 NotifyPermissionsUpdated(ADDED, extension, added.get());
58}
59
60void PermissionsUpdater::RemovePermissions(
[email protected]c2e66e12012-06-27 06:27:0661 const Extension* extension, const PermissionSet* permissions) {
62 scoped_refptr<const PermissionSet> existing(
[email protected]c333e792012-01-06 16:57:3963 extension->GetActivePermissions());
[email protected]c2e66e12012-06-27 06:27:0664 scoped_refptr<PermissionSet> total(
65 PermissionSet::CreateDifference(existing, permissions));
66 scoped_refptr<PermissionSet> removed(
67 PermissionSet::CreateDifference(existing, total.get()));
[email protected]c333e792012-01-06 16:57:3968
69 // We update the active permissions, and not the granted permissions, because
70 // the extension, not the user, removed the permissions. This allows the
71 // extension to add them again without prompting the user.
72 UpdateActivePermissions(extension, total.get());
73
74 NotifyPermissionsUpdated(REMOVED, extension, removed.get());
75}
76
[email protected]b70a2d92012-06-28 19:51:2177void PermissionsUpdater::GrantActivePermissions(const Extension* extension,
78 bool record_oauth2_grant) {
[email protected]c333e792012-01-06 16:57:3979 CHECK(extension);
80
[email protected]c24fb292012-02-01 22:52:1181 // We only maintain the granted permissions prefs for INTERNAL and LOAD
82 // extensions.
83 if (extension->location() != Extension::LOAD &&
84 extension->location() != Extension::INTERNAL)
[email protected]c333e792012-01-06 16:57:3985 return;
86
[email protected]d4a37f1c2012-07-09 21:36:1387 if (record_oauth2_grant)
[email protected]b70a2d92012-06-28 19:51:2188 RecordOAuth2Grant(extension);
[email protected]b70a2d92012-06-28 19:51:2189
[email protected]d4a37f1c2012-07-09 21:36:1390 GetExtensionPrefs()->AddGrantedPermissions(extension->id(),
91 extension->GetActivePermissions());
[email protected]f746b3f2012-07-03 17:53:3792}
93
[email protected]c333e792012-01-06 16:57:3994void PermissionsUpdater::UpdateActivePermissions(
[email protected]c2e66e12012-06-27 06:27:0695 const Extension* extension, const PermissionSet* permissions) {
[email protected]c333e792012-01-06 16:57:3996 GetExtensionPrefs()->SetActivePermissions(extension->id(), permissions);
97 extension->SetActivePermissions(permissions);
98}
99
[email protected]b70a2d92012-06-28 19:51:21100void PermissionsUpdater::RecordOAuth2Grant(const Extension* extension) {
101 TokenService* token_service = TokenServiceFactory::GetForProfile(profile_);
102 OAuth2MintTokenFlow* flow = new OAuth2MintTokenFlow(
103 profile_->GetRequestContext(), NULL, OAuth2MintTokenFlow::Parameters(
104 token_service->GetOAuth2LoginRefreshToken(),
105 extension->id(),
106 extension->oauth2_info().client_id,
107 extension->oauth2_info().scopes,
108 OAuth2MintTokenFlow::MODE_RECORD_GRANT));
109 // |flow| will delete itself.
110 flow->FireAndForget();
111}
112
[email protected]c333e792012-01-06 16:57:39113void PermissionsUpdater::DispatchEvent(
114 const std::string& extension_id,
115 const char* event_name,
[email protected]c2e66e12012-06-27 06:27:06116 const PermissionSet* changed_permissions) {
[email protected]c333e792012-01-06 16:57:39117 if (!profile_ || !profile_->GetExtensionEventRouter())
118 return;
119
120 ListValue value;
[email protected]15f08dd2012-01-27 07:29:48121 scoped_ptr<api::permissions::Permissions> permissions =
122 PackPermissionSet(changed_permissions);
[email protected]cfe484902012-02-15 14:52:32123 value.Append(permissions->ToValue().release());
[email protected]c333e792012-01-06 16:57:39124 std::string json_value;
[email protected]4abb4602012-03-16 01:59:55125 base::JSONWriter::Write(&value, &json_value);
[email protected]c333e792012-01-06 16:57:39126 profile_->GetExtensionEventRouter()->DispatchEventToExtension(
127 extension_id, event_name, json_value, profile_, GURL());
128}
129
130void PermissionsUpdater::NotifyPermissionsUpdated(
131 EventType event_type,
132 const Extension* extension,
[email protected]c2e66e12012-06-27 06:27:06133 const PermissionSet* changed) {
[email protected]c333e792012-01-06 16:57:39134 if (!changed || changed->IsEmpty())
135 return;
136
137 UpdatedExtensionPermissionsInfo::Reason reason;
138 const char* event_name = NULL;
139
140 if (event_type == REMOVED) {
141 reason = UpdatedExtensionPermissionsInfo::REMOVED;
142 event_name = kOnRemoved;
143 } else {
144 CHECK_EQ(ADDED, event_type);
145 reason = UpdatedExtensionPermissionsInfo::ADDED;
146 event_name = kOnAdded;
147 }
148
149 // Notify other APIs or interested parties.
150 UpdatedExtensionPermissionsInfo info = UpdatedExtensionPermissionsInfo(
151 extension, changed, reason);
152 content::NotificationService::current()->Notify(
153 chrome::NOTIFICATION_EXTENSION_PERMISSIONS_UPDATED,
154 content::Source<Profile>(profile_),
155 content::Details<UpdatedExtensionPermissionsInfo>(&info));
156
157 // Send the new permissions to the renderers.
158 for (RenderProcessHost::iterator i(RenderProcessHost::AllHostsIterator());
159 !i.IsAtEnd(); i.Advance()) {
160 RenderProcessHost* host = i.GetCurrentValue();
161 Profile* profile = Profile::FromBrowserContext(host->GetBrowserContext());
162 if (profile_->IsSameProfile(profile))
163 host->Send(new ExtensionMsg_UpdatePermissions(
164 static_cast<int>(reason),
165 extension->id(),
166 changed->apis(),
167 changed->explicit_hosts(),
168 changed->scriptable_hosts()));
169 }
170
171 // Trigger the onAdded and onRemoved events in the extension.
172 DispatchEvent(extension->id(), event_name, changed);
173}
174
175ExtensionPrefs* PermissionsUpdater::GetExtensionPrefs() {
176 return profile_->GetExtensionService()->extension_prefs();
177}
178
179} // namespace extensions