1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/identity/tests/chrome/test_sandbox.xul Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,324 @@ 1.4 +<?xml version="1.0"?> 1.5 +<?xml-stylesheet type="text/css" href="chrome://global/skin"?> 1.6 +<?xml-stylesheet type="text/css" href="/tests/SimpleTest/test.css"?> 1.7 +<!-- Any copyright is dedicated to the Public Domain. 1.8 + http://creativecommons.org/publicdomain/zero/1.0/ --> 1.9 +<!-- 1.10 +https://bugzilla.mozilla.org/show_bug.cgi?id=762993 1.11 +--> 1.12 +<window title="Mozilla Bug 762993" 1.13 + xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" 1.14 + onload="run_next_test();"> 1.15 + <script type="application/javascript" 1.16 + src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/> 1.17 + 1.18 + <!-- test results are displayed in the html:body --> 1.19 + <body xmlns="http://www.w3.org/1999/xhtml"> 1.20 + <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=762993" 1.21 + target="_blank">Mozilla Bug 762993</a> 1.22 + </body> 1.23 + 1.24 + <!-- test code goes here --> 1.25 + <script type="application/javascript;version=1.8"> 1.26 + <![CDATA[ 1.27 + 1.28 + /** Test for Bug 762993 **/ 1.29 + 1.30 +"use strict"; 1.31 + 1.32 +SimpleTest.expectAssertions(1); 1.33 + 1.34 +SimpleTest.waitForExplicitFinish(); 1.35 + 1.36 +const Cc = Components.classes; 1.37 +const Ci = Components.interfaces; 1.38 +const Cu = Components.utils; 1.39 + 1.40 +const secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager); 1.41 + 1.42 +const TEST_URL_1 = "https://example.com/"; 1.43 +// No trailing slash plus port to test normalization 1.44 +const TEST_URL_2 = "https://example.com:443"; 1.45 + 1.46 +const TEST_BASE = "http://mochi.test:8888/chrome/toolkit/identity/tests/chrome/" 1.47 +const STATE_URL = TEST_BASE + "sandbox_content.sjs" 1.48 + 1.49 +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); 1.50 +Cu.import("resource://gre/modules/Services.jsm"); 1.51 + 1.52 +Services.prefs.setBoolPref("toolkit.identity.debug", true); 1.53 + 1.54 +XPCOMUtils.defineLazyModuleGetter(this, "Sandbox", 1.55 + "resource://gre/modules/identity/Sandbox.jsm"); 1.56 + 1.57 +function check_sandbox(aSandbox, aURL) { 1.58 + ok(aSandbox.id > 0, "valid ID"); 1.59 + is(aSandbox._url, aURL, "matching URL (with normalization)"); 1.60 + isnot(aSandbox._frame, null, "frame"); 1.61 + isnot(aSandbox._container, null, "container"); 1.62 + let docPrincipal = aSandbox._frame.contentDocument.nodePrincipal; 1.63 + is(secMan.isSystemPrincipal(docPrincipal), false, 1.64 + "principal must not be system"); 1.65 +} 1.66 + 1.67 +/** 1.68 + * Free the sandbox and make sure all properties that are not booleans, 1.69 + * functions or numbers were freed. 1.70 + */ 1.71 +function free_and_check_sandbox(aSandbox) { 1.72 + SimpleTest.executeSoon(function() { 1.73 + aSandbox.free(); 1.74 + 1.75 + for(let prop in aSandbox) { 1.76 + // Don't trigger the "id" getter when the frame is supposed to be freed already 1.77 + if (prop == "id") 1.78 + continue; 1.79 + let propType = typeof(aSandbox[prop]); 1.80 + if (propType == "boolean" || propType == "function" || propType == "number") 1.81 + continue; 1.82 + is(aSandbox[prop], null, "freed " + prop); 1.83 + } 1.84 + run_next_test(); 1.85 + }); 1.86 +} 1.87 + 1.88 +function reset_server_state() { 1.89 + // Now reset the server state 1.90 + let resetReq = new XMLHttpRequest(); 1.91 + resetReq.open("GET", STATE_URL + "?reset", false); 1.92 + resetReq.send(); 1.93 +} 1.94 + 1.95 +function test_creation() { 1.96 + new Sandbox(TEST_URL_1, function sandboxCB(aSandbox) { 1.97 + check_sandbox(aSandbox, TEST_URL_1); 1.98 + free_and_check_sandbox(aSandbox); 1.99 + }); 1.100 +} 1.101 + 1.102 +function test_reload() { 1.103 + new Sandbox(TEST_URL_1, function sandboxCB(aSandbox) { 1.104 + check_sandbox(aSandbox, TEST_URL_1); 1.105 + let originalId = aSandbox.id; 1.106 + 1.107 + aSandbox.reload(function sandboxReloadCB(aSandbox) { 1.108 + check_sandbox(aSandbox, TEST_URL_1); 1.109 + is(aSandbox.id, originalId, "Sandbox ID should be the same after reload"); 1.110 + free_and_check_sandbox(aSandbox); 1.111 + }); 1.112 + }); 1.113 +} 1.114 + 1.115 +function test_url_normalization() { 1.116 + new Sandbox(TEST_URL_2, function sandboxCB(aSandbox) { 1.117 + // TEST_URL_2 should be normalized into the form of TEST_URL_1 1.118 + check_sandbox(aSandbox, TEST_URL_1); 1.119 + free_and_check_sandbox(aSandbox); 1.120 + }); 1.121 +} 1.122 + 1.123 +/** 1.124 + * Check with the server's state to see what content was loaded then reset it. 1.125 + */ 1.126 +function check_loaded_content(aSandbox, aNothingShouldLoad, aCallback) { 1.127 + 1.128 + let xhr = new XMLHttpRequest(); 1.129 + xhr.open("GET", STATE_URL + "?get_loaded", true); 1.130 + xhr.onload = function() { 1.131 + let res = xhr.responseText; 1.132 + is(xhr.status, 200, "Check successful response"); 1.133 + 1.134 + if (aNothingShouldLoad) { 1.135 + is(res, "NOTHING", "Check that nothing was loaded on the server"); 1.136 + } else { 1.137 + let allowedTypes = [ "application/javascript", "text/html", "application/x-test" ]; 1.138 + let loadedTypes = res == "NOTHING" ? [] : res.split(","); 1.139 + 1.140 + for (let loadedType of loadedTypes) { 1.141 + isnot(allowedTypes.indexOf(loadedType), -1, "Check that " + loadedType + " was expected to load"); // TODO 1.142 + } 1.143 + 1.144 + isnot(loadedTypes.indexOf("application/javascript"), -1, "Check JS was loaded"); 1.145 + isnot(loadedTypes.indexOf("text/html"), -1, "Check iframe was loaded"); 1.146 + is(loadedTypes.indexOf("video/webm"), -1, "Check webm was not loaded"); 1.147 + is(loadedTypes.indexOf("audio/ogg"), -1, "Check ogg was not loaded"); 1.148 + 1.149 + // Check that no plugin tags have a type other than TYPE_NULL (failed load) 1.150 + // -- 1.151 + // Checking if a channel was opened is not sufficient for plugin tags -- 1.152 + // An object tag may still be allowed to load a sub-document, but not a 1.153 + // plugin, so it will open a channel but then abort when it gets a 1.154 + // plugin-type. 1.155 + let doc = aSandbox._frame.contentDocument; 1.156 + let nullType = Components.interfaces.nsIObjectLoadingContent.TYPE_NULL; 1.157 + for (let tag of doc.querySelectorAll("embed, object, applet")) { 1.158 + tag instanceof Components.interfaces.nsIObjectLoadingContent; 1.159 + is(tag.displayedType, nullType, "Check that plugin did not load content"); 1.160 + } 1.161 + } 1.162 + 1.163 + reset_server_state(); 1.164 + 1.165 + aCallback(); 1.166 + }; 1.167 + xhr.send(); 1.168 +} 1.169 + 1.170 +/** 1.171 + * Helper to check that only certain content is loaded on creation and during reload. 1.172 + */ 1.173 +function check_disabled_content(aSandboxURL, aNothingShouldLoad = false) { 1.174 + new Sandbox(aSandboxURL, function sandboxCB(aSandbox) { 1.175 + check_sandbox(aSandbox, aSandboxURL); 1.176 + let originalId = aSandbox.id; 1.177 + 1.178 + setTimeout(function() { 1.179 + check_loaded_content(aSandbox, aNothingShouldLoad, function checkFinished() { 1.180 + 1.181 + info("reload the sandbox content"); 1.182 + aSandbox.reload(function sandboxReloadCB(aSandbox) { 1.183 + check_sandbox(aSandbox, aSandboxURL); 1.184 + is(aSandbox.id, originalId, "Sandbox ID should be the same after reload"); 1.185 + 1.186 + setTimeout(function() { 1.187 + check_loaded_content(aSandbox, aNothingShouldLoad, function reloadCheckFinished() { 1.188 + free_and_check_sandbox(aSandbox); 1.189 + }); 1.190 + }, 5000); 1.191 + }); 1.192 + }); 1.193 + }, 5000); 1.194 + }); 1.195 +} 1.196 + 1.197 +function test_disabled_content() { 1.198 + let url = TEST_BASE + "sandbox_content.html"; 1.199 + check_disabled_content(url); 1.200 +} 1.201 + 1.202 +// Same as test above but with content in an iframe. 1.203 +function test_disabled_content_framed() { 1.204 + let url = TEST_BASE + "sandbox_content_framed.html"; 1.205 + check_disabled_content(url); 1.206 +} 1.207 + 1.208 +function test_redirect() { 1.209 + let url = TEST_BASE + "sandbox_content_redirect.html"; 1.210 + check_disabled_content(url); 1.211 +} 1.212 + 1.213 +function WindowObserver(aCallback) { 1.214 + this.observe = function(aSubject, aTopic, aData) { 1.215 + if (aTopic != "domwindowopened") { 1.216 + return; 1.217 + } 1.218 + Services.ww.unregisterNotification(this); 1.219 + 1.220 + let domWin = aSubject.QueryInterface(Ci.nsIDOMWindow); 1.221 + ok(!domWin, "No window should be opened"); 1.222 + SimpleTest.executeSoon(function() { 1.223 + info("Closing opened window"); 1.224 + domWin.close(); 1.225 + aCallback(); 1.226 + }); 1.227 + } 1.228 +} 1.229 + 1.230 +// Can the sandbox call window.alert() or popup other UI? 1.231 +function test_alert() { 1.232 + let alertURL = TEST_BASE + "sandbox_content_alert.html"; 1.233 + 1.234 + new Sandbox(alertURL, function sandboxCB(aSandbox) { 1.235 + check_sandbox(aSandbox, alertURL); 1.236 + setTimeout(function() { 1.237 + 1.238 + let win = Services.wm.getMostRecentWindow(null); 1.239 + isnot(win.document.documentElement.getAttribute("id"), "commonDialog", 1.240 + "Make sure most recent window is not a dialog"); 1.241 + if (win.document.documentElement.getAttribute("id") == "commonDialog") { 1.242 + // If a dialog did open, close it so we don't interfere with future tests 1.243 + win.close() 1.244 + } 1.245 + 1.246 + free_and_check_sandbox(aSandbox); 1.247 + }, 1000); 1.248 + }); 1.249 +} 1.250 + 1.251 +// Can the sandboxed page open a popup with window.open? 1.252 +function test_popup() { 1.253 + let alertURL = TEST_BASE + "sandbox_content_popup.html"; 1.254 + let theSandbox; 1.255 + function continueTest() { 1.256 + // avoid double-free 1.257 + if (!theSandbox) 1.258 + return; 1.259 + free_and_check_sandbox(theSandbox); 1.260 + theSandbox = null; 1.261 + } 1.262 + let winObs = new WindowObserver(continueTest); 1.263 + Services.ww.registerNotification(winObs); 1.264 + new Sandbox(alertURL, function sandboxCB(aSandbox) { 1.265 + theSandbox = aSandbox; 1.266 + check_sandbox(aSandbox, alertURL); 1.267 + // Wait 5 seconds to see if the window is going to open. 1.268 + setTimeout(function() { 1.269 + Services.ww.unregisterNotification(winObs); 1.270 + continueTest(); 1.271 + }, 5000); 1.272 + }); 1.273 +} 1.274 + 1.275 +// Loading a page with a bad cert 1.276 +function test_bad_cert() { 1.277 + let url = TEST_BASE + "sandbox_content.sjs?text/html"; 1.278 + url = url.replace("http://mochi.test:8888", "https://untrusted.example.com"); 1.279 + check_disabled_content(url, /*nothingShouldLoad=*/true); 1.280 +} 1.281 + 1.282 +// Loading a page to check window.top and other permissions. 1.283 +function test_frame_perms() { 1.284 + let url = TEST_BASE + "sandbox_content_perms.html"; 1.285 + new Sandbox(url, function sandboxCB(aSandbox) { 1.286 + check_sandbox(aSandbox, url); 1.287 + 1.288 + // Give the content time to load 1.289 + setTimeout(function() { 1.290 + let xhr = new XMLHttpRequest(); 1.291 + xhr.open("GET", STATE_URL + "?get_loaded", true); 1.292 + xhr.responseType = "json"; 1.293 + xhr.onload = function() { 1.294 + is(xhr.status, 200, "Check successful response"); 1.295 + is(typeof(xhr.response), "object", "Check response is object"); 1.296 + is(Object.keys(xhr.response).length, 3, "Check the number of perm. tests"); 1.297 + for (let test in xhr.response) { 1.298 + ok(xhr.response[test], "Check result of " + test); 1.299 + } 1.300 + 1.301 + reset_server_state(); 1.302 + free_and_check_sandbox(aSandbox); 1.303 + }; 1.304 + xhr.send(); 1.305 + }, 3000); 1.306 + }); 1.307 +} 1.308 + 1.309 +let TESTS = [test_creation, test_reload, test_url_normalization]; 1.310 +TESTS.push(test_disabled_content, test_disabled_content_framed); 1.311 +TESTS.push(test_alert, test_popup, test_bad_cert); 1.312 +TESTS.push(test_redirect, test_frame_perms); 1.313 + 1.314 +function run_next_test() { 1.315 + if (TESTS.length) { 1.316 + let test = TESTS.shift(); 1.317 + info(test.name); 1.318 + test(); 1.319 + } else { 1.320 + Services.prefs.clearUserPref("toolkit.identity.debug"); 1.321 + SimpleTest.finish(); 1.322 + } 1.323 +} 1.324 + 1.325 + ]]> 1.326 + </script> 1.327 +</window>