1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "mozilla/dom/TabContext.h"
8 #include "mozilla/dom/PTabContext.h"
9 #include "mozilla/dom/TabParent.h"
10 #include "mozilla/dom/TabChild.h"
11 #include "nsIAppsService.h"
12 #include "nsIScriptSecurityManager.h"
13 #include "nsServiceManagerUtils.h"
14
15 #define NO_APP_ID (nsIScriptSecurityManager::NO_APP_ID)
16
17 using namespace mozilla::dom::ipc;
18 using namespace mozilla::layout;
19
20 namespace mozilla {
21 namespace dom {
22
TabContext()23 TabContext::TabContext()
24 : mIsPrerendered(false)
25 , mInitialized(false)
26 , mIsMozBrowserElement(false)
27 , mContainingAppId(NO_APP_ID)
28 , mShowAccelerators(UIStateChangeType_NoChange)
29 , mShowFocusRings(UIStateChangeType_NoChange)
30 {
31 }
32
33 bool
IsMozBrowserElement() const34 TabContext::IsMozBrowserElement() const
35 {
36 return mIsMozBrowserElement;
37 }
38
39 bool
IsIsolatedMozBrowserElement() const40 TabContext::IsIsolatedMozBrowserElement() const
41 {
42 return mOriginAttributes.mInIsolatedMozBrowser;
43 }
44
45 bool
IsMozBrowserOrApp() const46 TabContext::IsMozBrowserOrApp() const
47 {
48 return HasOwnApp() || IsMozBrowserElement();
49 }
50
51 uint32_t
OwnAppId() const52 TabContext::OwnAppId() const
53 {
54 return mOriginAttributes.mAppId;
55 }
56
57 already_AddRefed<mozIApplication>
GetOwnApp() const58 TabContext::GetOwnApp() const
59 {
60 nsCOMPtr<mozIApplication> ownApp = mOwnApp;
61 return ownApp.forget();
62 }
63
64 bool
HasOwnApp() const65 TabContext::HasOwnApp() const
66 {
67 nsCOMPtr<mozIApplication> ownApp = GetOwnApp();
68 return !!ownApp;
69 }
70
71 uint32_t
BrowserOwnerAppId() const72 TabContext::BrowserOwnerAppId() const
73 {
74 if (IsMozBrowserElement()) {
75 return mContainingAppId;
76 }
77 return NO_APP_ID;
78 }
79
80 already_AddRefed<mozIApplication>
GetBrowserOwnerApp() const81 TabContext::GetBrowserOwnerApp() const
82 {
83 nsCOMPtr<mozIApplication> ownerApp;
84 if (IsMozBrowserElement()) {
85 ownerApp = mContainingApp;
86 }
87 return ownerApp.forget();
88 }
89
90 bool
HasBrowserOwnerApp() const91 TabContext::HasBrowserOwnerApp() const
92 {
93 nsCOMPtr<mozIApplication> ownerApp = GetBrowserOwnerApp();
94 return !!ownerApp;
95 }
96
97 uint32_t
AppOwnerAppId() const98 TabContext::AppOwnerAppId() const
99 {
100 if (HasOwnApp()) {
101 return mContainingAppId;
102 }
103 return NO_APP_ID;
104 }
105
106 already_AddRefed<mozIApplication>
GetAppOwnerApp() const107 TabContext::GetAppOwnerApp() const
108 {
109 nsCOMPtr<mozIApplication> ownerApp;
110 if (HasOwnApp()) {
111 ownerApp = mContainingApp;
112 }
113 return ownerApp.forget();
114 }
115
116 bool
HasAppOwnerApp() const117 TabContext::HasAppOwnerApp() const
118 {
119 nsCOMPtr<mozIApplication> ownerApp = GetAppOwnerApp();
120 return !!ownerApp;
121 }
122
123 uint32_t
OwnOrContainingAppId() const124 TabContext::OwnOrContainingAppId() const
125 {
126 if (HasOwnApp()) {
127 return mOriginAttributes.mAppId;
128 }
129
130 return mContainingAppId;
131 }
132
133 already_AddRefed<mozIApplication>
GetOwnOrContainingApp() const134 TabContext::GetOwnOrContainingApp() const
135 {
136 nsCOMPtr<mozIApplication> ownOrContainingApp;
137 if (HasOwnApp()) {
138 ownOrContainingApp = mOwnApp;
139 } else {
140 ownOrContainingApp = mContainingApp;
141 }
142
143 return ownOrContainingApp.forget();
144 }
145
146 bool
HasOwnOrContainingApp() const147 TabContext::HasOwnOrContainingApp() const
148 {
149 nsCOMPtr<mozIApplication> ownOrContainingApp = GetOwnOrContainingApp();
150 return !!ownOrContainingApp;
151 }
152
153 bool
SetTabContext(const TabContext & aContext)154 TabContext::SetTabContext(const TabContext& aContext)
155 {
156 NS_ENSURE_FALSE(mInitialized, false);
157
158 *this = aContext;
159 mInitialized = true;
160
161 return true;
162 }
163
164 void
SetPrivateBrowsingAttributes(bool aIsPrivateBrowsing)165 TabContext::SetPrivateBrowsingAttributes(bool aIsPrivateBrowsing)
166 {
167 mOriginAttributes.SyncAttributesWithPrivateBrowsing(aIsPrivateBrowsing);
168 }
169
170 bool
UpdateTabContextAfterSwap(const TabContext & aContext)171 TabContext::UpdateTabContextAfterSwap(const TabContext& aContext)
172 {
173 // This is only used after already initialized.
174 MOZ_ASSERT(mInitialized);
175
176 // The only permissable change is to `mIsMozBrowserElement`. All other fields
177 // must match for the change to be accepted.
178 if (aContext.OwnAppId() != OwnAppId() ||
179 aContext.mContainingAppId != mContainingAppId ||
180 aContext.mOriginAttributes != mOriginAttributes) {
181 return false;
182 }
183
184 mIsMozBrowserElement = aContext.mIsMozBrowserElement;
185 return true;
186 }
187
188 const DocShellOriginAttributes&
OriginAttributesRef() const189 TabContext::OriginAttributesRef() const
190 {
191 return mOriginAttributes;
192 }
193
194 const nsAString&
PresentationURL() const195 TabContext::PresentationURL() const
196 {
197 return mPresentationURL;
198 }
199
200 UIStateChangeType
ShowAccelerators() const201 TabContext::ShowAccelerators() const
202 {
203 return mShowAccelerators;
204 }
205
206 UIStateChangeType
ShowFocusRings() const207 TabContext::ShowFocusRings() const
208 {
209 return mShowFocusRings;
210 }
211
212 bool
SetTabContext(bool aIsMozBrowserElement,bool aIsPrerendered,mozIApplication * aOwnApp,mozIApplication * aAppFrameOwnerApp,UIStateChangeType aShowAccelerators,UIStateChangeType aShowFocusRings,const DocShellOriginAttributes & aOriginAttributes,const nsAString & aPresentationURL)213 TabContext::SetTabContext(bool aIsMozBrowserElement,
214 bool aIsPrerendered,
215 mozIApplication* aOwnApp,
216 mozIApplication* aAppFrameOwnerApp,
217 UIStateChangeType aShowAccelerators,
218 UIStateChangeType aShowFocusRings,
219 const DocShellOriginAttributes& aOriginAttributes,
220 const nsAString& aPresentationURL)
221 {
222 NS_ENSURE_FALSE(mInitialized, false);
223
224 // Get ids for both apps and only write to our member variables after we've
225 // verified that this worked.
226 uint32_t ownAppId = NO_APP_ID;
227 if (aOwnApp) {
228 nsresult rv = aOwnApp->GetLocalId(&ownAppId);
229 NS_ENSURE_SUCCESS(rv, false);
230 NS_ENSURE_TRUE(ownAppId != NO_APP_ID, false);
231 }
232
233 uint32_t containingAppId = NO_APP_ID;
234 if (aAppFrameOwnerApp) {
235 nsresult rv = aAppFrameOwnerApp->GetLocalId(&containingAppId);
236 NS_ENSURE_SUCCESS(rv, false);
237 NS_ENSURE_TRUE(containingAppId != NO_APP_ID, false);
238 }
239
240 // Veryify that app id matches mAppId passed in originAttributes
241 MOZ_RELEASE_ASSERT((aOwnApp && aOriginAttributes.mAppId == ownAppId) ||
242 (aAppFrameOwnerApp && aOriginAttributes.mAppId == containingAppId) ||
243 aOriginAttributes.mAppId == NO_APP_ID);
244
245 mInitialized = true;
246 mIsMozBrowserElement = aIsMozBrowserElement;
247 mIsPrerendered = aIsPrerendered;
248 mOriginAttributes = aOriginAttributes;
249 mContainingAppId = containingAppId;
250 mOwnApp = aOwnApp;
251 mContainingApp = aAppFrameOwnerApp;
252 mPresentationURL = aPresentationURL;
253 mShowAccelerators = aShowAccelerators;
254 mShowFocusRings = aShowFocusRings;
255 return true;
256 }
257
258 IPCTabContext
AsIPCTabContext() const259 TabContext::AsIPCTabContext() const
260 {
261 return IPCTabContext(FrameIPCTabContext(mOriginAttributes,
262 mContainingAppId,
263 mIsMozBrowserElement,
264 mIsPrerendered,
265 mPresentationURL,
266 mShowAccelerators,
267 mShowFocusRings));
268 }
269
270 static already_AddRefed<mozIApplication>
GetAppForId(uint32_t aAppId)271 GetAppForId(uint32_t aAppId)
272 {
273 nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
274 NS_ENSURE_TRUE(appsService, nullptr);
275
276 nsCOMPtr<mozIApplication> app;
277 appsService->GetAppByLocalId(aAppId, getter_AddRefs(app));
278
279 return app.forget();
280 }
281
MaybeInvalidTabContext(const IPCTabContext & aParams)282 MaybeInvalidTabContext::MaybeInvalidTabContext(const IPCTabContext& aParams)
283 : mInvalidReason(nullptr)
284 {
285 bool isMozBrowserElement = false;
286 bool isPrerendered = false;
287 uint32_t containingAppId = NO_APP_ID;
288 DocShellOriginAttributes originAttributes;
289 nsAutoString presentationURL;
290 UIStateChangeType showAccelerators = UIStateChangeType_NoChange;
291 UIStateChangeType showFocusRings = UIStateChangeType_NoChange;
292
293 switch(aParams.type()) {
294 case IPCTabContext::TPopupIPCTabContext: {
295 const PopupIPCTabContext &ipcContext = aParams.get_PopupIPCTabContext();
296
297 TabContext *context;
298 if (ipcContext.opener().type() == PBrowserOrId::TPBrowserParent) {
299 context = TabParent::GetFrom(ipcContext.opener().get_PBrowserParent());
300 if (!context) {
301 mInvalidReason = "Child is-browser process tried to "
302 "open a null tab.";
303 return;
304 }
305 if (context->IsMozBrowserElement() &&
306 !ipcContext.isMozBrowserElement()) {
307 // If the TabParent corresponds to a browser element, then it can only
308 // open other browser elements, for security reasons. We should have
309 // checked this before calling the TabContext constructor, so this is
310 // a fatal error.
311 mInvalidReason = "Child is-browser process tried to "
312 "open a non-browser tab.";
313 return;
314 }
315 } else if (ipcContext.opener().type() == PBrowserOrId::TPBrowserChild) {
316 context = static_cast<TabChild*>(ipcContext.opener().get_PBrowserChild());
317 } else if (ipcContext.opener().type() == PBrowserOrId::TTabId) {
318 // We should never get here because this PopupIPCTabContext is only
319 // used for allocating a new tab id, not for allocating a PBrowser.
320 mInvalidReason = "Child process tried to open an tab without the opener information.";
321 return;
322 } else {
323 // This should be unreachable because PopupIPCTabContext::opener is not a
324 // nullable field.
325 mInvalidReason = "PopupIPCTabContext::opener was null (?!).";
326 return;
327 }
328
329 // Browser elements can't nest other browser elements. So if
330 // our opener is browser element, we must be a new DOM window
331 // opened by it. In that case we inherit our containing app ID
332 // (if any).
333 //
334 // Otherwise, we're a new app window and we inherit from our
335 // opener app.
336 isMozBrowserElement = ipcContext.isMozBrowserElement();
337 originAttributes = context->mOriginAttributes;
338 if (isMozBrowserElement) {
339 containingAppId = context->OwnOrContainingAppId();
340 } else {
341 containingAppId = context->mContainingAppId;
342 }
343 break;
344 }
345 case IPCTabContext::TFrameIPCTabContext: {
346 const FrameIPCTabContext &ipcContext =
347 aParams.get_FrameIPCTabContext();
348
349 isMozBrowserElement = ipcContext.isMozBrowserElement();
350 isPrerendered = ipcContext.isPrerendered();
351 containingAppId = ipcContext.frameOwnerAppId();
352 presentationURL = ipcContext.presentationURL();
353 showAccelerators = ipcContext.showAccelerators();
354 showFocusRings = ipcContext.showFocusRings();
355 originAttributes = ipcContext.originAttributes();
356 break;
357 }
358 case IPCTabContext::TUnsafeIPCTabContext: {
359 // XXXcatalinb: This used *only* by ServiceWorkerClients::OpenWindow.
360 // It is meant as a temporary solution until service workers can
361 // provide a TabChild equivalent. Don't allow this on b2g since
362 // it might be used to escalate privileges.
363 #ifdef MOZ_B2G
364 mInvalidReason = "ServiceWorkerClients::OpenWindow is not supported.";
365 return;
366 #endif
367 if (!Preferences::GetBool("dom.serviceWorkers.enabled", false)) {
368 mInvalidReason = "ServiceWorkers should be enabled.";
369 return;
370 }
371
372 containingAppId = NO_APP_ID;
373 break;
374 }
375 default: {
376 MOZ_CRASH();
377 }
378 }
379
380 nsCOMPtr<mozIApplication> ownApp;
381 if (!isMozBrowserElement) {
382 // mAppId corresponds to OwnOrContainingAppId; if isMozBrowserElement is
383 // false then it's ownApp otherwise it's containingApp
384 ownApp = GetAppForId(originAttributes.mAppId);
385 if ((ownApp == nullptr) != (originAttributes.mAppId == NO_APP_ID)) {
386 mInvalidReason = "Got an ownAppId that didn't correspond to an app.";
387 return;
388 }
389 }
390
391 nsCOMPtr<mozIApplication> containingApp = GetAppForId(containingAppId);
392 if ((containingApp == nullptr) != (containingAppId == NO_APP_ID)) {
393 mInvalidReason = "Got a containingAppId that didn't correspond to an app.";
394 return;
395 }
396
397 bool rv;
398 rv = mTabContext.SetTabContext(isMozBrowserElement,
399 isPrerendered,
400 ownApp,
401 containingApp,
402 showAccelerators,
403 showFocusRings,
404 originAttributes,
405 presentationURL);
406 if (!rv) {
407 mInvalidReason = "Couldn't initialize TabContext.";
408 }
409 }
410
411 bool
IsValid()412 MaybeInvalidTabContext::IsValid()
413 {
414 return mInvalidReason == nullptr;
415 }
416
417 const char*
GetInvalidReason()418 MaybeInvalidTabContext::GetInvalidReason()
419 {
420 return mInvalidReason;
421 }
422
423 const TabContext&
GetTabContext()424 MaybeInvalidTabContext::GetTabContext()
425 {
426 if (!IsValid()) {
427 MOZ_CRASH("Can't GetTabContext() if !IsValid().");
428 }
429
430 return mTabContext;
431 }
432
433 } // namespace dom
434 } // namespace mozilla
435