mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Bug 949488 - postMessage's targetOrigin argument should accept /, r=bholley
This commit is contained in:
parent
03c8eceaa0
commit
202e31a90e
@ -15,6 +15,7 @@
|
||||
#include "nsIScriptContext.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsJSUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -92,6 +93,25 @@ void DestroyScriptSettings()
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
// This mostly gets the entry global, but doesn't entirely match the spec in
|
||||
// certain edge cases. It's good enough for some purposes, but not others. If
|
||||
// you want to call this function, ping bholley and describe your use-case.
|
||||
nsIGlobalObject*
|
||||
BrokenGetEntryGlobal()
|
||||
{
|
||||
// We need the current JSContext in order to check the JS for
|
||||
// scripted frames that may have appeared since anyone last
|
||||
// manipulated the stack. If it's null, that means that there
|
||||
// must be no entry point on the stack.
|
||||
JSContext *cx = nsContentUtils::GetCurrentJSContextForThread();
|
||||
if (!cx) {
|
||||
MOZ_ASSERT(ScriptSettingsStack::Ref().EntryPoint() == nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return nsJSUtils::GetDynamicScriptGlobal(cx);
|
||||
}
|
||||
|
||||
// Note: When we're ready to expose it, GetEntryGlobal will look similar to
|
||||
// GetIncumbentGlobal below.
|
||||
|
||||
|
@ -27,6 +27,11 @@ namespace dom {
|
||||
void InitScriptSettings();
|
||||
void DestroyScriptSettings();
|
||||
|
||||
// This mostly gets the entry global, but doesn't entirely match the spec in
|
||||
// certain edge cases. It's good enough for some purposes, but not others. If
|
||||
// you want to call this function, ping bholley and describe your use-case.
|
||||
nsIGlobalObject* BrokenGetEntryGlobal();
|
||||
|
||||
// Note: We don't yet expose GetEntryGlobal, because in order for it to be
|
||||
// correct, we first need to replace a bunch of explicit cx pushing in the
|
||||
// browser with AutoEntryScript. But GetIncumbentGlobal is simpler, because it
|
||||
|
@ -84,6 +84,7 @@ UNIFIED_SOURCES += [
|
||||
'nsFocusManager.cpp',
|
||||
'nsGlobalWindowCommands.cpp',
|
||||
'nsHistory.cpp',
|
||||
'nsIGlobalObject.cpp',
|
||||
'nsJSTimeoutHandler.cpp',
|
||||
'nsJSUtils.cpp',
|
||||
'nsLocation.cpp',
|
||||
|
@ -7493,14 +7493,14 @@ class PostMessageEvent : public nsRunnable
|
||||
PostMessageEvent(nsGlobalWindow* aSource,
|
||||
const nsAString& aCallerOrigin,
|
||||
nsGlobalWindow* aTargetWindow,
|
||||
nsIURI* aProvidedOrigin,
|
||||
nsIPrincipal* aProvidedPrincipal,
|
||||
bool aTrustedCaller)
|
||||
: mSource(aSource),
|
||||
mCallerOrigin(aCallerOrigin),
|
||||
mMessage(nullptr),
|
||||
mMessageLen(0),
|
||||
mTargetWindow(aTargetWindow),
|
||||
mProvidedOrigin(aProvidedOrigin),
|
||||
mProvidedPrincipal(aProvidedPrincipal),
|
||||
mTrustedCaller(aTrustedCaller)
|
||||
{
|
||||
MOZ_COUNT_CTOR(PostMessageEvent);
|
||||
@ -7530,7 +7530,7 @@ class PostMessageEvent : public nsRunnable
|
||||
uint64_t* mMessage;
|
||||
size_t mMessageLen;
|
||||
nsRefPtr<nsGlobalWindow> mTargetWindow;
|
||||
nsCOMPtr<nsIURI> mProvidedOrigin;
|
||||
nsCOMPtr<nsIPrincipal> mProvidedPrincipal;
|
||||
bool mTrustedCaller;
|
||||
nsTArray<nsCOMPtr<nsISupports> > mSupportsArray;
|
||||
};
|
||||
@ -7699,32 +7699,22 @@ PostMessageEvent::Run()
|
||||
// intercept messages intended for another site by carefully timing navigation
|
||||
// of the target window so it changed location after postMessage but before
|
||||
// now.
|
||||
if (mProvidedOrigin) {
|
||||
if (mProvidedPrincipal) {
|
||||
// Get the target's origin either from its principal or, in the case the
|
||||
// principal doesn't carry a URI (e.g. the system principal), the target's
|
||||
// document.
|
||||
nsIPrincipal* targetPrin = targetWindow->GetPrincipal();
|
||||
if (!targetPrin)
|
||||
if (NS_WARN_IF(!targetPrin))
|
||||
return NS_OK;
|
||||
nsCOMPtr<nsIURI> targetURI;
|
||||
if (NS_FAILED(targetPrin->GetURI(getter_AddRefs(targetURI))))
|
||||
return NS_OK;
|
||||
if (!targetURI) {
|
||||
targetURI = targetWindow->mDoc->GetDocumentURI();
|
||||
if (!targetURI)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Note: This is contrary to the spec with respect to file: URLs, which
|
||||
// the spec groups into a single origin, but given we intentionally
|
||||
// don't do that in other places it seems better to hold the line for
|
||||
// now. Long-term, we want HTML5 to address this so that we can
|
||||
// be compliant while being safer.
|
||||
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
||||
nsresult rv =
|
||||
ssm->CheckSameOriginURI(mProvidedOrigin, targetURI, true);
|
||||
if (NS_FAILED(rv))
|
||||
if (!targetPrin->EqualsIgnoringDomain(mProvidedPrincipal)) {
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Deserialize the structured clone data
|
||||
@ -7857,15 +7847,47 @@ nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
}
|
||||
|
||||
// Convert the provided origin string into a URI for comparison purposes.
|
||||
nsCOMPtr<nsIPrincipal> providedPrincipal;
|
||||
|
||||
if (aTargetOrigin.EqualsASCII("/")) {
|
||||
providedPrincipal = BrokenGetEntryGlobal()->PrincipalOrNull();
|
||||
if (NS_WARN_IF(!providedPrincipal))
|
||||
return;
|
||||
}
|
||||
|
||||
// "*" indicates no specific origin is required.
|
||||
nsCOMPtr<nsIURI> providedOrigin;
|
||||
if (!aTargetOrigin.EqualsASCII("*")) {
|
||||
if (NS_FAILED(NS_NewURI(getter_AddRefs(providedOrigin), aTargetOrigin))) {
|
||||
else if (!aTargetOrigin.EqualsASCII("*")) {
|
||||
nsCOMPtr<nsIURI> originURI;
|
||||
if (NS_FAILED(NS_NewURI(getter_AddRefs(originURI), aTargetOrigin))) {
|
||||
aError.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
||||
return;
|
||||
}
|
||||
if (NS_FAILED(providedOrigin->SetUserPass(EmptyCString())) ||
|
||||
NS_FAILED(providedOrigin->SetPath(EmptyCString()))) {
|
||||
|
||||
if (NS_FAILED(originURI->SetUserPass(EmptyCString())) ||
|
||||
NS_FAILED(originURI->SetPath(EmptyCString()))) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptSecurityManager> ssm =
|
||||
nsContentUtils::GetSecurityManager();
|
||||
MOZ_ASSERT(ssm);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal = nsContentUtils::GetSubjectPrincipal();
|
||||
MOZ_ASSERT(principal);
|
||||
|
||||
uint32_t appId;
|
||||
if (NS_WARN_IF(NS_FAILED(principal->GetAppId(&appId))))
|
||||
return;
|
||||
|
||||
bool isInBrowser;
|
||||
if (NS_WARN_IF(NS_FAILED(principal->GetIsInBrowserElement(&isInBrowser))))
|
||||
return;
|
||||
|
||||
// Create a nsIPrincipal inheriting the app/browser attributes from the
|
||||
// caller.
|
||||
nsresult rv = ssm->GetAppCodebasePrincipal(originURI, appId, isInBrowser,
|
||||
getter_AddRefs(providedPrincipal));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -7878,7 +7900,7 @@ nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
: callerInnerWin->GetOuterWindowInternal(),
|
||||
origin,
|
||||
this,
|
||||
providedOrigin,
|
||||
providedPrincipal,
|
||||
nsContentUtils::IsCallerChrome());
|
||||
|
||||
// We *must* clone the data here, or the JS::Value could be modified
|
||||
|
18
dom/base/nsIGlobalObject.cpp
Normal file
18
dom/base/nsIGlobalObject.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "nsIGlobalObject.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
nsIPrincipal*
|
||||
nsIGlobalObject::PrincipalOrNull()
|
||||
{
|
||||
JSObject *global = GetGlobalJSObject();
|
||||
if (NS_WARN_IF(!global))
|
||||
return nullptr;
|
||||
|
||||
return nsContentUtils::GetObjectPrincipal(global);
|
||||
}
|
@ -13,12 +13,17 @@
|
||||
{ 0xe2538ded, 0x13ef, 0x4f4d, \
|
||||
{ 0x94, 0x6b, 0x65, 0xd3, 0x33, 0xb4, 0xf0, 0x3c } }
|
||||
|
||||
class nsIPrincipal;
|
||||
|
||||
class nsIGlobalObject : public nsISupports
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IGLOBALOBJECT_IID)
|
||||
|
||||
virtual JSObject* GetGlobalJSObject() = 0;
|
||||
|
||||
// This method is not meant to be overridden.
|
||||
nsIPrincipal* PrincipalOrNull();
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIGlobalObject,
|
||||
|
15
dom/base/test/iframe_postMessage_solidus.html
Normal file
15
dom/base/test/iframe_postMessage_solidus.html
Normal file
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<body>
|
||||
<script type="application/javascript">
|
||||
|
||||
window.addEventListener('message', receiveMessage, false);
|
||||
function receiveMessage(evt) {
|
||||
window.parent.postMessage(evt.data, '*');
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
@ -4,6 +4,7 @@ support-files =
|
||||
iframe_messageChannel_pingpong.html
|
||||
iframe_messageChannel_post.html
|
||||
file_empty.html
|
||||
iframe_postMessage_solidus.html
|
||||
|
||||
[test_Image_constructor.html]
|
||||
[test_appname_override.html]
|
||||
@ -45,4 +46,5 @@ support-files =
|
||||
[test_openDialogChromeOnly.html]
|
||||
[test_messagemanager_targetchain.html]
|
||||
[test_url_empty_port.html]
|
||||
[test_postMessage_solidus.html]
|
||||
[test_urlSearchParams.html]
|
||||
|
93
dom/base/test/test_postMessage_solidus.html
Normal file
93
dom/base/test/test_postMessage_solidus.html
Normal file
@ -0,0 +1,93 @@
|
||||
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=949488
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 949488 - basic support</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=949488">Mozilla Bug 949488</a>
|
||||
<div id="content"></div>
|
||||
<script type="application/javascript">
|
||||
|
||||
function selfMessage() {
|
||||
addEventListener('message', receiveMessage);
|
||||
function receiveMessage(evt) {
|
||||
is(evt.data, 1, "Message received");
|
||||
removeEventListener('message', receiveMessage);
|
||||
runTest();
|
||||
}
|
||||
|
||||
postMessage(1, '/');
|
||||
}
|
||||
|
||||
function frameOk() {
|
||||
var ifr = document.createElement("iframe");
|
||||
ifr.addEventListener("load", iframeLoaded, false);
|
||||
ifr.setAttribute('src', "iframe_postMessage_solidus.html");
|
||||
|
||||
var div = document.getElementById("content");
|
||||
div.appendChild(ifr);
|
||||
|
||||
function iframeLoaded() {
|
||||
addEventListener('message', receiveMessage);
|
||||
function receiveMessage(evt) {
|
||||
is(evt.data, 2, "Message received");
|
||||
removeEventListener('message', receiveMessage);
|
||||
runTest();
|
||||
}
|
||||
|
||||
ifr.contentWindow.postMessage(2, '/');
|
||||
}
|
||||
}
|
||||
|
||||
function frameWrong() {
|
||||
var ifr = document.createElement("iframe");
|
||||
ifr.addEventListener("load", iframeLoaded, false);
|
||||
ifr.setAttribute('src', "http://www.example.com/tests/dom/base/test/iframe_postMessage_solidus.html");
|
||||
|
||||
var div = document.getElementById("content");
|
||||
div.appendChild(ifr);
|
||||
|
||||
function iframeLoaded() {
|
||||
addEventListener('message', receiveMessage);
|
||||
function receiveMessage(evt) {
|
||||
ok(evt.data, 3, "Message received");
|
||||
removeEventListener('message', receiveMessage);
|
||||
runTest();
|
||||
}
|
||||
|
||||
ifr.contentWindow.postMessage(4, '/');
|
||||
SimpleTest.executeSoon(function() {
|
||||
ifr.contentWindow.postMessage(3, '*');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var tests = [
|
||||
selfMessage,
|
||||
frameOk,
|
||||
frameWrong
|
||||
];
|
||||
|
||||
function runTest() {
|
||||
if (!tests.length) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
runTest();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -191,7 +191,7 @@ function browserLoadEvent() {
|
||||
setupStorage(gBrowserStorage.localStorage);
|
||||
setupStorage(gBrowserStorage.sessionStorage);
|
||||
|
||||
frames[1].postMessage("clear", "http://www.example.com");
|
||||
frames[1].postMessage("clear", "*");
|
||||
|
||||
waitForClearBrowserData();
|
||||
};
|
||||
|
@ -28,11 +28,11 @@ function onMessageReceived(event)
|
||||
// Indication of successfully finished step of a test
|
||||
case "perf":
|
||||
if (callMasterFrame)
|
||||
masterFrame.postMessage("step", masterFrameOrigin);
|
||||
masterFrame.postMessage("step", "*");
|
||||
else if (slaveFrame)
|
||||
slaveFrame.postMessage("step", slaveFrameOrigin);
|
||||
slaveFrame.postMessage("step", "*");
|
||||
else if (SpecialPowers.wrap(masterFrame).slaveFrame)
|
||||
SpecialPowers.wrap(masterFrame).slaveFrame.postMessage("step", slaveFrameOrigin);
|
||||
SpecialPowers.wrap(masterFrame).slaveFrame.postMessage("step", "*");
|
||||
callMasterFrame = !callMasterFrame;
|
||||
break;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user