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/permissions_updater.h" 11 #include "chrome/browser/profiles/profile.h" 12 #include "chrome/common/extensions/api/permissions.h" 13 #include "extensions/browser/extension_prefs.h" 14 #include "extensions/common/error_utils.h" 15 #include "extensions/common/extension.h" 16 #include "extensions/common/manifest_handlers/permissions_parser.h" 17 #include "extensions/common/permissions/permission_message_provider.h" 18 #include "extensions/common/permissions/permissions_data.h" 19 #include "extensions/common/permissions/permissions_info.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::RunSync() { 53 scoped_ptr<Contains::Params> params(Contains::Params::Create(*args_)); 54 EXTENSION_FUNCTION_VALIDATE(params); 55 56 scoped_refptr<PermissionSet> permissions = helpers::UnpackPermissionSet( 57 params->permissions, 58 ExtensionPrefs::Get(GetProfile())->AllowFileAccess(extension_->id()), 59 &error_); 60 if (!permissions.get()) 61 return false; 62 63 results_ = Contains::Results::Create( 64 GetExtension()->permissions_data()->active_permissions()->Contains( 65 *permissions.get())); 66 return true; 67 } 68 69 bool PermissionsGetAllFunction::RunSync() { 70 scoped_ptr<Permissions> permissions = helpers::PackPermissionSet( 71 GetExtension()->permissions_data()->active_permissions().get()); 72 results_ = GetAll::Results::Create(*permissions); 73 return true; 74 } 75 76 bool PermissionsRemoveFunction::RunSync() { 77 scoped_ptr<Remove::Params> params(Remove::Params::Create(*args_)); 78 EXTENSION_FUNCTION_VALIDATE(params); 79 80 scoped_refptr<PermissionSet> permissions = helpers::UnpackPermissionSet( 81 params->permissions, 82 ExtensionPrefs::Get(GetProfile())->AllowFileAccess(extension_->id()), 83 &error_); 84 if (!permissions.get()) 85 return false; 86 87 const Extension* extension = GetExtension(); 88 89 // Make sure they're only trying to remove permissions supported by this API. 90 APIPermissionSet apis = permissions->apis(); 91 for (APIPermissionSet::const_iterator i = apis.begin(); 92 i != apis.end(); ++i) { 93 if (!i->info()->supports_optional()) { 94 error_ = ErrorUtils::FormatErrorMessage( 95 kNotWhitelistedError, i->name()); 96 return false; 97 } 98 } 99 100 // Make sure we don't remove any required pemissions. 101 scoped_refptr<const PermissionSet> required = 102 PermissionsParser::GetRequiredPermissions(extension); 103 scoped_refptr<PermissionSet> intersection( 104 PermissionSet::CreateIntersection(permissions.get(), required)); 105 if (!intersection->IsEmpty()) { 106 error_ = kCantRemoveRequiredPermissionsError; 107 return false; 108 } 109 110 PermissionsUpdater(GetProfile()) 111 .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(GetProfile()); 131 perms_updater.AddPermissions(GetExtension(), requested_permissions_.get()); 132 133 results_ = Request::Results::Create(true); 134 SendResponse(true); 135 136 Release(); // Balanced in RunAsync(). 137 } 138 139 void PermissionsRequestFunction::InstallUIAbort(bool user_initiated) { 140 SendResponse(true); 141 142 Release(); // Balanced in RunAsync(). 143 } 144 145 PermissionsRequestFunction::~PermissionsRequestFunction() {} 146 147 bool PermissionsRequestFunction::RunAsync() { 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_ = helpers::UnpackPermissionSet( 161 params->permissions, 162 ExtensionPrefs::Get(GetProfile())->AllowFileAccess(extension_->id()), 163 &error_); 164 if (!requested_permissions_.get()) 165 return false; 166 167 // Make sure they're only requesting permissions supported by this API. 168 APIPermissionSet apis = requested_permissions_->apis(); 169 for (APIPermissionSet::const_iterator i = apis.begin(); 170 i != apis.end(); ++i) { 171 if (!i->info()->supports_optional()) { 172 error_ = ErrorUtils::FormatErrorMessage( 173 kNotWhitelistedError, i->name()); 174 return false; 175 } 176 } 177 178 // The requested permissions must be defined as optional in the manifest. 179 if (!PermissionsParser::GetOptionalPermissions(GetExtension()) 180 ->Contains(*requested_permissions_)) { 181 error_ = kNotInOptionalPermissionsError; 182 return false; 183 } 184 185 // We don't need to prompt the user if the requested permissions are a subset 186 // of the granted permissions set. 187 scoped_refptr<const PermissionSet> granted = ExtensionPrefs::Get( 188 GetProfile())->GetGrantedPermissions(GetExtension()->id()); 189 if (granted.get() && granted->Contains(*requested_permissions_.get())) { 190 PermissionsUpdater perms_updater(GetProfile()); 191 perms_updater.AddPermissions(GetExtension(), requested_permissions_.get()); 192 results_ = Request::Results::Create(true); 193 SendResponse(true); 194 return true; 195 } 196 197 // Filter out the granted permissions so we only prompt for new ones. 198 requested_permissions_ = PermissionSet::CreateDifference( 199 requested_permissions_.get(), granted.get()); 200 201 AddRef(); // Balanced in InstallUIProceed() / InstallUIAbort(). 202 203 // We don't need to show the prompt if there are no new warnings, or if 204 // we're skipping the confirmation UI. All extension types but INTERNAL 205 // are allowed to silently increase their permission level. 206 bool has_no_warnings = 207 PermissionMessageProvider::Get()->GetWarningMessages( 208 requested_permissions_, GetExtension()->GetType()).empty(); 209 if (auto_confirm_for_tests == PROCEED || has_no_warnings || 210 extension_->location() == Manifest::COMPONENT) { 211 InstallUIProceed(); 212 } else if (auto_confirm_for_tests == ABORT) { 213 // Pretend the user clicked cancel. 214 InstallUIAbort(true); 215 } else { 216 CHECK_EQ(DO_NOT_SKIP, auto_confirm_for_tests); 217 install_ui_.reset(new ExtensionInstallPrompt(GetAssociatedWebContents())); 218 install_ui_->ConfirmPermissions( 219 this, GetExtension(), requested_permissions_.get()); 220 } 221 222 return true; 223 } 224 225 } // namespace extensions 226