summaryrefslogtreecommitdiff
path: root/chromium/extensions/renderer/script_context.h
blob: 585c6775183d436b8432054620c20a0357854c77 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef EXTENSIONS_RENDERER_SCRIPT_CONTEXT_H_
#define EXTENSIONS_RENDERER_SCRIPT_CONTEXT_H_

#include <memory>
#include <string>
#include <utility>
#include <vector>

#include "base/callback.h"
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/threading/thread_checker.h"
#include "base/unguessable_token.h"
#include "extensions/common/features/feature.h"
#include "extensions/common/mojom/api_permission_id.mojom-shared.h"
#include "extensions/common/permissions/api_permission_set.h"
#include "extensions/common/script_constants.h"
#include "extensions/renderer/module_system.h"
#include "extensions/renderer/safe_builtins.h"
#include "extensions/renderer/script_injection_callback.h"
#include "url/gurl.h"
#include "v8/include/v8.h"

namespace blink {
class WebDocumentLoader;
class WebLocalFrame;
}

namespace content {
class RenderFrame;
}

namespace extensions {
enum class CheckAliasStatus;
class Extension;

// Extensions wrapper for a v8::Context.
//
// v8::Contexts can be constructed on any thread, and must only be accessed or
// destroyed that thread.
//
// Note that ScriptContexts bound to worker threads will not have the full
// functionality as those bound to the main RenderThread.
class ScriptContext {
 public:
  using RunScriptExceptionHandler =
      base::OnceCallback<void(const v8::TryCatch&)>;

  ScriptContext(const v8::Local<v8::Context>& context,
                blink::WebLocalFrame* frame,
                const Extension* extension,
                Feature::Context context_type,
                const Extension* effective_extension,
                Feature::Context effective_context_type);
  ~ScriptContext();

  // Returns whether |url| from any Extension in |extension_set| is sandboxed,
  // as declared in each Extension's manifest.
  // TODO(kalman): Delete this when crbug.com/466373 is fixed.
  // See comment in HasAccessOrThrowError.
  static bool IsSandboxedPage(const GURL& url);

  // Initializes |module_system| and associates it with this context.
  void SetModuleSystem(std::unique_ptr<ModuleSystem> module_system);

  // Clears the WebLocalFrame for this contexts and invalidates the associated
  // ModuleSystem.
  void Invalidate();

  // Registers |observer| to be run when this context is invalidated. Closures
  // are run immediately when Invalidate() is called, not in a message loop.
  void AddInvalidationObserver(base::OnceClosure observer);

  // Returns true if this context is still valid, false if it isn't.
  // A context becomes invalid via Invalidate().
  bool is_valid() const { return is_valid_; }

  v8::Local<v8::Context> v8_context() const {
    return v8::Local<v8::Context>::New(isolate_, v8_context_);
  }

  const Extension* extension() const { return extension_.get(); }

  const Extension* effective_extension() const {
    return effective_extension_.get();
  }

  blink::WebLocalFrame* web_frame() const { return web_frame_; }

  Feature::Context context_type() const { return context_type_; }

  Feature::Context effective_context_type() const {
    return effective_context_type_;
  }

  const base::UnguessableToken& context_id() const { return context_id_; }

  ModuleSystem* module_system() { return module_system_.get(); }

  SafeBuiltins* safe_builtins() { return &safe_builtins_; }

  const SafeBuiltins* safe_builtins() const { return &safe_builtins_; }

  // Returns the ID of the extension associated with this context, or empty
  // string if there is no such extension.
  const std::string& GetExtensionID() const;

  // Returns the RenderFrame associated with this context. Can return NULL if
  // the context is in the process of being destroyed.
  content::RenderFrame* GetRenderFrame() const;

  // Safely calls the v8::Function, respecting the page load deferrer and
  // possibly executing asynchronously.
  // Doesn't catch exceptions; callers must do that if they want.
  // USE THESE METHODS RATHER THAN v8::Function::Call WHEREVER POSSIBLE.
  void SafeCallFunction(const v8::Local<v8::Function>& function,
                        int argc,
                        v8::Local<v8::Value> argv[]);
  void SafeCallFunction(const v8::Local<v8::Function>& function,
                        int argc,
                        v8::Local<v8::Value> argv[],
                        ScriptInjectionCallback::CompleteCallback callback);

