Home | History | Annotate | Download | only in extensions
      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/active_tab_permission_granter.h"
      6 
      7 #include "chrome/browser/extensions/active_script_controller.h"
      8 #include "chrome/browser/profiles/profile.h"
      9 #include "content/public/browser/navigation_details.h"
     10 #include "content/public/browser/navigation_entry.h"
     11 #include "content/public/browser/web_contents.h"
     12 #include "extensions/browser/extension_registry.h"
     13 #include "extensions/common/extension_messages.h"
     14 #include "extensions/common/permissions/permission_set.h"
     15 #include "extensions/common/permissions/permissions_data.h"
     16 #include "extensions/common/user_script.h"
     17 #include "url/gurl.h"
     18 
     19 using content::RenderProcessHost;
     20 using content::WebContentsObserver;
     21 
     22 namespace extensions {
     23 
     24 ActiveTabPermissionGranter::ActiveTabPermissionGranter(
     25     content::WebContents* web_contents,
     26     int tab_id,
     27     Profile* profile)
     28     : WebContentsObserver(web_contents),
     29       tab_id_(tab_id),
     30       extension_registry_observer_(this) {
     31   extension_registry_observer_.Add(ExtensionRegistry::Get(profile));
     32 }
     33 
     34 ActiveTabPermissionGranter::~ActiveTabPermissionGranter() {}
     35 
     36 void ActiveTabPermissionGranter::GrantIfRequested(const Extension* extension) {
     37   if (granted_extensions_.Contains(extension->id()))
     38     return;
     39 
     40   APIPermissionSet new_apis;
     41   URLPatternSet new_hosts;
     42 
     43   const PermissionsData* permissions_data = extension->permissions_data();
     44 
     45   // If the extension requires action for script execution, we grant it
     46   // active tab-style permissions, even if it doesn't have the activeTab
     47   // permission in the manifest.
     48   // We don't take tab id into account, because we want to know if the extension
     49   // should require active tab in general (not for the current tab).
     50   bool requires_action_for_script_execution =
     51       permissions_data->RequiresActionForScriptExecution(extension,
     52                                                          -1,  // No tab id.
     53                                                          GURL());
     54 
     55   if (extension->permissions_data()->HasAPIPermission(
     56           APIPermission::kActiveTab) ||
     57       requires_action_for_script_execution) {
     58     URLPattern pattern(UserScript::ValidUserScriptSchemes());
     59     // Pattern parsing could fail if this is an unsupported URL e.g. chrome://.
     60     if (pattern.Parse(web_contents()->GetURL().spec()) ==
     61             URLPattern::PARSE_SUCCESS) {
     62       new_hosts.AddPattern(pattern);
     63     }
     64     new_apis.insert(APIPermission::kTab);
     65   }
     66 
     67   if (extension->permissions_data()->HasAPIPermission(
     68           APIPermission::kTabCapture))
     69     new_apis.insert(APIPermission::kTabCaptureForTab);
     70 
     71   if (!new_apis.empty() || !new_hosts.is_empty()) {
     72     granted_extensions_.Insert(extension);
     73     scoped_refptr<const PermissionSet> new_permissions =
     74         new PermissionSet(new_apis, ManifestPermissionSet(),
     75                           new_hosts, URLPatternSet());
     76     permissions_data->UpdateTabSpecificPermissions(tab_id_, new_permissions);
     77     const content::NavigationEntry* navigation_entry =
     78         web_contents()->GetController().GetVisibleEntry();
     79     if (navigation_entry) {
     80       Send(new ExtensionMsg_UpdateTabSpecificPermissions(
     81           navigation_entry->GetPageID(),
     82           tab_id_,
     83           extension->id(),
     84           new_hosts));
     85       // If more things ever need to know about this, we should consider making
     86       // an observer class.
     87       // It's important that this comes after the IPC is sent to the renderer,
     88       // so that any tasks executing in the renderer occur after it has the
     89       // updated permissions.
     90       ActiveScriptController::GetForWebContents(web_contents())
     91           ->OnActiveTabPermissionGranted(extension);
     92     }
     93   }
     94 }
     95 
     96 void ActiveTabPermissionGranter::DidNavigateMainFrame(
     97     const content::LoadCommittedDetails& details,
     98     const content::FrameNavigateParams& params) {
     99   if (details.is_in_page)
    100     return;
    101   DCHECK(details.is_main_frame);  // important: sub-frames don't get granted!
    102   ClearActiveExtensionsAndNotify();
    103 }
    104 
    105 void ActiveTabPermissionGranter::WebContentsDestroyed() {
    106   ClearActiveExtensionsAndNotify();
    107 }
    108 
    109 void ActiveTabPermissionGranter::OnExtensionUnloaded(
    110     content::BrowserContext* browser_context,
    111     const Extension* extension,
    112     UnloadedExtensionInfo::Reason reason) {
    113   // Note: don't need to clear the permissions (nor tell the renderer about it)
    114   // because it's being unloaded anyway.
    115   granted_extensions_.Remove(extension->id());
    116 }
    117 
    118 void ActiveTabPermissionGranter::ClearActiveExtensionsAndNotify() {
    119   if (granted_extensions_.is_empty())
    120     return;
    121 
    122   std::vector<std::string> extension_ids;
    123 
    124   for (ExtensionSet::const_iterator it = granted_extensions_.begin();
    125        it != granted_extensions_.end(); ++it) {
    126     it->get()->permissions_data()->ClearTabSpecificPermissions(tab_id_);
    127     extension_ids.push_back((*it)->id());
    128   }
    129 
    130   Send(new ExtensionMsg_ClearTabSpecificPermissions(tab_id_, extension_ids));
    131   granted_extensions_.Clear();
    132 }
    133 
    134 }  // namespace extensions
    135