зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1381408. Make cross-origin-exposed non-symbol properties enumerable. r=bholley
The list of exposed properties can be gotten via Object.getOwnPropertyNames/Symbols already, so there's nothing to be won from the non-enumerability. The web platform test changes are backports of https://github.com/w3c/web-platform-tests/pull/6538 and https://github.com/w3c/web-platform-tests/pull/6571 and https://github.com/w3c/web-platform-tests/pull/6583 The js/xpconnect/tests/mochitest/*crossOriginObject* tests being removed are just older versions of the web platfrom test.
This commit is contained in:
Родитель
8f8eed7be6
Коммит
58c5f32380
|
@ -1,35 +0,0 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
// Override the |frames| property to test that such overrides are
|
||||
// properly ignored cross-origin.
|
||||
window.frames = "override";
|
||||
|
||||
// If we get a postMessage, we grab references to everything and set
|
||||
// document.domain to trim off our topmost subdomain.
|
||||
window.onmessage = function(evt) {
|
||||
window.windowReferences = [];
|
||||
window.locationReferences = [];
|
||||
for (var i = 0; i < parent.length; ++i) {
|
||||
windowReferences.push(parent[i]);
|
||||
locationReferences.push(parent[i].location);
|
||||
}
|
||||
document.domain = document.domain.substring(document.domain.indexOf('.') + 1);
|
||||
evt.source.postMessage('', '*');
|
||||
}
|
||||
|
||||
function checkWindowReferences() {
|
||||
for (var i = 0; i < parent.length; ++i) {
|
||||
if (windowReferences[i] != parent[i])
|
||||
throw new Error("Window references don't match for " + i + " after document.domain");
|
||||
if (locationReferences[i] != parent[i].location)
|
||||
throw new Error("Location references don't match for " + i + " after document.domain");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
|
@ -1,55 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<script>
|
||||
function loadFrames() {
|
||||
window.A = document.getElementById('A').contentWindow;
|
||||
window.B = document.getElementById('B').contentWindow;
|
||||
window.C = document.getElementById('C').contentWindow;
|
||||
window.D = document.getElementById('D').contentWindow;
|
||||
|
||||
var path = location.pathname.substring(0, location.pathname.lastIndexOf('/')) + '/file_crossOriginObjects.html';
|
||||
A.location = 'file_crossOriginObjects.html';
|
||||
B.location = frameURI = 'http://test2.mochi.test:' + location.port + path;
|
||||
C.location = frameURI = 'http://test1.mochi.test:' + location.port + path;
|
||||
D.location = frameURI = 'http://test1.mochi.test:' + location.port + path;
|
||||
|
||||
var loadCount = 0;
|
||||
function frameLoaded() {
|
||||
if (++loadCount == 4)
|
||||
go();
|
||||
}
|
||||
Array.forEach(document.getElementsByTagName('iframe'), function(ifr) { ifr.onload = frameLoaded; });
|
||||
}
|
||||
|
||||
|
||||
var results = [];
|
||||
function assert(cond, msg) {
|
||||
results.push({pass: !!cond, message: msg});
|
||||
}
|
||||
|
||||
function go() {
|
||||
window.onmessage = function() {
|
||||
assert(B.checkWindowReferences(), "B's Window references are still self-consistent after document.domain");
|
||||
for (var i = 0; i < window.length; ++i) {
|
||||
assert(window[i] === B.windowReferences[i],
|
||||
"Window reference " + i + " consistent between globals after document.domain");
|
||||
assert(window[i].location === B.locationReferences[i],
|
||||
"Location reference " + i + " consistent between globals after document.domain");
|
||||
}
|
||||
opener.postMessage(results, '*');
|
||||
};
|
||||
A.document.domain = A.document.domain;
|
||||
document.domain = document.domain;
|
||||
B.postMessage('', '*');
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="loadFrames()">
|
||||
<iframe id="A"></iframe>
|
||||
<iframe id="B"></iframe>
|
||||
<iframe id="C"></iframe>
|
||||
<iframe id="D"></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -22,8 +22,6 @@ support-files =
|
|||
file_bug799348.html
|
||||
file_bug802557.html
|
||||
file_bug860494.html
|
||||
file_crossOriginObjects.html
|
||||
file_crossOriginObjects_documentDomain.html
|
||||
file_crosscompartment_weakmap.html
|
||||
file_documentdomain.html
|
||||
file_doublewrappedcompartments.html
|
||||
|
@ -94,7 +92,6 @@ support-files =
|
|||
[test_bug1005806.html]
|
||||
[test_bug1094930.html]
|
||||
[test_bug1158558.html]
|
||||
[test_crossOriginObjects.html]
|
||||
[test_crosscompartment_weakmap.html]
|
||||
[test_frameWrapping.html]
|
||||
# The JS test component we use below is only available in debug builds.
|
||||
|
|
|
@ -13,16 +13,29 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=862380
|
|||
/** Test for Bug 862380 **/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
function go() {
|
||||
checkNotEnumerable($('ifr').contentWindow);
|
||||
checkNotEnumerable($('ifr').contentWindow.location);
|
||||
checkNotEnumerable($('ifr').contentWindow, true);
|
||||
checkNotEnumerable($('ifr').contentWindow.location, false);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function checkNotEnumerable(obj) {
|
||||
function checkNotEnumerable(obj, isWindow) {
|
||||
try {
|
||||
is(Object.keys(obj).length, 0, "Object.keys gives empty array");
|
||||
const expectedWindow = ["0", "window", "location", "top", "close",
|
||||
"focus", "blur", "postMessage", "self", "closed",
|
||||
"frames", "length", "opener", "parent"];
|
||||
const expectedLocation = ["replace", "href"];
|
||||
const expected = isWindow ? expectedWindow : expectedLocation;
|
||||
is(Object.keys(obj).length, expected.length,
|
||||
"Object.keys gives right array length");
|
||||
var actual = [];
|
||||
for (var i in obj)
|
||||
ok(false, "Enumerated something: " + i);
|
||||
actual.push(i);
|
||||
is(actual.length, expected.length,
|
||||
"Enumeration sees the right number of props");
|
||||
actual.sort();
|
||||
expected.sort();
|
||||
for (var i = 0; i < actual.length; ++i)
|
||||
is(actual[i], expected[i], "Arrays should be the same " + i);
|
||||
} catch (e) {
|
||||
ok(false, "threw: " + e);
|
||||
}
|
||||
|
|
|
@ -1,335 +0,0 @@
|
|||
<!doctype html>
|
||||
<meta charset=utf-8>
|
||||
<meta name="timeout" content="long">
|
||||
<title>Cross-origin behavior of Window and Location</title>
|
||||
<link rel="author" title="Bobby Holley (:bholley)" href="bobbyholley@gmail.com">
|
||||
<link rel="help" href="http://www.whatwg.org/specs/web-apps/current-work/#security-window">
|
||||
<link rel="help" href="http://www.whatwg.org/specs/web-apps/current-work/#security-location">
|
||||
<script src="/resources/testharness.js"></script>
|
||||
<script src="/resources/testharnessreport.js"></script>
|
||||
<div id=log></div>
|
||||
<iframe id="B"></iframe>
|
||||
<iframe id="C"></iframe>
|
||||
<script>
|
||||
|
||||
/*
|
||||
* Setup boilerplate. This gives us a same-origin window "B" and a cross-origin
|
||||
* window "C".
|
||||
*/
|
||||
|
||||
setup({explicit_done: true});
|
||||
path = location.pathname.substring(0, location.pathname.lastIndexOf('/')) + '/file_crossOriginObjects.html';
|
||||
var B = document.getElementById('B').contentWindow;
|
||||
var C = document.getElementById('C').contentWindow;
|
||||
B.frameElement.uriToLoad = path;
|
||||
C.frameElement.uriToLoad = 'http://test1.mochi.test:' + location.port + path;
|
||||
|
||||
function reloadSubframes(cb) {
|
||||
var iframes = document.getElementsByTagName('iframe');
|
||||
iframes.forEach = Array.prototype.forEach;
|
||||
var count = 0;
|
||||
function frameLoaded() {
|
||||
this.onload = null;
|
||||
if (++count == iframes.length)
|
||||
cb();
|
||||
}
|
||||
iframes.forEach(function(ifr) { ifr.onload = frameLoaded; ifr.setAttribute('src', ifr.uriToLoad); });
|
||||
}
|
||||
function isObject(x) { return Object(x) === x; }
|
||||
|
||||
/*
|
||||
* Note: we eschew assert_equals in a lot of these tests, since the harness ends
|
||||
* up throwing when it tries to format a message involving a cross-origin object.
|
||||
*/
|
||||
|
||||
var testList = [];
|
||||
function addTest(fun, desc) { testList.push([fun, desc]); }
|
||||
|
||||
|
||||
/*
|
||||
* Basic sanity testing.
|
||||
*/
|
||||
|
||||
addTest(function() {
|
||||
assert_equals(location.host, 'mochi.test:8888', 'Need to run the top-level test from mochi.test:8888');
|
||||
assert_equals(B.parent, window, "window.parent works same-origin");
|
||||
assert_equals(C.parent, window, "window.parent works cross-origin");
|
||||
assert_equals(B.location.pathname, path, "location.href works same-origin");
|
||||
assert_throws(null, function() { C.location.pathname; }, "location.pathname throws cross-origin");
|
||||
assert_equals(B.frames, 'override', "Overrides visible in the same-origin case");
|
||||
assert_equals(C.frames, C, "Overrides invisible in the cross-origin case");
|
||||
}, "Basic sanity-checking");
|
||||
|
||||
/*
|
||||
* Whitelist behavior.
|
||||
*
|
||||
* Also tests for [[GetOwnProperty]] and [[HasOwnProperty]] behavior.
|
||||
*/
|
||||
|
||||
var whitelistedWindowProps = ['location', 'postMessage', 'window', 'frames', 'self', 'top', 'parent',
|
||||
'opener', 'closed', 'close', 'blur', 'focus', 'length'];
|
||||
addTest(function() {
|
||||
for (var prop in window) {
|
||||
if (whitelistedWindowProps.indexOf(prop) != -1) {
|
||||
C[prop]; // Shouldn't throw.
|
||||
Object.getOwnPropertyDescriptor(C, prop); // Shouldn't throw.
|
||||
assert_true(Object.prototype.hasOwnProperty.call(C, prop), "hasOwnProperty for " + prop);
|
||||
} else {
|
||||
assert_throws(null, function() { C[prop]; }, "Should throw when accessing " + prop + " on Window");
|
||||
assert_throws(null, function() { Object.getOwnPropertyDescriptor(C, prop); },
|
||||
"Should throw when accessing property descriptor for " + prop + " on Window");
|
||||
assert_throws(null, function() { Object.prototype.hasOwnProperty.call(C, prop); },
|
||||
"Should throw when invoking hasOwnProperty for " + prop + " on Window");
|
||||
}
|
||||
if (prop != 'location')
|
||||
assert_throws(null, function() { C[prop] = undefined; }, "Should throw when writing to " + prop + " on Window");
|
||||
}
|
||||
for (var prop in location) {
|
||||
if (prop == 'replace') {
|
||||
C.location[prop]; // Shouldn't throw.
|
||||
Object.getOwnPropertyDescriptor(C.location, prop); // Shouldn't throw.
|
||||
assert_true(Object.prototype.hasOwnProperty.call(C.location, prop), "hasOwnProperty for " + prop);
|
||||
}
|
||||
else {
|
||||
assert_throws(null, function() { C[prop]; }, "Should throw when accessing " + prop + " on Location");
|
||||
assert_throws(null, function() { Object.getOwnPropertyDescriptor(C, prop); },
|
||||
"Should throw when accessing property descriptor for " + prop + " on Location");
|
||||
assert_throws(null, function() { Object.prototype.hasOwnProperty.call(C, prop); },
|
||||
"Should throw when invoking hasOwnProperty for " + prop + " on Location");
|
||||
}
|
||||
if (prop != 'href')
|
||||
assert_throws(null, function() { C[prop] = undefined; }, "Should throw when writing to " + prop + " on Location");
|
||||
}
|
||||
}, "Only whitelisted properties are accessible cross-origin");
|
||||
|
||||
/*
|
||||
* ES Internal Methods.
|
||||
*/
|
||||
|
||||
/*
|
||||
* [[GetPrototypeOf]]
|
||||
*/
|
||||
addTest(function() {
|
||||
assert_true(Object.getPrototypeOf(C) === null, "cross-origin Window proto is null");
|
||||
assert_true(Object.getPrototypeOf(C.location) === null, "cross-origin Location proto is null (__proto__)");
|
||||
var protoGetter = Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').get;
|
||||
assert_true(protoGetter.call(C) === null, "cross-origin Window proto is null");
|
||||
assert_true(protoGetter.call(C.location) === null, "cross-origin Location proto is null (__proto__)");
|
||||
assert_throws(null, function() { C.__proto__; }, "__proto__ property not available cross-origin");
|
||||
assert_throws(null, function() { C.location.__proto__; }, "__proto__ property not available cross-origin");
|
||||
|
||||
}, "[[GetPrototypeOf]] should return null");
|
||||
|
||||
/*
|
||||
* [[SetPrototypeOf]]
|
||||
*/
|
||||
addTest(function() {
|
||||
assert_throws(null, function() { C.__proto__ = new Object(); }, "proto set on cross-origin Window");
|
||||
assert_throws(null, function() { C.location.__proto__ = new Object(); }, "proto set on cross-origin Location");
|
||||
var setters = [Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set];
|
||||
if (Object.setPrototypeOf)
|
||||
setters.push(function(p) { Object.setPrototypeOf(this, p); });
|
||||
setters.forEach(function(protoSetter) {
|
||||
assert_throws(null, function() { protoSetter.call(C, new Object()); }, "proto setter |call| on cross-origin Window");
|
||||
assert_throws(null, function() { protoSetter.call(C.location, new Object()); }, "proto setter |call| on cross-origin Location");
|
||||
});
|
||||
}, "[[SetPrototypeOf]] should throw");
|
||||
|
||||
/*
|
||||
* [[IsExtensible]]
|
||||
*/
|
||||
addTest(function() {
|
||||
assert_true(Object.isExtensible(C), "cross-origin Window should be extensible");
|
||||
assert_true(Object.isExtensible(C.location), "cross-origin Location should be extensible");
|
||||
}, "[[IsExtensible]] should return true for cross-origin objects");
|
||||
|
||||
/*
|
||||
* [[PreventExtensions]]
|
||||
*/
|
||||
addTest(function() {
|
||||
assert_throws(null, function() { Object.preventExtensions(C) },
|
||||
"preventExtensions on cross-origin Window should throw");
|
||||
assert_throws(null, function() { Object.preventExtensions(C.location) },
|
||||
"preventExtensions on cross-origin Location should throw");
|
||||
}, "[[PreventExtensions]] should throw for cross-origin objects");
|
||||
|
||||
/*
|
||||
* [[GetOwnProperty]]
|
||||
*/
|
||||
|
||||
addTest(function() {
|
||||
assert_true(isObject(Object.getOwnPropertyDescriptor(C, 'close')), "C.close is |own|");
|
||||
assert_true(isObject(Object.getOwnPropertyDescriptor(C, 'top')), "C.top is |own|");
|
||||
assert_true(isObject(Object.getOwnPropertyDescriptor(C.location, 'href')), "C.location.href is |own|");
|
||||
assert_true(isObject(Object.getOwnPropertyDescriptor(C.location, 'replace')), "C.location.replace is |own|");
|
||||
}, "[[GetOwnProperty]] - Properties on cross-origin objects should be reported |own|");
|
||||
|
||||
function checkPropertyDescriptor(desc, propName, expectWritable) {
|
||||
assert_true(isObject(desc), "property descriptor for " + propName + " should exist");
|
||||
assert_equals(desc.enumerable, false, "property descriptor for " + propName + " should be non-enumerable");
|
||||
assert_equals(desc.configurable, true, "property descriptor for " + propName + " should be configurable");
|
||||
if ('value' in desc)
|
||||
assert_equals(desc.writable, expectWritable, "property descriptor for " + propName + " should have writable: " + expectWritable);
|
||||
else
|
||||
assert_equals(typeof desc.set != 'undefined', expectWritable,
|
||||
"property descriptor for " + propName + " should " + (expectWritable ? "" : "not ") + "have setter");
|
||||
}
|
||||
|
||||
addTest(function() {
|
||||
whitelistedWindowProps.forEach(function(prop) {
|
||||
var desc = Object.getOwnPropertyDescriptor(C, prop);
|
||||
checkPropertyDescriptor(desc, prop, prop == 'location');
|
||||
});
|
||||
checkPropertyDescriptor(Object.getOwnPropertyDescriptor(C.location, 'replace'), 'replace', false);
|
||||
checkPropertyDescriptor(Object.getOwnPropertyDescriptor(C.location, 'href'), 'href', true);
|
||||
assert_equals(typeof Object.getOwnPropertyDescriptor(C.location, 'href').get, 'undefined', "Cross-origin location should have no href getter");
|
||||
}, "[[GetOwnProperty]] - Property descriptors for cross-origin properties should be set up correctly");
|
||||
|
||||
/*
|
||||
* [[Delete]]
|
||||
*/
|
||||
addTest(function() {
|
||||
assert_throws(null, function() { delete C.location; }, "Can't delete cross-origin property");
|
||||
assert_throws(null, function() { delete C.parent; }, "Can't delete cross-origin property");
|
||||
assert_throws(null, function() { delete C.length; }, "Can't delete cross-origin property");
|
||||
assert_throws(null, function() { delete C.document; }, "Can't delete cross-origin property");
|
||||
assert_throws(null, function() { delete C.foopy; }, "Can't delete cross-origin property");
|
||||
assert_throws(null, function() { delete C.location.href; }, "Can't delete cross-origin property");
|
||||
assert_throws(null, function() { delete C.location.replace; }, "Can't delete cross-origin property");
|
||||
assert_throws(null, function() { delete C.location.port; }, "Can't delete cross-origin property");
|
||||
assert_throws(null, function() { delete C.location.foopy; }, "Can't delete cross-origin property");
|
||||
}, "[[Delete]] Should throw on cross-origin objects");
|
||||
|
||||
/*
|
||||
* [[DefineOwnProperty]]
|
||||
*/
|
||||
function checkDefine(obj, prop) {
|
||||
var valueDesc = { configurable: true, enumerable: false, writable: false, value: 2 };
|
||||
var accessorDesc = { configurable: true, enumerable: false, get: function() {} };
|
||||
assert_throws(null, function() { Object.defineProperty(obj, prop, valueDesc); }, "Can't define cross-origin value property " + prop);
|
||||
assert_throws(null, function() { Object.defineProperty(obj, prop, accessorDesc); }, "Can't define cross-origin accessor property " + prop);
|
||||
}
|
||||
addTest(function() {
|
||||
checkDefine(C, 'length');
|
||||
checkDefine(C, 'parent');
|
||||
checkDefine(C, 'location');
|
||||
checkDefine(C, 'document');
|
||||
checkDefine(C, 'foopy');
|
||||
checkDefine(C.location, 'href');
|
||||
checkDefine(C.location, 'replace');
|
||||
checkDefine(C.location, 'port');
|
||||
checkDefine(C.location, 'foopy');
|
||||
}, "[[DefineOwnProperty]] Should throw for cross-origin objects");
|
||||
|
||||
/*
|
||||
* [[Enumerate]]
|
||||
*/
|
||||
|
||||
addTest(function() {
|
||||
for (var prop in C)
|
||||
assert_unreached("Shouldn't have been able to enumerate " + prop + " on cross-origin Window");
|
||||
for (var prop in C.location)
|
||||
assert_unreached("Shouldn't have been able to enumerate " + prop + " on cross-origin Location");
|
||||
}, "[[Enumerate]] should return an empty iterator");
|
||||
|
||||
/*
|
||||
* [[OwnPropertyKeys]]
|
||||
*/
|
||||
|
||||
addTest(function() {
|
||||
assert_array_equals(whitelistedWindowProps.sort(), Object.getOwnPropertyNames(C).sort(),
|
||||
"Object.getOwnPropertyNames() gives the right answer for cross-origin Window");
|
||||
assert_array_equals(Object.getOwnPropertyNames(C.location).sort(), ['href', 'replace'],
|
||||
"Object.getOwnPropertyNames() gives the right answer for cross-origin Location");
|
||||
}, "[[OwnPropertyKeys]] should return all properties from cross-origin objects");
|
||||
|
||||
addTest(function() {
|
||||
assert_true(B.eval('parent.C') === C, "A and B observe the same identity for C's Window");
|
||||
assert_true(B.eval('parent.C.location') === C.location, "A and B observe the same identity for C's Location");
|
||||
}, "A and B jointly observe the same identity for cross-origin Window and Location");
|
||||
|
||||
function checkFunction(f, proto) {
|
||||
var name = f.name || '<missing name>';
|
||||
assert_equals(typeof f, 'function', name + " is a function");
|
||||
assert_equals(Object.getPrototypeOf(f), proto, f.name + " has the right prototype");
|
||||
}
|
||||
|
||||
addTest(function() {
|
||||
checkFunction(C.close, Function.prototype);
|
||||
checkFunction(C.location.replace, Function.prototype);
|
||||
}, "Cross-origin functions get local Function.prototype");
|
||||
|
||||
addTest(function() {
|
||||
assert_true(isObject(Object.getOwnPropertyDescriptor(C, 'parent')),
|
||||
"Need to be able to use Object.getOwnPropertyDescriptor do this test");
|
||||
checkFunction(Object.getOwnPropertyDescriptor(C, 'parent').get, Function.prototype);
|
||||
checkFunction(Object.getOwnPropertyDescriptor(C.location, 'href').set, Function.prototype);
|
||||
}, "Cross-origin Window accessors get local Function.prototype");
|
||||
|
||||
addTest(function() {
|
||||
checkFunction(close, Function.prototype);
|
||||
assert_true(close != B.close, 'same-origin Window functions get their own object');
|
||||
assert_true(close != C.close, 'cross-origin Window functions get their own object');
|
||||
var close_B = B.eval('parent.C.close');
|
||||
assert_true(close != close_B, 'close_B is unique when viewed by the parent');
|
||||
assert_true(close_B != C.close, 'different Window functions per-incumbent script settings object');
|
||||
checkFunction(close_B, B.Function.prototype);
|
||||
|
||||
checkFunction(location.replace, Function.prototype);
|
||||
assert_true(location.replace != C.location.replace, "cross-origin Location functions get their own object");
|
||||
var replace_B = B.eval('parent.C.location.replace');
|
||||
assert_true(replace_B != C.location.replace, 'different Location functions per-incumbent script settings object');
|
||||
checkFunction(replace_B, B.Function.prototype);
|
||||
}, "Same-origin observers get different functions for cross-origin objects");
|
||||
|
||||
addTest(function() {
|
||||
assert_true(isObject(Object.getOwnPropertyDescriptor(C, 'parent')),
|
||||
"Need to be able to use Object.getOwnPropertyDescriptor do this test");
|
||||
var get_self_parent = Object.getOwnPropertyDescriptor(window, 'parent').get;
|
||||
var get_parent_A = Object.getOwnPropertyDescriptor(C, 'parent').get;
|
||||
var get_parent_B = B.eval('Object.getOwnPropertyDescriptor(parent.C, "parent").get');
|
||||
assert_true(get_self_parent != get_parent_A, 'different Window accessors per-incumbent script settings object');
|
||||
assert_true(get_parent_A != get_parent_B, 'different Window accessors per-incumbent script settings object');
|
||||
checkFunction(get_self_parent, Function.prototype);
|
||||
checkFunction(get_parent_A, Function.prototype);
|
||||
checkFunction(get_parent_B, B.Function.prototype);
|
||||
}, "Same-origin obsevers get different accessors for cross-origin Window");
|
||||
|
||||
addTest(function() {
|
||||
var set_self_href = Object.getOwnPropertyDescriptor(window.location, 'href').set;
|
||||
var set_href_A = Object.getOwnPropertyDescriptor(C.location, 'href').set;
|
||||
var set_href_B = B.eval('Object.getOwnPropertyDescriptor(parent.C.location, "href").set');
|
||||
assert_true(set_self_href != set_href_A, 'different Location accessors per-incumbent script settings object');
|
||||
assert_true(set_href_A != set_href_B, 'different Location accessors per-incumbent script settings object');
|
||||
checkFunction(set_self_href, Function.prototype);
|
||||
checkFunction(set_href_A, Function.prototype);
|
||||
checkFunction(set_href_B, B.Function.prototype);
|
||||
}, "Same-origin observers get different accessors for cross-origin Location");
|
||||
|
||||
function doDocumentDomainTest(cb) {
|
||||
window.addEventListener('message', function(evt) {
|
||||
test(function() {
|
||||
var results = evt.data;
|
||||
assert_true(results.length > 0, 'Need results');
|
||||
results.forEach(function(r) { assert_true(r.pass, r.message); });
|
||||
}, "Cross-origin object identity preserved across document.domain");
|
||||
win.close();
|
||||
cb();
|
||||
}, {once: true});
|
||||
var win = window.open('file_crossOriginObjects_documentDomain.html');
|
||||
}
|
||||
|
||||
// We do a fresh load of the subframes for each test to minimize side-effects.
|
||||
// It would be nice to reload ourselves as well, but we can't do that without
|
||||
// disrupting the test harness.
|
||||
function runNextTest() {
|
||||
var entry = testList.shift();
|
||||
test(entry[0], entry[1]);
|
||||
if (testList.length != 0)
|
||||
reloadSubframes(runNextTest);
|
||||
else
|
||||
doDocumentDomainTest(done); // Asynchronous.
|
||||
}
|
||||
reloadSubframes(runNextTest);
|
||||
|
||||
</script>
|
|
@ -223,9 +223,8 @@ CrossOriginXrayWrapper::getPropertyDescriptor(JSContext* cx,
|
|||
// All properties on cross-origin DOM objects are |own|.
|
||||
desc.object().set(wrapper);
|
||||
|
||||
// All properties on cross-origin DOM objects are non-enumerable and
|
||||
// "configurable". Any value attributes are read-only.
|
||||
desc.attributesRef() &= ~JSPROP_ENUMERATE;
|
||||
// All properties on cross-origin DOM objects are "configurable". Any
|
||||
// value attributes are read-only.
|
||||
desc.attributesRef() &= ~JSPROP_PERMANENT;
|
||||
if (!desc.getter() && !desc.setter())
|
||||
desc.attributesRef() |= JSPROP_READONLY;
|
||||
|
|
|
@ -187,14 +187,16 @@ function checkPropertyDescriptor(desc, propName, expectWritable) {
|
|||
var isSymbol = (typeof(propName) == "symbol");
|
||||
propName = String(propName);
|
||||
assert_true(isObject(desc), "property descriptor for " + propName + " should exist");
|
||||
assert_equals(desc.enumerable, false, "property descriptor for " + propName + " should be non-enumerable");
|
||||
assert_equals(desc.configurable, true, "property descriptor for " + propName + " should be configurable");
|
||||
if (isSymbol) {
|
||||
assert_equals(desc.enumerable, false, "symbol-property descriptor for " + propName + " should not be enumerable");
|
||||
assert_true("value" in desc,
|
||||
"property descriptor for " + propName + " should be a value descriptor");
|
||||
assert_equals(desc.value, undefined,
|
||||
"symbol-named cross-origin visible prop " + propName +
|
||||
" should come back as undefined");
|
||||
} else {
|
||||
assert_equals(desc.enumerable, true, "property descriptor for " + propName + " should be enumerable");
|
||||
}
|
||||
if ('value' in desc)
|
||||
assert_equals(desc.writable, expectWritable, "property descriptor for " + propName + " should have writable: " + expectWritable);
|
||||
|
@ -256,15 +258,23 @@ addTest(function() {
|
|||
}, "[[DefineOwnProperty]] Should throw for cross-origin objects");
|
||||
|
||||
/*
|
||||
* [[Enumerate]]
|
||||
* EnumerateObjectProperties (backed by [[OwnPropertyKeys]])
|
||||
*/
|
||||
|
||||
addTest(function() {
|
||||
for (var prop in C)
|
||||
assert_unreached("Shouldn't have been able to enumerate " + prop + " on cross-origin Window");
|
||||
for (var prop in C.location)
|
||||
assert_unreached("Shouldn't have been able to enumerate " + prop + " on cross-origin Location");
|
||||
}, "[[Enumerate]] should return an empty iterator");
|
||||
let i = 0;
|
||||
for (var prop in C) {
|
||||
i++;
|
||||
assert_true(whitelistedWindowPropNames.includes(prop), prop + " is not safelisted for a cross-origin Window");
|
||||
}
|
||||
assert_equals(i, whitelistedWindowPropNames.length, "Enumerate all safelisted cross-origin Window properties");
|
||||
i = 0;
|
||||
for (var prop in C.location) {
|
||||
i++;
|
||||
assert_true(whitelistedLocationPropNames.includes(prop), prop + " is not safelisted for a cross-origin Location");
|
||||
}
|
||||
assert_equals(i, whitelistedLocationPropNames.length, "Enumerate all safelisted cross-origin Location properties");
|
||||
}, "Can only enumerate safelisted properties");
|
||||
|
||||
/*
|
||||
* [[OwnPropertyKeys]]
|
||||
|
@ -274,9 +284,15 @@ addTest(function() {
|
|||
assert_array_equals(Object.getOwnPropertyNames(C).sort(),
|
||||
whitelistedWindowPropNames,
|
||||
"Object.getOwnPropertyNames() gives the right answer for cross-origin Window");
|
||||
assert_array_equals(Object.keys(C).sort(),
|
||||
whitelistedWindowPropNames,
|
||||
"Object.keys() gives the right answer for cross-origin Window");
|
||||
assert_array_equals(Object.getOwnPropertyNames(C.location).sort(),
|
||||
whitelistedLocationPropNames,
|
||||
"Object.getOwnPropertyNames() gives the right answer for cross-origin Location");
|
||||
assert_array_equals(Object.keys(C.location).sort(),
|
||||
whitelistedLocationPropNames,
|
||||
"Object.keys() gives the right answer for cross-origin Location");
|
||||
}, "[[OwnPropertyKeys]] should return all properties from cross-origin objects");
|
||||
|
||||
addTest(function() {
|
||||
|
|
|
@ -37,6 +37,6 @@
|
|||
<body>
|
||||
<!-- Two subframes to give us some indexed properties -->
|
||||
<iframe></iframe>
|
||||
<iframe></iframe>
|
||||
<iframe name=donotleakme></iframe><!-- "donotleakme" is excluded as cross-origin named property due to [[HideFromKeys]] -->
|
||||
</body>
|
||||
</html>
|
||||
|
|
Загрузка…
Ссылка в новой задаче