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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/extensions/api/permissions/permissions_api.h" 6 7 #include "base/memory/scoped_ptr.h" 8 #include "chrome/browser/chrome_notification_types.h" 9 #include "chrome/browser/extensions/api/permissions/permissions_api_helpers.h" 10 #include "chrome/browser/extensions/extension_prefs.h" 11 #include "chrome/browser/extensions/permissions_updater.h" 12 #include "chrome/browser/profiles/profile.h" 13 #include "chrome/common/extensions/api/permissions.h" 14 #include "chrome/common/extensions/extension.h" 15 #include "chrome/common/extensions/permissions/permissions_data.h" 16 #include "chrome/common/extensions/permissions/permissions_info.h" 17 #include "extensions/common/error_utils.h" 18 #include "extensions/common/url_pattern_set.h" 19 #include "url/gurl.h" 20 21 namespace extensions { 22 23 using api::permissions::Permissions; 24 25 namespace Contains = api::permissions::Contains; 26 namespace GetAll = api::permissions::GetAll; 27 namespace Remove = api::permissions::Remove; 28 namespace Request = api::permissions::Request; 29 namespace helpers = permissions_api_helpers; 30 31 namespace { 32 33 const char kCantRemoveRequiredPermissionsError[] = 34 "You cannot remove required permissions."; 35 const char kNotInOptionalPermissionsError[] = 36 "Optional permissions must be listed in extension manifest."; 37 const char kNotWhitelistedError[] = 38 "The optional permissions API does not support '*'."; 39 const char kUserGestureRequiredError[] = 40 "This function must be called during a user gesture"; 41 42 enum AutoConfirmForTest { 43 DO_NOT_SKIP = 0, 44 PROCEED, 45 ABORT 46 }; 47 AutoConfirmForTest auto_confirm_for_tests = DO_NOT_SKIP; 48 bool ignore_user_gesture_for_tests = false; 49 50 } // namespace 51 52 bool PermissionsContainsFunction::RunImpl() { 53 scoped_ptr<Contains::Params> params(Contains::Params::Create(*args_)); 54 EXTENSION_FUNCTION_VALIDATE(params); 55 56 scoped_refptr<PermissionSet> permissions = 57 helpers::UnpackPermissionSet( 58 params->permissions, 59 ExtensionPrefs::Get(profile_)->AllowFileAccess(extension_->id()), 60 &error_); 61 if (!permissions.get()) 62 return false; 63 64 results_ = Contains::Results::Create( 65 GetExtension()->GetActivePermissions()->Contains(*permissions.get())); 66 return true; 67 } 68 69 bool PermissionsGetAllFunction::RunImpl() { 70 scoped_ptr<Permissions> permissions = 71 helpers::PackPermissionSet(GetExtension()->GetActivePermissions().get()); 72 results_ = GetAll::Results::Create(*permissions); 73 return true; 74 } 75 76 bool PermissionsRemoveFunction::RunImpl() { 77 scoped_ptr<Remove::Params> params(Remove::Params::Create(*args_)); 78 EXTENSION_FUNCTION_VALIDATE(params); 79 80 scoped_refptr<PermissionSet> permissions = 81 helpers::UnpackPermissionSet( 82 params->permissions, 83 ExtensionPrefs::Get(profile_)->AllowFileAccess(extension_->id()), 84 &error_); 85 if (!permissions.get()) 86 return false; 87 88 const Extension* extension = GetExtension(); 89 90 // Make sure they're only trying to remove permissions supported by this API. 91 APIPermissionSet apis = permissions->apis(); 92 for (APIPermissionSet::const_iterator i = apis.begin(); 93 i != apis.end(); ++i) { 94 if (!i->info()->supports_optional()) { 95 error_ = ErrorUtils::FormatErrorMessage( 96 kNotWhitelistedError, i->name()); 97 return false; 98 } 99 } 100 101 // Make sure we don't remove any required pemissions. 102 const PermissionSet* required = 103 PermissionsData::GetRequiredPermissions(extension); 104 scoped_refptr<PermissionSet> intersection( 105 PermissionSet::CreateIntersection(permissions.get(), required)); 106 if (!intersection->IsEmpty()) { 107 error_ = kCantRemoveRequiredPermissionsError; 108 return false; 109 } 110 111 PermissionsUpdater(profile()).RemovePermissions(extension, permissions.get()); 112 results_ = Remove::Results::Create(true); 113 return true; 114 } 115 116 // static 117 void PermissionsRequestFunction::SetAutoConfirmForTests(bool should_proceed) { 118 auto_confirm_for_tests = should_proceed ? PROCEED : ABORT; 119 } 120 121 // static 122 void PermissionsRequestFunction::SetIgnoreUserGestureForTests( 123 bool ignore) { 124 ignore_user_gesture_for_tests = ignore; 125 } 126 127 PermissionsRequestFunction::PermissionsRequestFunction() {} 128 129 void PermissionsRequestFunction::InstallUIProceed() { 130 PermissionsUpdater perms_updater(profile()); 131 perms_updater.AddPermissions(GetExtension(), requested_permissions_.get()); 132 133 results_ = Request::Results::Create(true); 134 SendResponse(true); 135 136 Release(); // Balanced in RunImpl(). 137 } 138 139 void PermissionsRequestFunction::InstallUIAbort(bool user_initiated) { 140 SendResponse(true); 141 142 Release(); // Balanced in RunImpl(). 143 } 144 145 PermissionsRequestFunction::~PermissionsRequestFunction() {} 146 147 bool PermissionsRequestFunction::RunImpl() { 148 results_ = Request::Results::Create(false); 149 150 if (!user_gesture() && 151 !ignore_user_gesture_for_tests && 152 extension_->location() != Manifest::COMPONENT) { 153 error_ = kUserGestureRequiredError; 154 return false; 155 } 156 157 scoped_ptr<Request::Params> params(Request::Params::Create(*args_)); 158 EXTENSION_FUNCTION_VALIDATE(params); 159 160 requested_permissions_ = 161 helpers::UnpackPermissionSet( 162 params->permissions, 163 ExtensionPrefs::Get(profile_)->AllowFileAccess(extension_->id()), 164 &error_); 165 if (!requested_permissions_.get()) 166 return false; 167 168 // Make sure they're only requesting permissions supported by this API. 169 APIPermissionSet apis = requested_permissions_->apis(); 170 for (APIPermissionSet::const_iterator i = apis.begin(); 171 i != apis.end(); ++i) { 172 if (!i->info()->supports_optional()) { 173 error_ = ErrorUtils::FormatErrorMessage( 174 kNotWhitelistedError, i->name()); 175 return false; 176 } 177 } 178 179 // Filter out permissions that do not need to be listed in the optional 180 // section of the manifest. 181 scoped_refptr<PermissionSet> manifest_required_requested_permissions = 182 PermissionSet::ExcludeNotInManifestPermissions( 183 requested_permissions_.get()); 184 185 // The requested permissions must be defined as optional in the manifest. 186 if (!PermissionsData::GetOptionalPermissions(GetExtension()) 187 ->Contains(*manifest_required_requested_permissions.get())) { 188 error_ = kNotInOptionalPermissionsError; 189 return false; 190 } 191 192 // We don't need to prompt the user if the requested permissions are a subset 193 // of the granted permissions set. 194 scoped_refptr<const PermissionSet> granted = 195 ExtensionPrefs::Get(profile_)-> 196 GetGrantedPermissions(GetExtension()->id()); 197 if (granted.get() && granted->Contains(*requested_permissions_.get())) { 198 PermissionsUpdater perms_updater(profile()); 199 perms_updater.AddPermissions(GetExtension(), requested_permissions_.get()); 200 results_ = Request::Results::Create(true); 201 SendResponse(true); 202 return true; 203 } 204 205 // Filter out the granted permissions so we only prompt for new ones. 206 requested_permissions_ = PermissionSet::CreateDifference( 207 requested_permissions_.get(), granted.get()); 208 209 AddRef(); // Balanced in InstallUIProceed() / InstallUIAbort(). 210 211 // We don't need to show the prompt if there are no new warnings, or if 212 // we're skipping the confirmation UI. All extension types but INTERNAL 213 // are allowed to silently increase their permission level. 214 bool has_no_warnings = requested_permissions_->GetWarningMessages( 215 GetExtension()->GetType()).empty(); 216 if (auto_confirm_for_tests == PROCEED || has_no_warnings || 217 extension_->location() == Manifest::COMPONENT) { 218 InstallUIProceed(); 219 } else if (auto_confirm_for_tests == ABORT) { 220 // Pretend the user clicked cancel. 221 InstallUIAbort(true); 222 } else { 223 CHECK_EQ(DO_NOT_SKIP, auto_confirm_for_tests); 224 install_ui_.reset(new ExtensionInstallPrompt(GetAssociatedWebContents())); 225 install_ui_->ConfirmPermissions( 226 this, GetExtension(), requested_permissions_.get()); 227 } 228 229 return true; 230 } 231 232 } // namespace extensions 233