WindowGlobalActor.cpp 8.71 KB
Newer Older
1
2
3
4
5
6
7
8
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "mozilla/dom/WindowGlobalActor.h"

9
#include "nsContentUtils.h"
10
#include "mozJSComponentLoader.h"
11
#include "mozilla/ContentBlockingAllowList.h"
12
#include "mozilla/Logging.h"
13
#include "mozilla/dom/JSActorService.h"
14
15
#include "mozilla/dom/JSWindowActorParent.h"
#include "mozilla/dom/JSWindowActorChild.h"
16
#include "mozilla/net/CookieJarSettings.h"
17
#include "mozilla/dom/nsMixedContentBlocker.h"
18
19
20
21

namespace mozilla {
namespace dom {

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// CORPP 3.1.3 https://mikewest.github.io/corpp/#integration-html
static nsILoadInfo::CrossOriginEmbedderPolicy InheritedPolicy(
    dom::BrowsingContext* aBrowsingContext) {
  WindowContext* inherit = aBrowsingContext->GetParentWindowContext();
  if (inherit) {
    return inherit->GetEmbedderPolicy();
  }

  RefPtr<dom::BrowsingContext> opener = aBrowsingContext->GetOpener();
  if (!opener) {
    return nsILoadInfo::EMBEDDER_POLICY_NULL;
  }
  // Bug 1637035: make sure we don't inherit a COEP for non-http,
  // non-initial-about:blank documents when we shouldn't be.
  inherit = opener->GetCurrentWindowContext();

  if (!inherit) {
    return nsILoadInfo::EMBEDDER_POLICY_NULL;
  }

  return inherit->GetEmbedderPolicy();
}

45
46
// Common WindowGlobalInit creation code used by both `AboutBlankInitializer`
// and `WindowInitializer`.
47
48
49
WindowGlobalInit WindowGlobalActor::BaseInitializer(
    dom::BrowsingContext* aBrowsingContext, uint64_t aInnerWindowId,
    uint64_t aOuterWindowId) {
50
51
52
53
54
55
56
57
  MOZ_DIAGNOSTIC_ASSERT(aBrowsingContext);

  WindowGlobalInit init;
  auto& ctx = init.context();
  ctx.mInnerWindowId = aInnerWindowId;
  ctx.mOuterWindowId = aOuterWindowId;
  ctx.mBrowsingContextId = aBrowsingContext->Id();

58
59
60
61
  // If any synced fields need to be initialized from our BrowsingContext, we
  // can initialize them here.
  mozilla::Get<WindowContext::IDX_EmbedderPolicy>(ctx.mFields) =
      InheritedPolicy(aBrowsingContext);
62
63
64
  return init;
}

65
66
WindowGlobalInit WindowGlobalActor::AboutBlankInitializer(
    dom::BrowsingContext* aBrowsingContext, nsIPrincipal* aPrincipal) {
67
68
69
  WindowGlobalInit init =
      BaseInitializer(aBrowsingContext, nsContentUtils::GenerateWindowId(),
                      nsContentUtils::GenerateWindowId());
70

71
72
73
74
75
76
77
  init.principal() = aPrincipal;
  Unused << NS_NewURI(getter_AddRefs(init.documentURI()), "about:blank");
  ContentBlockingAllowList::ComputePrincipal(
      aPrincipal, getter_AddRefs(init.contentBlockingAllowListPrincipal()));

  return init;
}
78

79
80
81
82
83
WindowGlobalInit WindowGlobalActor::WindowInitializer(
    nsGlobalWindowInner* aWindow) {
  WindowGlobalInit init =
      BaseInitializer(aWindow->GetBrowsingContext(), aWindow->WindowID(),
                      aWindow->GetOuterWindow()->WindowID());
84

85
86
87
88
  init.principal() = aWindow->GetPrincipal();
  init.contentBlockingAllowListPrincipal() =
      aWindow->GetDocumentContentBlockingAllowListPrincipal();
  init.documentURI() = aWindow->GetDocumentURI();
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
  Document* doc = aWindow->GetDocument();

  init.blockAllMixedContent() = doc->GetBlockAllMixedContent(false);
  init.upgradeInsecureRequests() = doc->GetUpgradeInsecureRequests(false);
  init.sandboxFlags() = doc->GetSandboxFlags();
  net::CookieJarSettings::Cast(doc->CookieJarSettings())
      ->Serialize(init.cookieJarSettings());
  init.httpsOnlyStatus() = doc->HttpsOnlyStatus();

  mozilla::Get<WindowContext::IDX_CookieBehavior>(init.context().mFields) =
      Some(doc->CookieJarSettings()->GetCookieBehavior());
  mozilla::Get<WindowContext::IDX_IsOnContentBlockingAllowList>(
      init.context().mFields) =
      doc->CookieJarSettings()->GetIsOnContentBlockingAllowList();
  mozilla::Get<WindowContext::IDX_IsThirdPartyWindow>(init.context().mFields) =
      nsContentUtils::IsThirdPartyWindowOrChannel(aWindow, nullptr, nullptr);
  mozilla::Get<WindowContext::IDX_IsThirdPartyTrackingResourceWindow>(
      init.context().mFields) =
      nsContentUtils::IsThirdPartyTrackingResourceWindow(aWindow);
  mozilla::Get<WindowContext::IDX_IsSecureContext>(init.context().mFields) =
      aWindow->IsSecureContext();

  auto policy = doc->GetEmbedderPolicyFromHTTP();
  if (policy.isSome()) {
    mozilla::Get<WindowContext::IDX_EmbedderPolicy>(init.context().mFields) =
        policy.ref();
  }

  // Init Mixed Content Fields
  nsCOMPtr<nsIURI> innerDocURI = NS_GetInnermostURI(doc->GetDocumentURI());
  if (innerDocURI) {
    mozilla::Get<WindowContext::IDX_IsSecure>(init.context().mFields) =
122
123
        innerDocURI->SchemeIs("https") ||
        nsMixedContentBlocker::IsPotentiallyTrustworthyOnion(innerDocURI);
124
125
126
127
128
129
130
131
132
133
134
  }
  nsCOMPtr<nsIChannel> mixedChannel;
  aWindow->GetDocShell()->GetMixedContentChannel(getter_AddRefs(mixedChannel));
  // A non null mixedContent channel on the docshell indicates,
  // that the user has overriden mixed content to allow mixed
  // content loads to happen.
  if (mixedChannel && (mixedChannel == doc->GetChannel())) {
    mozilla::Get<WindowContext::IDX_AllowMixedContent>(init.context().mFields) =
        true;
  }

135
136
137
138
139
140
141
142
  nsCOMPtr<nsITransportSecurityInfo> securityInfo;
  if (nsCOMPtr<nsIChannel> channel = doc->GetChannel()) {
    nsCOMPtr<nsISupports> securityInfoSupports;
    channel->GetSecurityInfo(getter_AddRefs(securityInfoSupports));
    securityInfo = do_QueryInterface(securityInfoSupports);
  }
  init.securityInfo() = securityInfo;

143
144
145
146
  // Most data here is specific to the Document, which can change without
  // creating a new WindowGlobal. Anything new added here which fits that
  // description should also be synchronized in
  // WindowGlobalChild::OnNewDocument.
147
  return init;
148
149
}

150
void WindowGlobalActor::ConstructActor(const nsACString& aName,
151
152
                                       JS::MutableHandleObject aActor,
                                       ErrorResult& aRv) {
153
154
  MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());

155
156
  JSActor::Type actorType = GetSide();
  MOZ_ASSERT_IF(actorType == JSActor::Type::Parent, XRE_IsParentProcess());
157
158
159
160
161
162
163

