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