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 21namespace extensions { 22 23using api::permissions::Permissions; 24 25namespace Contains = api::permissions::Contains; 26namespace GetAll = api::permissions::GetAll; 27namespace Remove = api::permissions::Remove; 28namespace Request = api::permissions::Request; 29namespace helpers = permissions_api_helpers; 30 31namespace { 32 33const char kCantRemoveRequiredPermissionsError[] = 34 "You cannot remove required permissions."; 35const char kNotInOptionalPermissionsError[] = 36 "Optional permissions must be listed in extension manifest."; 37const char kNotWhitelistedError[] = 38 "The optional permissions API does not support '*'."; 39const char kUserGestureRequiredError[] = 40 "This function must be called during a user gesture"; 41 42enum AutoConfirmForTest { 43 DO_NOT_SKIP = 0, 44 PROCEED, 45 ABORT 46}; 47AutoConfirmForTest auto_confirm_for_tests = DO_NOT_SKIP; 48bool ignore_user_gesture_for_tests = false; 49 50} // namespace 51 52bool 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 extension()->permissions_data()->active_permissions()->Contains( 65 *permissions.get())); 66 return true; 67} 68 69bool PermissionsGetAllFunction::RunSync() { 70 scoped_ptr<Permissions> permissions = helpers::PackPermissionSet( 71 extension()->permissions_data()->active_permissions().get()); 72 results_ = GetAll::Results::Create(*permissions); 73 return true; 74} 75 76bool 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 // Make sure they're only trying to remove permissions supported by this API. 88 APIPermissionSet apis = permissions->apis(); 89 for (APIPermissionSet::const_iterator i = apis.begin(); 90 i != apis.end(); ++i) { 91 if (!i->info()->supports_optional()) { 92 error_ = ErrorUtils::FormatErrorMessage( 93 kNotWhitelistedError, i->name()); 94 return false; 95 } 96 } 97 98 // Make sure we don't remove any required pemissions. 99 scoped_refptr<const PermissionSet> required = 100 PermissionsParser::GetRequiredPermissions(extension()); 101 scoped_refptr<PermissionSet> intersection( 102 PermissionSet::CreateIntersection(permissions.get(), required.get())); 103 if (!intersection->IsEmpty()) { 104 error_ = kCantRemoveRequiredPermissionsError; 105 return false; 106 } 107 108 PermissionsUpdater(GetProfile()) 109 .RemovePermissions(extension(), permissions.get()); 110 results_ = Remove::Results::Create(true); 111 return true; 112} 113 114// static 115void PermissionsRequestFunction::SetAutoConfirmForTests(bool should_proceed) { 116 auto_confirm_for_tests = should_proceed ? PROCEED : ABORT; 117} 118 119// static 120void PermissionsRequestFunction::SetIgnoreUserGestureForTests( 121 bool ignore) { 122 ignore_user_gesture_for_tests = ignore; 123} 124 125PermissionsRequestFunction::PermissionsRequestFunction() {} 126 127void PermissionsRequestFunction::InstallUIProceed() { 128 PermissionsUpdater perms_updater(GetProfile()); 129 perms_updater.AddPermissions(extension(), requested_permissions_.get()); 130 131 results_ = Request::Results::Create(true); 132 SendResponse(true); 133 134 Release(); // Balanced in RunAsync(). 135} 136 137void PermissionsRequestFunction::InstallUIAbort(bool user_initiated) { 138 SendResponse(true); 139 140 Release(); // Balanced in RunAsync(). 141} 142 143PermissionsRequestFunction::~PermissionsRequestFunction() {} 144 145bool PermissionsRequestFunction::RunAsync() { 146 results_ = Request::Results::Create(false); 147 148 if (!user_gesture() && 149 !ignore_user_gesture_for_tests && 150 extension_->location() != Manifest::COMPONENT) { 151 error_ = kUserGestureRequiredError; 152 return false; 153 } 154 155 scoped_ptr<Request::Params> params(Request::Params::Create(*args_)); 156 EXTENSION_FUNCTION_VALIDATE(params); 157 158 requested_permissions_ = helpers::UnpackPermissionSet( 159 params->permissions, 160 ExtensionPrefs::Get(GetProfile())->AllowFileAccess(extension_->id()), 161 &error_); 162 if (!requested_permissions_.get()) 163 return false; 164 165 // Make sure they're only requesting permissions supported by this API. 166 APIPermissionSet apis = requested_permissions_->apis(); 167 for (APIPermissionSet::const_iterator i = apis.begin(); 168 i != apis.end(); ++i) { 169 if (!i->info()->supports_optional()) { 170 error_ = ErrorUtils::FormatErrorMessage( 171 kNotWhitelistedError, i->name()); 172 return false; 173 } 174 } 175 176 // The requested permissions must be defined as optional in the manifest. 177 if (!PermissionsParser::GetOptionalPermissions(extension()) 178 ->Contains(*requested_permissions_.get())) { 179 error_ = kNotInOptionalPermissionsError; 180 return false; 181 } 182 183 // We don't need to prompt the user if the requested permissions are a subset 184 // of the granted permissions set. 185 scoped_refptr<const PermissionSet> granted = 186 ExtensionPrefs::Get(GetProfile()) 187 ->GetGrantedPermissions(extension()->id()); 188 if (granted.get() && granted->Contains(*requested_permissions_.get())) { 189 PermissionsUpdater perms_updater(GetProfile()); 190 perms_updater.AddPermissions(extension(), requested_permissions_.get()); 191 results_ = Request::Results::Create(true); 192 SendResponse(true); 193 return true; 194 } 195 196 // Filter out the granted permissions so we only prompt for new ones. 197 requested_permissions_ = PermissionSet::CreateDifference( 198 requested_permissions_.get(), granted.get()); 199 200 AddRef(); // Balanced in InstallUIProceed() / InstallUIAbort(). 201 202 // We don't need to show the prompt if there are no new warnings, or if 203 // we're skipping the confirmation UI. All extension types but INTERNAL 204 // are allowed to silently increase their permission level. 205 bool has_no_warnings = PermissionMessageProvider::Get() 206 ->GetWarningMessages(requested_permissions_.get(), 207 extension()->GetType()) 208 .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, extension(), requested_permissions_.get()); 220 } 221 222 return true; 223} 224 225} // namespace extensions 226