Home | History | Annotate | Download | only in permissions
      1 // Copyright (c) 2013 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 "extensions/common/permissions/permissions_data.h"
      6 
      7 #include "base/command_line.h"
      8 #include "content/public/common/url_constants.h"
      9 #include "extensions/common/constants.h"
     10 #include "extensions/common/error_utils.h"
     11 #include "extensions/common/extensions_client.h"
     12 #include "extensions/common/manifest.h"
     13 #include "extensions/common/manifest_constants.h"
     14 #include "extensions/common/manifest_handlers/permissions_parser.h"
     15 #include "extensions/common/permissions/permission_message_provider.h"
     16 #include "extensions/common/switches.h"
     17 #include "extensions/common/url_pattern_set.h"
     18 #include "extensions/common/user_script.h"
     19 #include "url/gurl.h"
     20 #include "url/url_constants.h"
     21 
     22 namespace extensions {
     23 
     24 namespace {
     25 
     26 PermissionsData::PolicyDelegate* g_policy_delegate = NULL;
     27 
     28 }  // namespace
     29 
     30 PermissionsData::PermissionsData(const Extension* extension)
     31     : extension_id_(extension->id()), manifest_type_(extension->GetType()) {
     32   base::AutoLock auto_lock(runtime_lock_);
     33   scoped_refptr<const PermissionSet> required_permissions =
     34       PermissionsParser::GetRequiredPermissions(extension);
     35   active_permissions_unsafe_ =
     36       new PermissionSet(required_permissions->apis(),
     37                         required_permissions->manifest_permissions(),
     38                         required_permissions->explicit_hosts(),
     39                         required_permissions->scriptable_hosts());
     40   withheld_permissions_unsafe_ = new PermissionSet();
     41 }
     42 
     43 PermissionsData::~PermissionsData() {
     44 }
     45 
     46 // static
     47 void PermissionsData::SetPolicyDelegate(PolicyDelegate* delegate) {
     48   g_policy_delegate = delegate;
     49 }
     50 
     51 // static
     52 bool PermissionsData::CanSilentlyIncreasePermissions(
     53     const Extension* extension) {
     54   return extension->location() != Manifest::INTERNAL;
     55 }
     56 
     57 // static
     58 bool PermissionsData::CanExecuteScriptEverywhere(const Extension* extension) {
     59   if (extension->location() == Manifest::COMPONENT)
     60     return true;
     61 
     62   const ExtensionsClient::ScriptingWhitelist& whitelist =
     63       ExtensionsClient::Get()->GetScriptingWhitelist();
     64 
     65   return std::find(whitelist.begin(), whitelist.end(), extension->id()) !=
     66          whitelist.end();
     67 }
     68 
     69 bool PermissionsData::ShouldSkipPermissionWarnings(
     70     const std::string& extension_id) {
     71   // See http://b/4946060 for more details.
     72   return extension_id == std::string("nckgahadagoaajjgafhacjanaoiihapd");
     73 }
     74 
     75 // static
     76 bool PermissionsData::IsRestrictedUrl(const GURL& document_url,
     77                                       const GURL& top_frame_url,
     78                                       const Extension* extension,
     79                                       std::string* error) {
     80   if (extension && CanExecuteScriptEverywhere(extension))
     81     return false;
     82 
     83   // Check if the scheme is valid for extensions. If not, return.
     84   if (!URLPattern::IsValidSchemeForExtensions(document_url.scheme()) &&
     85       document_url.spec() != url::kAboutBlankURL) {
     86     if (error) {
     87       *error = ErrorUtils::FormatErrorMessage(
     88                    manifest_errors::kCannotAccessPage,
     89                    document_url.spec());
     90     }
     91     return true;
     92   }
     93 
     94   if (!ExtensionsClient::Get()->IsScriptableURL(document_url, error))
     95     return true;
     96 
     97   bool allow_on_chrome_urls = base::CommandLine::ForCurrentProcess()->HasSwitch(
     98                                   switches::kExtensionsOnChromeURLs);
     99   if (document_url.SchemeIs(content::kChromeUIScheme) &&
    100       !allow_on_chrome_urls) {
    101     if (error)
    102       *error = manifest_errors::kCannotAccessChromeUrl;
    103     return true;
    104   }
    105 
    106   if (extension && top_frame_url.SchemeIs(kExtensionScheme) &&
    107       top_frame_url.host() != extension->id() && !allow_on_chrome_urls) {
    108     if (error)
    109       *error = manifest_errors::kCannotAccessExtensionUrl;
    110     return true;
    111   }
    112 
    113   return false;
    114 }
    115 
    116 void PermissionsData::SetPermissions(
    117     const scoped_refptr<const PermissionSet>& active,
    118     const scoped_refptr<const PermissionSet>& withheld) const {
    119   base::AutoLock auto_lock(runtime_lock_);
    120   active_permissions_unsafe_ = active;
    121   withheld_permissions_unsafe_ = withheld;
    122 }
    123 
    124 void PermissionsData::UpdateTabSpecificPermissions(
    125     int tab_id,
    126     scoped_refptr<const PermissionSet> permissions) const {
    127   base::AutoLock auto_lock(runtime_lock_);
    128   CHECK_GE(tab_id, 0);
    129   TabPermissionsMap::iterator iter = tab_specific_permissions_.find(tab_id);
    130   if (iter == tab_specific_permissions_.end())
    131     tab_specific_permissions_[tab_id] = permissions;
    132   else
    133     iter->second =
    134         PermissionSet::CreateUnion(iter->second.get(), permissions.get());
    135 }
    136 
    137 void PermissionsData::ClearTabSpecificPermissions(int tab_id) const {
    138   base::AutoLock auto_lock(runtime_lock_);
    139   CHECK_GE(tab_id, 0);
    140   tab_specific_permissions_.erase(tab_id);
    141 }
    142 
    143 bool PermissionsData::HasAPIPermission(APIPermission::ID permission) const {
    144   return active_permissions()->HasAPIPermission(permission);
    145 }
    146 
    147 bool PermissionsData::HasAPIPermission(
    148     const std::string& permission_name) const {
    149   return active_permissions()->HasAPIPermission(permission_name);
    150 }
    151 
    152 bool PermissionsData::HasAPIPermissionForTab(
    153     int tab_id,
    154     APIPermission::ID permission) const {
    155   if (HasAPIPermission(permission))
    156     return true;
    157 
    158   scoped_refptr<const PermissionSet> tab_permissions =
    159       GetTabSpecificPermissions(tab_id);
    160 
    161   // Place autolock below the HasAPIPermission() and
    162   // GetTabSpecificPermissions(), since each already acquires the lock.
    163   base::AutoLock auto_lock(runtime_lock_);
    164   return tab_permissions.get() && tab_permissions->HasAPIPermission(permission);
    165 }
    166 
    167 bool PermissionsData::CheckAPIPermissionWithParam(
    168     APIPermission::ID permission,
    169     const APIPermission::CheckParam* param) const {
    170   return active_permissions()->CheckAPIPermissionWithParam(permission, param);
    171 }
    172 
    173 const URLPatternSet& PermissionsData::GetEffectiveHostPermissions() const {
    174   return active_permissions()->effective_hosts();
    175 }
    176 
    177 bool PermissionsData::HasHostPermission(const GURL& url) const {
    178   return active_permissions()->HasExplicitAccessToOrigin(url);
    179 }
    180 
    181 bool PermissionsData::HasEffectiveAccessToAllHosts() const {
    182   return active_permissions()->HasEffectiveAccessToAllHosts();
    183 }
    184 
    185 PermissionMessages PermissionsData::GetPermissionMessages() const {
    186   if (ShouldSkipPermissionWarnings(extension_id_)) {
    187     return PermissionMessages();
    188   } else {
    189     return PermissionMessageProvider::Get()->GetPermissionMessages(
    190         active_permissions().get(), manifest_type_);
    191   }
    192 }
    193 
    194 std::vector<base::string16> PermissionsData::GetPermissionMessageStrings()
    195     const {
    196   if (ShouldSkipPermissionWarnings(extension_id_))
    197     return std::vector<base::string16>();
    198   return PermissionMessageProvider::Get()->GetWarningMessages(
    199       active_permissions().get(), manifest_type_);
    200 }
    201 
    202 std::vector<base::string16>
    203 PermissionsData::GetPermissionMessageDetailsStrings() const {
    204   if (ShouldSkipPermissionWarnings(extension_id_))
    205     return std::vector<base::string16>();
    206   return PermissionMessageProvider::Get()->GetWarningMessagesDetails(
    207       active_permissions().get(), manifest_type_);
    208 }
    209 
    210 bool PermissionsData::HasWithheldImpliedAllHosts() const {
    211   // Since we currently only withhold all_hosts, it's sufficient to check
    212   // that either set is not empty.
    213   return !withheld_permissions()->explicit_hosts().is_empty() ||
    214          !withheld_permissions()->scriptable_hosts().is_empty();
    215 }
    216 
    217 bool PermissionsData::CanAccessPage(const Extension* extension,
    218                                     const GURL& document_url,
    219                                     const GURL& top_frame_url,
    220                                     int tab_id,
    221                                     int process_id,
    222                                     std::string* error) const {
    223   AccessType result = CanRunOnPage(extension,
    224                                    document_url,
    225                                    top_frame_url,
    226                                    tab_id,
    227                                    process_id,
    228                                    active_permissions()->explicit_hosts(),
    229                                    withheld_permissions()->explicit_hosts(),
    230                                    error);
    231   // TODO(rdevlin.cronin) Update callers so that they only need ACCESS_ALLOWED.
    232   return result == ACCESS_ALLOWED || result == ACCESS_WITHHELD;
    233 }
    234 
    235 PermissionsData::AccessType PermissionsData::GetPageAccess(
    236     const Extension* extension,
    237     const GURL& document_url,
    238     const GURL& top_frame_url,
    239     int tab_id,
    240     int process_id,
    241     std::string* error) const {
    242   return CanRunOnPage(extension,
    243                       document_url,
    244                       top_frame_url,
    245                       tab_id,
    246                       process_id,
    247                       active_permissions()->explicit_hosts(),
    248                       withheld_permissions()->explicit_hosts(),
    249                       error);
    250 }
    251 
    252 bool PermissionsData::CanRunContentScriptOnPage(const Extension* extension,
    253                                                 const GURL& document_url,
    254                                                 const GURL& top_frame_url,
    255                                                 int tab_id,
    256                                                 int process_id,
    257                                                 std::string* error) const {
    258   AccessType result = CanRunOnPage(extension,
    259                                    document_url,
    260                                    top_frame_url,
    261                                    tab_id,
    262                                    process_id,
    263                                    active_permissions()->scriptable_hosts(),
    264                                    withheld_permissions()->scriptable_hosts(),
    265                                    error);
    266   // TODO(rdevlin.cronin) Update callers so that they only need ACCESS_ALLOWED.
    267   return result == ACCESS_ALLOWED || result == ACCESS_WITHHELD;
    268 }
    269 
    270 PermissionsData::AccessType PermissionsData::GetContentScriptAccess(
    271     const Extension* extension,
    272     const GURL& document_url,
    273     const GURL& top_frame_url,
    274     int tab_id,
    275     int process_id,
    276     std::string* error) const {
    277   return CanRunOnPage(extension,
    278                       document_url,
    279                       top_frame_url,
    280                       tab_id,
    281                       process_id,
    282                       active_permissions()->scriptable_hosts(),
    283                       withheld_permissions()->scriptable_hosts(),
    284                       error);
    285 }
    286 
    287 bool PermissionsData::CanCaptureVisiblePage(int tab_id,
    288                                             std::string* error) const {
    289   const URLPattern all_urls(URLPattern::SCHEME_ALL,
    290                             URLPattern::kAllUrlsPattern);
    291 
    292   if (active_permissions()->explicit_hosts().ContainsPattern(all_urls))
    293     return true;
    294 
    295   if (tab_id >= 0) {
    296     scoped_refptr<const PermissionSet> tab_permissions =
    297         GetTabSpecificPermissions(tab_id);
    298     if (tab_permissions.get() &&
    299         tab_permissions->HasAPIPermission(APIPermission::kTab)) {
    300       return true;
    301     }
    302     if (error)
    303       *error = manifest_errors::kActiveTabPermissionNotGranted;
    304     return false;
    305   }
    306 
    307   if (error)
    308     *error = manifest_errors::kAllURLOrActiveTabNeeded;
    309   return false;
    310 }
    311 
    312 scoped_refptr<const PermissionSet> PermissionsData::GetTabSpecificPermissions(
    313     int tab_id) const {
    314   base::AutoLock auto_lock(runtime_lock_);
    315   CHECK_GE(tab_id, 0);
    316   TabPermissionsMap::const_iterator iter =
    317       tab_specific_permissions_.find(tab_id);
    318   return (iter != tab_specific_permissions_.end()) ? iter->second : NULL;
    319 }
    320 
    321 bool PermissionsData::HasTabSpecificPermissionToExecuteScript(
    322     int tab_id,
    323     const GURL& url) const {
    324   if (tab_id >= 0) {
    325     scoped_refptr<const PermissionSet> tab_permissions =
    326         GetTabSpecificPermissions(tab_id);
    327     if (tab_permissions.get() &&
    328         tab_permissions->explicit_hosts().MatchesSecurityOrigin(url)) {
    329       return true;
    330     }
    331   }
    332   return false;
    333 }
    334 
    335 PermissionsData::AccessType PermissionsData::CanRunOnPage(
    336     const Extension* extension,
    337     const GURL& document_url,
    338     const GURL& top_frame_url,
    339     int tab_id,
    340     int process_id,
    341     const URLPatternSet& permitted_url_patterns,
    342     const URLPatternSet& withheld_url_patterns,
    343     std::string* error) const {
    344   if (g_policy_delegate &&
    345       !g_policy_delegate->CanExecuteScriptOnPage(
    346           extension, document_url, top_frame_url, tab_id, process_id, error)) {
    347     return ACCESS_DENIED;
    348   }
    349 
    350   if (IsRestrictedUrl(document_url, top_frame_url, extension, error))
    351     return ACCESS_DENIED;
    352 
    353   if (HasTabSpecificPermissionToExecuteScript(tab_id, top_frame_url))
    354     return ACCESS_ALLOWED;
    355 
    356   if (permitted_url_patterns.MatchesURL(document_url))
    357     return ACCESS_ALLOWED;
    358 
    359   if (withheld_url_patterns.MatchesURL(document_url))
    360     return ACCESS_WITHHELD;
    361 
    362   if (error) {
    363     *error = ErrorUtils::FormatErrorMessage(manifest_errors::kCannotAccessPage,
    364                                             document_url.spec());
    365   }
    366   return ACCESS_DENIED;
    367 }
    368 
    369 }  // namespace extensions
    370