1 // Copyright 2014 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 #ifndef CHROME_BROWSER_EXTENSIONS_ACTIVE_SCRIPT_CONTROLLER_H_ 6 #define CHROME_BROWSER_EXTENSIONS_ACTIVE_SCRIPT_CONTROLLER_H_ 7 8 #include <map> 9 #include <set> 10 #include <string> 11 #include <vector> 12 13 #include "base/callback.h" 14 #include "base/compiler_specific.h" 15 #include "base/scoped_observer.h" 16 #include "content/public/browser/web_contents_observer.h" 17 #include "extensions/browser/extension_registry_observer.h" 18 #include "extensions/common/permissions/permissions_data.h" 19 #include "extensions/common/user_script.h" 20 21 namespace content { 22 class WebContents; 23 } 24 25 namespace IPC { 26 class Message; 27 } 28 29 class ExtensionAction; 30 31 namespace extensions { 32 class Extension; 33 class ExtensionRegistry; 34 35 // The provider for ExtensionActions corresponding to scripts which are actively 36 // running or need permission. 37 // TODO(rdevlin.cronin): This isn't really a controller, but it has good parity 38 // with LocationBar"Controller". 39 class ActiveScriptController : public content::WebContentsObserver, 40 public ExtensionRegistryObserver { 41 public: 42 explicit ActiveScriptController(content::WebContents* web_contents); 43 virtual ~ActiveScriptController(); 44 45 // Returns the ActiveScriptController for the given |web_contents|, or NULL 46 // if one does not exist. 47 static ActiveScriptController* GetForWebContents( 48 content::WebContents* web_contents); 49 50 // Notifies the ActiveScriptController that an extension has been granted 51 // active tab permissions. This will run any pending injections for that 52 // extension. 53 void OnActiveTabPermissionGranted(const Extension* extension); 54 55 // Notifies the ActiveScriptController of detected ad injection. 56 void OnAdInjectionDetected(const std::set<std::string>& ad_injectors); 57 58 // Adds the visible origin to |extension|'s active permissions, granting 59 // |extension| permission to always run script injections on the origin. 60 void AlwaysRunOnVisibleOrigin(const Extension* extension); 61 62 // Notifies the ActiveScriptController that the action for |extension| has 63 // been clicked, running any pending tasks that were previously shelved. 64 void OnClicked(const Extension* extension); 65 66 // Returns true if the given |extension| has a pending script that wants to 67 // run. 68 bool WantsToRun(const Extension* extension); 69 70 #if defined(UNIT_TEST) 71 // Only used in tests. RequiresUserConsentForScriptInjectionForTesting(const Extension * extension,UserScript::InjectionType type)72 PermissionsData::AccessType RequiresUserConsentForScriptInjectionForTesting( 73 const Extension* extension, 74 UserScript::InjectionType type) { 75 return RequiresUserConsentForScriptInjection(extension, type); 76 } RequestScriptInjectionForTesting(const Extension * extension,const base::Closure & callback)77 void RequestScriptInjectionForTesting(const Extension* extension, 78 const base::Closure& callback) { 79 return RequestScriptInjection(extension, callback); 80 } 81 #endif // defined(UNIT_TEST) 82 83 private: 84 typedef std::vector<base::Closure> PendingRequestList; 85 typedef std::map<std::string, PendingRequestList> PendingRequestMap; 86 87 // Returns true if the extension requesting script injection requires 88 // user consent. If this is true, the caller should then register a request 89 // via RequestScriptInjection(). 90 PermissionsData::AccessType RequiresUserConsentForScriptInjection( 91 const Extension* extension, 92 UserScript::InjectionType type); 93 94 // |callback|. The only assumption that can be made about when (or if) 95 // |callback| is run is that, if it is run, it will run on the current page. 96 void RequestScriptInjection(const Extension* extension, 97 const base::Closure& callback); 98 99 // Runs any pending injections for the corresponding extension. 100 void RunPendingForExtension(const Extension* extension); 101 102 // Handle the RequestScriptInjectionPermission message. 103 void OnRequestScriptInjectionPermission( 104 const std::string& extension_id, 105 UserScript::InjectionType script_type, 106 int64 request_id); 107 108 // Grants permission for the given request to run. 109 void PermitScriptInjection(int64 request_id); 110 111 // Log metrics. 112 void LogUMA() const; 113 114 // content::WebContentsObserver implementation. 115 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; 116 virtual void DidNavigateMainFrame( 117 const content::LoadCommittedDetails& details, 118 const content::FrameNavigateParams& params) OVERRIDE; 119 120 // ExtensionRegistryObserver: 121 virtual void OnExtensionUnloaded( 122 content::BrowserContext* browser_context, 123 const Extension* extension, 124 UnloadedExtensionInfo::Reason reason) OVERRIDE; 125 126 // Whether or not the ActiveScriptController is enabled (corresponding to the 127 // kActiveScriptEnforcement switch). If it is not, it acts as an empty shell, 128 // always allowing scripts to run and never displaying actions. 129 bool enabled_; 130 131 // The map of extension_id:pending_request of all pending requests. 132 PendingRequestMap pending_requests_; 133 134 // The extensions which have been granted permission to run on the given page. 135 // TODO(rdevlin.cronin): Right now, this just keeps track of extensions that 136 // have been permitted to run on the page via this interface. Instead, it 137 // should incorporate more fully with ActiveTab. 138 std::set<std::string> permitted_extensions_; 139 140 ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> 141 extension_registry_observer_; 142 143 DISALLOW_COPY_AND_ASSIGN(ActiveScriptController); 144 }; 145 146 } // namespace extensions 147 148 #endif // CHROME_BROWSER_EXTENSIONS_ACTIVE_SCRIPT_CONTROLLER_H_ 149