  // Returns the availability of the API |api_name|.
  Feature::Availability GetAvailability(const std::string& api_name);
  // Returns the availability of the API |api_name|.
  // |check_alias| Whether API that has an alias that is available should be
  // considered available (even if the API itself is not available).
  Feature::Availability GetAvailability(const std::string& api_name,
                                        CheckAliasStatus check_alias);

  // Returns a string description of the type of context this is.
  std::string GetContextTypeDescription() const;

  // Returns a string description of the effective type of context this is.
  std::string GetEffectiveContextTypeDescription() const;

  v8::Isolate* isolate() const { return isolate_; }

  // Get the URL of this context's web frame.
  //
  // TODO(kalman): Remove this and replace with a GetOrigin() call which reads
  // of WebDocument::getSecurityOrigin():
  //  - The URL can change (e.g. pushState) but the origin cannot. Luckily it
  //    appears as though callers don't make security decisions based on the
  //    result of url() so it's not a problem... yet.
  //  - Origin is the correct check to be making.
  //  - It might let us remove the about:blank resolving?
  const GURL& url() const { return url_; }

  const GURL& service_worker_scope() const;

  int64_t service_worker_version_id() const {
    return service_worker_version_id_;
  }

  bool IsForServiceWorker() const;

  // Sets the URL of this ScriptContext. Usually this will automatically be set
  // on construction, unless this isn't constructed with enough information to
  // determine the URL (e.g. frame was null).
  // TODO(kalman): Make this a constructor parameter (as an origin).
  void set_url(const GURL& url) { url_ = url; }
  void set_service_worker_scope(const GURL& scope) {
    service_worker_scope_ = scope;
  }
  void set_service_worker_version_id(int64_t service_worker_version_id) {
    service_worker_version_id_ = service_worker_version_id;
  }

  // Returns whether the API |api| or any part of the API could be available in
  // this context without taking into account the context's extension.
  // |check_alias| Whether the API should be considered available if it has an
  // alias that is available.
  bool IsAnyFeatureAvailableToContext(const extensions::Feature& api,
                                      CheckAliasStatus check_alias);

  // Scope which maps a frame to a document loader. This is used by various
  // static methods below, which need to account for "just about to load"
  // document when retrieving URL.
  class ScopedFrameDocumentLoader {
   public:
    ScopedFrameDocumentLoader(blink::WebLocalFrame* frame,
                              blink::WebDocumentLoader* document_loader);
    ~ScopedFrameDocumentLoader();

   private:
    blink::WebLocalFrame* frame_;
    blink::WebDocumentLoader* document_loader_;
    DISALLOW_COPY_AND_ASSIGN(ScopedFrameDocumentLoader);
  };

  // TODO(devlin): Move all these Get*URL*() methods out of here? While they are
  // vaguely ScriptContext related, there's enough here that they probably
  // warrant another class or utility file.

  // Utility to get the URL we will match against for a frame. If the frame has
  // committed, this is the commited URL. Otherwise it is the provisional URL.
  // The returned URL may be invalid.
  static GURL GetDocumentLoaderURLForFrame(const blink::WebLocalFrame* frame);

  // Similar to GetDocumentLoaderURLForFrame, but only returns the data source
  // URL if the frame's document url is empty and the frame has a security
  // origin that allows access to the data source url.
  // TODO(asargent/devlin) - there may be places that should switch to using
  // this instead of GetDocumentLoaderURLForFrame.
  static GURL GetAccessCheckedFrameURL(const blink::WebLocalFrame* frame);

  // Used to determine the "effective" URL in context classification, such as to
  // associate an about:blank frame in an extension context with its extension.
  // If |document_url| is an about: or data: URL, returns the URL of the first
  // frame without an about: or data: URL that matches the initiator origin.
  // This may not be the immediate parent. Returns |document_url| if it is not
  // an about: URL, if |match_about_blank| is false, or if a suitable parent
  // cannot be found.
  // Will not check parent contexts that cannot be accessed (as is the case
  // for sandboxed frames).
  static GURL GetEffectiveDocumentURLForContext(blink::WebLocalFrame* frame,
                                                const GURL& document_url,
                                                bool match_about_blank);

