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
21namespace content {
22class WebContents;
23}
24
25namespace IPC {
26class Message;
27}
28
29class ExtensionAction;
30
31namespace extensions {
32class Extension;
33class 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".
39class 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.
72  PermissionsData::AccessType RequiresUserConsentForScriptInjectionForTesting(
73      const Extension* extension,
74      UserScript::InjectionType type) {
75    return RequiresUserConsentForScriptInjection(extension, type);
76  }
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