mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-19 00:05:36 +00:00
Bug 1576407
: Part 3 - Return window opener as a WindowProxyHolder or BrowsingContext. r=farre
Also adds a legacy `GetSameProcessOpener()` method for callers which can only deal with in-process windows and may need to be updated for Fission. Differential Revision: https://phabricator.services.mozilla.com/D43692 --HG-- extra : source : 0ddbc451dcab431c2a1d934fa9baa5e8efc71545
This commit is contained in:
parent
fcd9f00395
commit
99bc492498
@ -16,6 +16,7 @@
|
|||||||
#include "nsError.h"
|
#include "nsError.h"
|
||||||
#include "nsContentSecurityManager.h"
|
#include "nsContentSecurityManager.h"
|
||||||
#include "nsDocShellLoadTypes.h"
|
#include "nsDocShellLoadTypes.h"
|
||||||
|
#include "nsGlobalWindowOuter.h"
|
||||||
#include "nsIInterfaceRequestor.h"
|
#include "nsIInterfaceRequestor.h"
|
||||||
#include "nsIMultiPartChannel.h"
|
#include "nsIMultiPartChannel.h"
|
||||||
|
|
||||||
@ -48,10 +49,11 @@ nsIInterfaceRequestor* MaybeCloseWindowHelper::MaybeCloseWindow() {
|
|||||||
if (mShouldCloseWindow) {
|
if (mShouldCloseWindow) {
|
||||||
// Reset the window context to the opener window so that the dependent
|
// Reset the window context to the opener window so that the dependent
|
||||||
// dialogs have a parent
|
// dialogs have a parent
|
||||||
nsCOMPtr<nsPIDOMWindowOuter> opener = window->GetOpener();
|
nsCOMPtr<nsPIDOMWindowOuter> opener =
|
||||||
|
nsGlobalWindowOuter::Cast(window)->GetSameProcessOpener();
|
||||||
|
|
||||||
if (opener && !opener->Closed()) {
|
if (opener && !opener->Closed()) {
|
||||||
mContentContext = do_GetInterface(opener);
|
mContentContext = do_QueryInterface(opener);
|
||||||
|
|
||||||
// Now close the old window. Do it on a timer so that we don't run
|
// Now close the old window. Do it on a timer so that we don't run
|
||||||
// into issues trying to close the window before it has fully opened.
|
// into issues trying to close the window before it has fully opened.
|
||||||
|
@ -14863,12 +14863,12 @@ void Document::MaybeAllowStorageForOpenerAfterUserInteraction() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsPIDOMWindowOuter> outer = inner->GetOuterWindow();
|
auto* outer = nsGlobalWindowOuter::Cast(inner->GetOuterWindow());
|
||||||
if (NS_WARN_IF(!outer)) {
|
if (NS_WARN_IF(!outer)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsPIDOMWindowOuter> outerOpener = outer->GetOpener();
|
nsCOMPtr<nsPIDOMWindowOuter> outerOpener = outer->GetSameProcessOpener();
|
||||||
if (!outerOpener) {
|
if (!outerOpener) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3034,20 +3034,23 @@ nsresult nsGlobalWindowInner::GetControllers(nsIControllers** aResult) {
|
|||||||
return rv.StealNSResult();
|
return rv.StealNSResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsPIDOMWindowOuter* nsGlobalWindowInner::GetOpenerWindow(ErrorResult& aError) {
|
Nullable<WindowProxyHolder> nsGlobalWindowInner::GetOpenerWindow(
|
||||||
|
ErrorResult& aError) {
|
||||||
FORWARD_TO_OUTER_OR_THROW(GetOpenerWindowOuter, (), aError, nullptr);
|
FORWARD_TO_OUTER_OR_THROW(GetOpenerWindowOuter, (), aError, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsGlobalWindowInner::GetOpener(JSContext* aCx,
|
void nsGlobalWindowInner::GetOpener(JSContext* aCx,
|
||||||
JS::MutableHandle<JS::Value> aRetval,
|
JS::MutableHandle<JS::Value> aRetval,
|
||||||
ErrorResult& aError) {
|
ErrorResult& aError) {
|
||||||
nsCOMPtr<nsPIDOMWindowOuter> opener = GetOpenerWindow(aError);
|
Nullable<WindowProxyHolder> opener = GetOpenerWindow(aError);
|
||||||
if (aError.Failed() || !opener) {
|
if (aError.Failed() || opener.IsNull()) {
|
||||||
aRetval.setNull();
|
aRetval.setNull();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
aError = nsContentUtils::WrapNative(aCx, opener, aRetval);
|
if (!ToJSValue(aCx, opener.Value(), aRetval)) {
|
||||||
|
aError.NoteJSContextException(aCx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsGlobalWindowInner::SetOpener(JSContext* aCx,
|
void nsGlobalWindowInner::SetOpener(JSContext* aCx,
|
||||||
|
@ -622,7 +622,8 @@ class nsGlobalWindowInner final : public mozilla::dom::EventTarget,
|
|||||||
void InitWasOffline();
|
void InitWasOffline();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
nsPIDOMWindowOuter* GetOpenerWindow(mozilla::ErrorResult& aError);
|
mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> GetOpenerWindow(
|
||||||
|
mozilla::ErrorResult& aError);
|
||||||
void GetOpener(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval,
|
void GetOpener(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval,
|
||||||
mozilla::ErrorResult& aError);
|
mozilla::ErrorResult& aError);
|
||||||
void SetOpener(JSContext* aCx, JS::Handle<JS::Value> aOpener,
|
void SetOpener(JSContext* aCx, JS::Handle<JS::Value> aOpener,
|
||||||
|
@ -3290,63 +3290,44 @@ nsresult nsGlobalWindowOuter::GetControllers(nsIControllers** aResult) {
|
|||||||
FORWARD_TO_INNER(GetControllers, (aResult), NS_ERROR_UNEXPECTED);
|
FORWARD_TO_INNER(GetControllers, (aResult), NS_ERROR_UNEXPECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsPIDOMWindowOuter* nsGlobalWindowOuter::GetSanitizedOpener(
|
already_AddRefed<BrowsingContext>
|
||||||
nsPIDOMWindowOuter* aOpener) {
|
nsGlobalWindowOuter::GetOpenerBrowsingContext() {
|
||||||
if (!aOpener) {
|
RefPtr<BrowsingContext> opener = GetBrowsingContext()->GetOpener();
|
||||||
|
MOZ_DIAGNOSTIC_ASSERT(!opener ||
|
||||||
|
opener->Group() == GetBrowsingContext()->Group());
|
||||||
|
if (!opener || opener->Group() != GetBrowsingContext()->Group()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsGlobalWindowOuter* win = nsGlobalWindowOuter::Cast(aOpener);
|
// Catch the case where we're chrome but the opener is not...
|
||||||
|
if (nsContentUtils::LegacyIsCallerChromeOrNativeCode() &&
|
||||||
// First, ensure that we're not handing back a chrome window to content:
|
GetPrincipal() == nsContentUtils::GetSystemPrincipal()) {
|
||||||
if (win->IsChromeWindow()) {
|
auto* openerWin = nsGlobalWindowOuter::Cast(opener->GetDOMWindow());
|
||||||
return nullptr;
|
if (!openerWin ||
|
||||||
}
|
openerWin->GetPrincipal() != nsContentUtils::GetSystemPrincipal()) {
|
||||||
|
return nullptr;
|
||||||
// We don't want to reveal the opener if the opener is a mail window,
|
|
||||||
// because opener can be used to spoof the contents of a message (bug 105050).
|
|
||||||
// So, we look in the opener's root docshell to see if it's a mail window.
|
|
||||||
nsCOMPtr<nsIDocShell> openerDocShell = aOpener->GetDocShell();
|
|
||||||
|
|
||||||
if (openerDocShell) {
|
|
||||||
nsCOMPtr<nsIDocShellTreeItem> openerRootItem;
|
|
||||||
openerDocShell->GetInProcessRootTreeItem(getter_AddRefs(openerRootItem));
|
|
||||||
nsCOMPtr<nsIDocShell> openerRootDocShell(do_QueryInterface(openerRootItem));
|
|
||||||
if (openerRootDocShell) {
|
|
||||||
nsIDocShell::AppType appType = openerRootDocShell->GetAppType();
|
|
||||||
if (appType != nsIDocShell::APP_TYPE_MAIL) {
|
|
||||||
return aOpener;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return opener.forget();
|
||||||
|
}
|
||||||
|
|
||||||
|
nsPIDOMWindowOuter* nsGlobalWindowOuter::GetSameProcessOpener() {
|
||||||
|
if (RefPtr<BrowsingContext> opener = GetOpenerBrowsingContext()) {
|
||||||
|
return opener->GetDOMWindow();
|
||||||
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsPIDOMWindowOuter* nsGlobalWindowOuter::GetOpenerWindowOuter() {
|
Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetOpenerWindowOuter() {
|
||||||
nsCOMPtr<nsPIDOMWindowOuter> opener = do_QueryReferent(mOpener);
|
if (RefPtr<BrowsingContext> opener = GetOpenerBrowsingContext()) {
|
||||||
|
return WindowProxyHolder(opener.forget());
|
||||||
if (!opener) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
return nullptr;
|
||||||
// First, check if we were called from a privileged chrome script
|
|
||||||
if (nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
|
|
||||||
// Catch the case where we're chrome but the opener is not...
|
|
||||||
if (GetPrincipal() == nsContentUtils::GetSystemPrincipal() &&
|
|
||||||
nsGlobalWindowOuter::Cast(opener)->GetPrincipal() !=
|
|
||||||
nsContentUtils::GetSystemPrincipal()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return opener;
|
|
||||||
}
|
|
||||||
|
|
||||||
return GetSanitizedOpener(opener);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
already_AddRefed<nsPIDOMWindowOuter> nsGlobalWindowOuter::GetOpener() {
|
Nullable<WindowProxyHolder> nsGlobalWindowOuter::GetOpener() {
|
||||||
nsCOMPtr<nsPIDOMWindowOuter> opener = GetOpenerWindowOuter();
|
return GetOpenerWindowOuter();
|
||||||
return opener.forget();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsGlobalWindowOuter::GetStatusOuter(nsAString& aStatus) {
|
void nsGlobalWindowOuter::GetStatusOuter(nsAString& aStatus) {
|
||||||
@ -4962,13 +4943,15 @@ void nsGlobalWindowOuter::FocusOuter() {
|
|||||||
|
|
||||||
nsCOMPtr<nsPIDOMWindowInner> caller = do_QueryInterface(GetEntryGlobal());
|
nsCOMPtr<nsPIDOMWindowInner> caller = do_QueryInterface(GetEntryGlobal());
|
||||||
nsPIDOMWindowOuter* callerOuter = caller ? caller->GetOuterWindow() : nullptr;
|
nsPIDOMWindowOuter* callerOuter = caller ? caller->GetOuterWindow() : nullptr;
|
||||||
nsCOMPtr<nsPIDOMWindowOuter> opener = GetOpener();
|
BrowsingContext* callerBC =
|
||||||
|
callerOuter ? callerOuter->GetBrowsingContext() : nullptr;
|
||||||
|
RefPtr<BrowsingContext> openerBC = GetOpenerBrowsingContext();
|
||||||
|
|
||||||
// Enforce dom.disable_window_flip (for non-chrome), but still allow the
|
// Enforce dom.disable_window_flip (for non-chrome), but still allow the
|
||||||
// window which opened us to raise us at times when popups are allowed
|
// window which opened us to raise us at times when popups are allowed
|
||||||
// (bugs 355482 and 369306).
|
// (bugs 355482 and 369306).
|
||||||
bool canFocus = CanSetProperty("dom.disable_window_flip") ||
|
bool canFocus = CanSetProperty("dom.disable_window_flip") ||
|
||||||
(opener == callerOuter &&
|
(openerBC == callerBC &&
|
||||||
RevisePopupAbuseLevel(PopupBlocker::GetPopupControlState()) <
|
RevisePopupAbuseLevel(PopupBlocker::GetPopupControlState()) <
|
||||||
PopupBlocker::openBlocked);
|
PopupBlocker::openBlocked);
|
||||||
|
|
||||||
@ -7771,11 +7754,11 @@ mozilla::dom::TabGroup* nsGlobalWindowOuter::TabGroupOuter() {
|
|||||||
// because a document is getting its NodePrincipal, and asking for the
|
// because a document is getting its NodePrincipal, and asking for the
|
||||||
// TabGroup to determine its DocGroup.
|
// TabGroup to determine its DocGroup.
|
||||||
if (!mTabGroup) {
|
if (!mTabGroup) {
|
||||||
// Get mOpener ourselves, instead of relying on GetOpenerWindowOuter,
|
// Get the opener ourselves, instead of relying on GetOpenerWindowOuter,
|
||||||
// because that way we dodge the LegacyIsCallerChromeOrNativeCode() call
|
// because that way we dodge the LegacyIsCallerChromeOrNativeCode() call
|
||||||
// which we want to return false.
|
// which we want to return false.
|
||||||
nsCOMPtr<nsPIDOMWindowOuter> piOpener = do_QueryReferent(mOpener);
|
RefPtr<BrowsingContext> openerBC = GetBrowsingContext()->GetOpener();
|
||||||
nsPIDOMWindowOuter* opener = GetSanitizedOpener(piOpener);
|
nsPIDOMWindowOuter* opener = openerBC ? openerBC->GetDOMWindow() : nullptr;
|
||||||
nsPIDOMWindowOuter* parent = GetInProcessScriptableParentOrNull();
|
nsPIDOMWindowOuter* parent = GetInProcessScriptableParentOrNull();
|
||||||
MOZ_ASSERT(!parent || !opener,
|
MOZ_ASSERT(!parent || !opener,
|
||||||
"Only one of parent and opener may be provided");
|
"Only one of parent and opener may be provided");
|
||||||
@ -7813,9 +7796,11 @@ mozilla::dom::TabGroup* nsGlobalWindowOuter::TabGroupOuter() {
|
|||||||
// Sanity check that our tabgroup matches our opener or parent.
|
// Sanity check that our tabgroup matches our opener or parent.
|
||||||
RefPtr<nsPIDOMWindowOuter> parent = GetInProcessScriptableParentOrNull();
|
RefPtr<nsPIDOMWindowOuter> parent = GetInProcessScriptableParentOrNull();
|
||||||
MOZ_ASSERT_IF(parent, parent->TabGroup() == mTabGroup);
|
MOZ_ASSERT_IF(parent, parent->TabGroup() == mTabGroup);
|
||||||
nsCOMPtr<nsPIDOMWindowOuter> piOpener = do_QueryReferent(mOpener);
|
|
||||||
nsPIDOMWindowOuter* opener = GetSanitizedOpener(piOpener);
|
RefPtr<BrowsingContext> openerBC = GetBrowsingContext()->GetOpener();
|
||||||
MOZ_ASSERT_IF(opener && nsGlobalWindowOuter::Cast(opener) != this,
|
nsPIDOMWindowOuter* opener =
|
||||||
|
openerBC ? openerBC->GetDOMWindow() : nullptr;
|
||||||
|
MOZ_ASSERT_IF(opener && Cast(opener) != this,
|
||||||
opener->TabGroup() == mTabGroup);
|
opener->TabGroup() == mTabGroup);
|
||||||
}
|
}
|
||||||
mIsValidatingTabGroup = false;
|
mIsValidatingTabGroup = false;
|
||||||
|
@ -550,14 +550,15 @@ class nsGlobalWindowOuter final : public mozilla::dom::EventTarget,
|
|||||||
RefPtr<mozilla::ThrottledEventQueue> mPostMessageEventQueue;
|
RefPtr<mozilla::ThrottledEventQueue> mPostMessageEventQueue;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
nsPIDOMWindowOuter* GetOpenerWindowOuter();
|
mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder>
|
||||||
|
GetOpenerWindowOuter();
|
||||||
// Initializes the mWasOffline member variable
|
// Initializes the mWasOffline member variable
|
||||||
void InitWasOffline();
|
void InitWasOffline();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
nsPIDOMWindowOuter* GetSanitizedOpener(nsPIDOMWindowOuter* aOpener);
|
nsPIDOMWindowOuter* GetSameProcessOpener();
|
||||||
|
already_AddRefed<mozilla::dom::BrowsingContext> GetOpenerBrowsingContext();
|
||||||
already_AddRefed<nsPIDOMWindowOuter> GetOpener() override;
|
mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> GetOpener() override;
|
||||||
mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> GetParentOuter();
|
mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder> GetParentOuter();
|
||||||
already_AddRefed<nsPIDOMWindowOuter> GetInProcessParent() override;
|
already_AddRefed<nsPIDOMWindowOuter> GetInProcessParent() override;
|
||||||
nsPIDOMWindowOuter* GetInProcessScriptableParent() override;
|
nsPIDOMWindowOuter* GetInProcessScriptableParent() override;
|
||||||
|
@ -1047,7 +1047,8 @@ class nsPIDOMWindowOuter : public mozIDOMWindowProxy {
|
|||||||
virtual nsresult GetPrompter(nsIPrompt** aPrompt) = 0;
|
virtual nsresult GetPrompter(nsIPrompt** aPrompt) = 0;
|
||||||
virtual nsresult GetControllers(nsIControllers** aControllers) = 0;
|
virtual nsresult GetControllers(nsIControllers** aControllers) = 0;
|
||||||
virtual already_AddRefed<mozilla::dom::Selection> GetSelection() = 0;
|
virtual already_AddRefed<mozilla::dom::Selection> GetSelection() = 0;
|
||||||
virtual already_AddRefed<nsPIDOMWindowOuter> GetOpener() = 0;
|
virtual mozilla::dom::Nullable<mozilla::dom::WindowProxyHolder>
|
||||||
|
GetOpener() = 0;
|
||||||
|
|
||||||
// aLoadState will be passed on through to the windowwatcher.
|
// aLoadState will be passed on through to the windowwatcher.
|
||||||
// aForceNoOpener will act just like a "noopener" feature in aOptions except
|
// aForceNoOpener will act just like a "noopener" feature in aOptions except
|
||||||
|
@ -2701,14 +2701,8 @@ nsresult WebSocketImpl::GetLoadingPrincipal(nsIPrincipal** aPrincipal) {
|
|||||||
|
|
||||||
// We are at the top. Let's see if we have an opener window.
|
// We are at the top. Let's see if we have an opener window.
|
||||||
if (innerWindow == currentInnerWindow) {
|
if (innerWindow == currentInnerWindow) {
|
||||||
ErrorResult error;
|
parentWindow = nsGlobalWindowOuter::Cast(innerWindow->GetOuterWindow())
|
||||||
parentWindow =
|
->GetSameProcessOpener();
|
||||||
nsGlobalWindowInner::Cast(innerWindow)->GetOpenerWindow(error);
|
|
||||||
if (NS_WARN_IF(error.Failed())) {
|
|
||||||
error.SuppressException();
|
|
||||||
return NS_ERROR_DOM_SECURITY_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!parentWindow) {
|
if (!parentWindow) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user