  // Constructing an actor requires a running script, so push an AutoEntryScript
  // onto the stack.
  AutoEntryScript aes(xpc::PrivilegedJunkScope(),
                      "WindowGlobalActor construction");
  JSContext* cx = aes.cx();

164
  RefPtr<JSActorService> actorSvc = JSActorService::GetSingleton();
165
  if (!actorSvc) {
166
    aRv.ThrowNotSupportedError("Could not acquire actor service");
167
168
169
    return;
  }

170
171
  RefPtr<JSWindowActorProtocol> proto =
      actorSvc->GetJSWindowActorProtocol(aName);
172
  if (!proto) {
173
174
175
    aRv.ThrowNotSupportedError(nsPrintfCString(
        "Could not get JSWindowActorProtocol: %s is not registered",
        PromiseFlatCString(aName).get()));
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
    return;
  }

  if (!proto->Matches(BrowsingContext(), GetDocumentURI(), GetRemoteType())) {
    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
    return;
  }

  // Load the module using mozJSComponentLoader.
  RefPtr<mozJSComponentLoader> loader = mozJSComponentLoader::Get();
  MOZ_ASSERT(loader);

  JS::RootedObject global(cx);
  JS::RootedObject exports(cx);

  const JSWindowActorProtocol::Sided* side;
192
  if (actorType == JSActor::Type::Parent) {
193
194
195
196
197
    side = &proto->Parent();
  } else {
    side = &proto->Child();
  }

198
199
200
  // Support basic functionally such as SendAsyncMessage and SendQuery for
  // unspecified moduleURI.
  if (!side->mModuleURI) {
201
202
    RefPtr<JSActor> actor;
    if (actorType == JSActor::Type::Parent) {
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
      actor = new JSWindowActorParent();
    } else {
      actor = new JSWindowActorChild();
    }

    JS::Rooted<JS::Value> wrapper(cx);
    if (!ToJSValue(cx, actor, &wrapper)) {
      aRv.NoteJSContextException(cx);
      return;
    }

    MOZ_ASSERT(wrapper.isObject());
    aActor.set(&wrapper.toObject());
    return;
  }

  aRv = loader->Import(cx, side->mModuleURI.ref(), &global, &exports);
220
221
222
223
224
225
226
227
  if (aRv.Failed()) {
    return;
  }

  MOZ_ASSERT(exports, "null exports!");

  // Load the specific property from our module.
  JS::RootedValue ctor(cx);
228
  nsAutoCString ctorName(aName);
229
230
231
  ctorName.Append(actorType == JSActor::Type::Parent
                      ? NS_LITERAL_CSTRING("Parent")
                      : NS_LITERAL_CSTRING("Child"));
232
  if (!JS_GetProperty(cx, exports, ctorName.get(), &ctor)) {
233
234
235
236
    aRv.NoteJSContextException(cx);
    return;
  }

237
238
  if (NS_WARN_IF(!ctor.isObject())) {
    nsPrintfCString message("Could not find actor constructor '%s'",
239
                            ctorName.get());
240
    aRv.ThrowNotFoundError(message);
241
242
243
    return;
  }

244
245
246
247
248
249
250
251
  // Invoke the constructor loaded from the module.
  if (!JS::Construct(cx, ctor, JS::HandleValueArray::empty(), aActor)) {
    aRv.NoteJSContextException(cx);
    return;
  }
}

}  // namespace dom
252
}  // namespace mozilla