  // Used to determine the "effective" URL for extension script injection.
  // If |document_url| is an about: or data: URL, returns the URL of the first
  // frame without an about: or data: URL that matches the initiator origin.
  // This may not be the immediate parent. Returns |document_url| if it is not
  // an about: or data: URL, if |match_origin_as_fallback| is set to not match,
  // or if a suitable parent cannot be found.
  // Considers parent contexts that cannot be accessed (as is the case for
  // sandboxed frames).
  static GURL GetEffectiveDocumentURLForInjection(
      blink::WebLocalFrame* frame,
      const GURL& document_url,
      MatchOriginAsFallbackBehavior match_origin_as_fallback);

  // Grants a set of content capabilities to this context.
  void set_content_capabilities(APIPermissionSet capabilities) {
    content_capabilities_ = std::move(capabilities);
  }

  // Indicates if this context has an effective API permission either by being
  // a context for an extension which has that permission, or by being a web
  // context which has been granted the corresponding capability by an
  // extension.
  bool HasAPIPermission(mojom::APIPermissionID permission) const;

  // Throws an Error in this context's JavaScript context, if this context does
  // not have access to |name|. Returns true if this context has access (i.e.
  // no exception thrown), false if it does not (i.e. an exception was thrown).
  bool HasAccessOrThrowError(const std::string& name);

  // Returns a string representation of this ScriptContext, for debugging.
  std::string GetDebugString() const;

  // Gets the current stack trace as a multi-line string to be logged.
  std::string GetStackTraceAsString() const;

  // Runs |code|, labelling the script that gets created as |name| (the name is
  // used in the devtools and stack traces). |exception_handler| will be called
  // re-entrantly if an exception is thrown during the script's execution.
  v8::Local<v8::Value> RunScript(
      v8::Local<v8::String> name,
      v8::Local<v8::String> code,
      RunScriptExceptionHandler exception_handler,
      v8::ScriptCompiler::NoCacheReason no_cache_reason =
          v8::ScriptCompiler::NoCacheReason::kNoCacheNoReason);

 private:
  // DEPRECATED.
  v8::Local<v8::Value> CallFunction(const v8::Local<v8::Function>& function,
                                    int argc,
                                    v8::Local<v8::Value> argv[]) const;

  // Whether this context is valid.
  bool is_valid_;

  // The v8 context the bindings are accessible to.
  v8::Global<v8::Context> v8_context_;

  // The WebLocalFrame associated with this context. This can be NULL because
  // this object can outlive is destroyed asynchronously.
  blink::WebLocalFrame* web_frame_;

  // The extension associated with this context, or NULL if there is none. This
  // might be a hosted app in the case that this context is hosting a web URL.
  scoped_refptr<const Extension> extension_;

  // The type of context.
  Feature::Context context_type_;

  // The effective extension associated with this context, or NULL if there is
  // none. This is different from the above extension if this context is in an
  // about:blank iframe for example.
  scoped_refptr<const Extension> effective_extension_;

  // The type of context.
  Feature::Context effective_context_type_;

  // A globally-unique ID for the script context.
  base::UnguessableToken context_id_;

  // Owns and structures the JS that is injected to set up extension bindings.
  std::unique_ptr<ModuleSystem> module_system_;

  // Contains safe copies of builtin objects like Function.prototype.
  SafeBuiltins safe_builtins_;

  // The set of capabilities granted to this context by extensions.
  APIPermissionSet content_capabilities_;

  // A list of base::OnceClosure instances as an observer interface for
  // invalidation.
  std::vector<base::OnceClosure> invalidate_observers_;

  v8::Isolate* isolate_;

  GURL url_;

  GURL service_worker_scope_;

  int64_t service_worker_version_id_;

  base::ThreadChecker thread_checker_;

  DISALLOW_COPY_AND_ASSIGN(ScriptContext);
};

}  // namespace extensions

#endif  // EXTENSIONS_RENDERER_SCRIPT_CONTEXT_H_