Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / extensions / renderer / user_script_set.cc
blob01e8a5a2e682887f24c136dc1fedaa99f7b6fc05
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.
5 #include "extensions/renderer/user_script_set.h"
7 #include "base/memory/ref_counted.h"
8 #include "content/public/common/url_constants.h"
9 #include "content/public/renderer/render_thread.h"
10 #include "extensions/common/extension.h"
11 #include "extensions/common/extension_set.h"
12 #include "extensions/common/extensions_client.h"
13 #include "extensions/common/permissions/permissions_data.h"
14 #include "extensions/renderer/extension_injection_host.h"
15 #include "extensions/renderer/extensions_renderer_client.h"
16 #include "extensions/renderer/injection_host.h"
17 #include "extensions/renderer/script_context.h"
18 #include "extensions/renderer/script_injection.h"
19 #include "extensions/renderer/user_script_injector.h"
20 #include "extensions/renderer/web_ui_injection_host.h"
21 #include "third_party/WebKit/public/web/WebDocument.h"
22 #include "third_party/WebKit/public/web/WebFrame.h"
23 #include "url/gurl.h"
25 namespace extensions {
27 namespace {
29 GURL GetDocumentUrlForFrame(blink::WebFrame* frame) {
30 GURL data_source_url = ScriptContext::GetDataSourceURLForFrame(frame);
31 if (!data_source_url.is_empty() && frame->isViewSourceModeEnabled()) {
32 data_source_url = GURL(content::kViewSourceScheme + std::string(":") +
33 data_source_url.spec());
36 return data_source_url;
39 } // namespace
41 UserScriptSet::UserScriptSet(const ExtensionSet* extensions)
42 : extensions_(extensions) {
45 UserScriptSet::~UserScriptSet() {
48 void UserScriptSet::AddObserver(Observer* observer) {
49 observers_.AddObserver(observer);
52 void UserScriptSet::RemoveObserver(Observer* observer) {
53 observers_.RemoveObserver(observer);
56 void UserScriptSet::GetActiveExtensionIds(
57 std::set<std::string>* ids) const {
58 for (ScopedVector<UserScript>::const_iterator iter = scripts_.begin();
59 iter != scripts_.end();
60 ++iter) {
61 if ((*iter)->host_id().type() != HostID::EXTENSIONS)
62 continue;
63 DCHECK(!(*iter)->extension_id().empty());
64 ids->insert((*iter)->extension_id());
68 void UserScriptSet::GetInjections(
69 ScopedVector<ScriptInjection>* injections,
70 blink::WebFrame* web_frame,
71 int tab_id,
72 UserScript::RunLocation run_location) {
73 GURL document_url = GetDocumentUrlForFrame(web_frame);
74 for (ScopedVector<UserScript>::const_iterator iter = scripts_.begin();
75 iter != scripts_.end();
76 ++iter) {
77 scoped_ptr<ScriptInjection> injection = GetInjectionForScript(
78 *iter,
79 web_frame,
80 tab_id,
81 run_location,
82 document_url,
83 false /* is_declarative */);
84 if (injection.get())
85 injections->push_back(injection.Pass());
89 bool UserScriptSet::UpdateUserScripts(base::SharedMemoryHandle shared_memory,
90 const std::set<HostID>& changed_hosts,
91 bool whitelisted_only) {
92 bool only_inject_incognito =
93 ExtensionsRendererClient::Get()->IsIncognitoProcess();
95 // Create the shared memory object (read only).
96 shared_memory_.reset(new base::SharedMemory(shared_memory, true));
97 if (!shared_memory_.get())
98 return false;
100 // First get the size of the memory block.
101 if (!shared_memory_->Map(sizeof(Pickle::Header)))
102 return false;
103 Pickle::Header* pickle_header =
104 reinterpret_cast<Pickle::Header*>(shared_memory_->memory());
106 // Now map in the rest of the block.
107 int pickle_size = sizeof(Pickle::Header) + pickle_header->payload_size;
108 shared_memory_->Unmap();
109 if (!shared_memory_->Map(pickle_size))
110 return false;
112 // Unpickle scripts.
113 size_t num_scripts = 0;
114 Pickle pickle(reinterpret_cast<char*>(shared_memory_->memory()), pickle_size);
115 PickleIterator iter(pickle);
116 CHECK(iter.ReadSizeT(&num_scripts));
118 scripts_.clear();
119 scripts_.reserve(num_scripts);
120 for (size_t i = 0; i < num_scripts; ++i) {
121 scoped_ptr<UserScript> script(new UserScript());
122 script->Unpickle(pickle, &iter);
124 // Note that this is a pointer into shared memory. We don't own it. It gets
125 // cleared up when the last renderer or browser process drops their
126 // reference to the shared memory.
127 for (size_t j = 0; j < script->js_scripts().size(); ++j) {
128 const char* body = NULL;
129 int body_length = 0;
130 CHECK(iter.ReadData(&body, &body_length));
131 script->js_scripts()[j].set_external_content(
132 base::StringPiece(body, body_length));
134 for (size_t j = 0; j < script->css_scripts().size(); ++j) {
135 const char* body = NULL;
136 int body_length = 0;
137 CHECK(iter.ReadData(&body, &body_length));
138 script->css_scripts()[j].set_external_content(
139 base::StringPiece(body, body_length));
142 if (only_inject_incognito && !script->is_incognito_enabled())
143 continue; // This script shouldn't run in an incognito tab.
145 const Extension* extension = extensions_->GetByID(script->extension_id());
146 if (whitelisted_only &&
147 (!extension ||
148 !PermissionsData::CanExecuteScriptEverywhere(extension))) {
149 continue;
152 scripts_.push_back(script.Pass());
155 FOR_EACH_OBSERVER(Observer,
156 observers_,
157 OnUserScriptsUpdated(changed_hosts, scripts_.get()));
158 return true;
161 scoped_ptr<ScriptInjection> UserScriptSet::GetDeclarativeScriptInjection(
162 int script_id,
163 blink::WebFrame* web_frame,
164 int tab_id,
165 UserScript::RunLocation run_location,
166 const GURL& document_url) {
167 for (ScopedVector<UserScript>::const_iterator it = scripts_.begin();
168 it != scripts_.end();
169 ++it) {
170 if ((*it)->id() == script_id) {
171 return GetInjectionForScript(*it,
172 web_frame,
173 tab_id,
174 run_location,
175 document_url,
176 true /* is_declarative */);
179 return scoped_ptr<ScriptInjection>();
182 // TODO(dcheng): Scripts can't be injected on a remote frame, so this function
183 // signature needs to be updated.
184 scoped_ptr<ScriptInjection> UserScriptSet::GetInjectionForScript(
185 UserScript* script,
186 blink::WebFrame* web_frame,
187 int tab_id,
188 UserScript::RunLocation run_location,
189 const GURL& document_url,
190 bool is_declarative) {
191 scoped_ptr<ScriptInjection> injection;
192 scoped_ptr<const InjectionHost> injection_host;
194 const HostID& host_id = script->host_id();
195 if (host_id.type() == HostID::EXTENSIONS) {
196 injection_host = ExtensionInjectionHost::Create(host_id.id(), extensions_);
197 if (!injection_host)
198 return injection.Pass();
199 } else {
200 DCHECK_EQ(host_id.type(), HostID::WEBUI);
201 injection_host.reset(new WebUIInjectionHost(host_id));
204 if (web_frame->parent() && !script->match_all_frames())
205 return injection.Pass(); // Only match subframes if the script declared it.
207 GURL effective_document_url = ScriptContext::GetEffectiveDocumentURL(
208 web_frame, document_url, script->match_about_blank());
210 if (!script->MatchesURL(effective_document_url))
211 return injection.Pass();
213 scoped_ptr<ScriptInjector> injector(new UserScriptInjector(script,
214 this,
215 is_declarative));
217 blink::WebFrame* top_frame = web_frame->top();
218 // It doesn't make sense to do script injection for remote frames, since they
219 // cannot host any documents or content.
220 // TODO(kalman): Fix this properly by moving all security checks into the
221 // browser. See http://crbug.com/466373 for ongoing work here.
222 if (top_frame->isWebRemoteFrame())
223 return injection.Pass();
225 if (injector->CanExecuteOnFrame(injection_host.get(), web_frame,
226 -1, // Content scripts are not tab-specific.
227 top_frame->document().url()) ==
228 PermissionsData::ACCESS_DENIED) {
229 return injection.Pass();
232 bool inject_css = !script->css_scripts().empty() &&
233 run_location == UserScript::DOCUMENT_START;
234 bool inject_js =
235 !script->js_scripts().empty() && script->run_location() == run_location;
236 if (inject_css || inject_js) {
237 injection.reset(new ScriptInjection(
238 injector.Pass(),
239 web_frame->toWebLocalFrame(),
240 injection_host.Pass(),
241 run_location,
242 tab_id));
244 return injection.Pass();
247 } // namespace extensions