| <html> |
| <body> |
| <p>Should not be able to read the secret text from another site.</p> |
| <script> |
| // Based on tests originally provided by Daniel Divricean (http://divricean.ro). |
| |
| if (window.testRunner) { |
| testRunner.dumpAsText(); |
| testRunner.waitUntilDone(); |
| } |
| |
| let errorTypes = [ Error, EvalError, RangeError, ReferenceError, SyntaxError, TypeError, URIError ]; |
| let errorTypeNames = errorTypes.map(function (errorType) { |
| return errorType.name; |
| }); |
| |
| let nameGettersInstalled = false; |
| let toStringGettersInstalled = false; |
| let timesInErrorGetter = 0; |
| let caseIndex = 0; |
| let caseStr; |
| let testedErrorTypeCount = 0; |
| let errorTypeIndexToTest = 0; |
| let inMainScript = true; |
| |
| function assert(expr) { |
| if (!eval(expr)) |
| console.log("FAILED assertion: " + expr); |
| } |
| function assertLessThan(a, b) { |
| if (!(a < b)) |
| console.log("FAILED assertion"); |
| } |
| function shouldContainNoSecrets(actual, calledFromMainScript) { |
| if (calledFromMainScript && String(actual).indexOf("Secret") != -1) |
| console.log("FAILED: Found other domain Secret in '" + actual + "'"); |
| else |
| console.log("PASSED: Did not see any Secret from another domain"); |
| } |
| |
| function logTitle(title) { |
| console.log(""); |
| console.log(title); |
| } |
| |
| window.onerror = function(error) { |
| console.log(" " + caseStr + " in window.onerror: err = " + error); |
| console.log(" " + caseStr + " in window.onerror: err.name = " + error.name); |
| console.log(" " + caseStr + " in window.onerror: err.message = " + error.message); |
| console.log(" " + caseStr + " in window.onerror: err.toString() = " + error.toString()); |
| |
| shouldContainNoSecrets(error, true); |
| shouldContainNoSecrets(error.name, true); |
| shouldContainNoSecrets(error.message, true); |
| shouldContainNoSecrets(error.toString(), true); |
| } |
| |
| let savedNameDescriptors = []; |
| function installNameGettersToCheckErrorMessageForSecrets() { |
| assert("nameGettersInstalled == false"); |
| for (var i in errorTypes) { |
| let errorType = errorTypes[i]; |
| savedNameDescriptors[i] = Object.getOwnPropertyDescriptor(errorType.prototype, 'name'); |
| errorType.prototype.__defineGetter__('name', function() { |
| var getterEntry = timesInErrorGetter++; |
| var error = this; |
| console.log(" " + caseStr + " in 'name' getter[" + getterEntry + "]: error.message = '" + error.message + "'"); |
| |
| shouldContainNoSecrets(error.message, inMainScript); |
| |
| return "GetterErrorName: getter[" + getterEntry + "] " + error.message; |
| }); |
| } |
| nameGettersInstalled = true; |
| } |
| |
| function resetNameGetters() { |
| assert("nameGettersInstalled == true"); |
| for (var i in errorTypes) { |
| let errorType = errorTypes[i]; |
| Object.defineProperty(errorType.prototype, 'name', savedNameDescriptors[i]); |
| } |
| nameGettersInstalled = false; |
| } |
| |
| assert('errorTypes.every((errorType) => errorType.prototype.toString === Error.prototype.toString)'); |
| let originalToStringDescriptor = Object.getOwnPropertyDescriptor(Error.prototype, 'toString'); |
| let replacementToStringDescriptor = { |
| get: function() { |
| var getterEntry = timesInErrorGetter++; |
| var error = this; |
| console.log(" " + caseStr + " in 'toString' getter[" + getterEntry + "]: error.message = '" + error.message + "'"); |
| |
| shouldContainNoSecrets(error.message, inMainScript); |
| |
| return function() { |
| return "GetterErrorToString: getter[" + getterEntry + "] " + error.message; |
| } |
| } |
| }; |
| |
| function installToStringGettersToCheckErrorMessageForSecrets() { |
| assert("toStringGettersInstalled == false"); |
| Object.defineProperty(Error.prototype, 'toString', replacementToStringDescriptor); |
| toStringGettersInstalled = true; |
| } |
| |
| function resetToStringGetters() { |
| assert("toStringGettersInstalled == true"); |
| Object.defineProperty(Error.prototype, 'toString', originalToStringDescriptor); |
| toStringGettersInstalled = false; |
| } |
| |
| function incCaseIndex() { |
| caseIndex++; |
| caseStr = "[case " + caseIndex + "]"; |
| } |
| |
| function doTest(index, newErrorName) { |
| assertLessThan(index, errorTypes.length); |
| |
| let errorType = errorTypes[index]; |
| let errorTypeName = errorTypeNames[index]; |
| |
| incCaseIndex(); |
| testedErrorTypeCount++; |
| |
| timesInErrorGetter = 0; |
| |
| logTitle("Test " + caseStr); |
| console.log(" " + caseStr + " let e = new " + errorTypeName + "('Error thrown from main script body');"); |
| let e = new errorType("Error thrown from main script body"); |
| if (newErrorName) { |
| console.log(" " + caseStr + " e.name = '" + newErrorName + "';"); |
| e.name = newErrorName; |
| } |
| |
| console.log(" [" + errorTypeName + "] e = '" + e + "'"); |
| console.log(" [" + errorTypeName + "] e.name = '" + e.name + "'"); |
| console.log(" [" + errorTypeName + "] e.message = '" + e.message + "'"); |
| console.log(" [" + errorTypeName + "] e.toString() = '" + e.toString() + "'"); |
| console.log(""); |
| |
| if (nameGettersInstalled) |
| assert("timesInErrorGetter == 3"); |
| else if (toStringGettersInstalled) |
| assert("timesInErrorGetter == 2"); |
| else |
| assert("timesInErrorGetter == 0"); |
| |
| console.log(" " + caseStr + " let caughtE; try { throw e } catch(err) { caughtE = err }"); |
| let caughtE; try { throw e } catch(err) { caughtE = err } |
| |
| console.log(" [" + errorTypeName + "] caughtE = '" + caughtE + "'"); |
| console.log(" [" + errorTypeName + "] caughtE.name = '" + caughtE.name + "'"); |
| console.log(" [" + errorTypeName + "] caughtE.message = '" + caughtE.message + "'"); |
| console.log(" [" + errorTypeName + "] caughtE.toString() = '" + caughtE.toString() + "'"); |
| console.log(""); |
| |
| if (nameGettersInstalled) |
| assert("timesInErrorGetter == 6"); |
| else if (toStringGettersInstalled) |
| assert("timesInErrorGetter == 4"); |
| else |
| assert("timesInErrorGetter == 0"); |
| |
| console.log(' throw e;'); |
| throw e; |
| } |
| </script> |
| |
| <script> |
| // Test throwing uncaught errors with no getters. |
| testedErrorTypeCount = 0; |
| </script> |
| <script> doTest(0) </script> |
| <script> doTest(1) </script> |
| <script> doTest(2) </script> |
| <script> doTest(3) </script> |
| <script> doTest(4) </script> |
| <script> doTest(5) </script> |
| <script> doTest(6) </script> |
| <script> |
| assert("testedErrorTypeCount == errorTypes.length"); |
| </script> |
| |
| <script> |
| // Test throwing uncaught errors with explicitly set names. |
| testedErrorTypeCount = 0; |
| </script> |
| <script> doTest(0, "My" + errorTypeNames[0]) </script> |
| <script> doTest(1, "My" + errorTypeNames[1]) </script> |
| <script> doTest(2, "My" + errorTypeNames[2]) </script> |
| <script> doTest(3, "My" + errorTypeNames[3]) </script> |
| <script> doTest(4, "My" + errorTypeNames[4]) </script> |
| <script> doTest(5, "My" + errorTypeNames[5]) </script> |
| <script> doTest(6, "My" + errorTypeNames[6]) </script> |
| <script> |
| assert("testedErrorTypeCount == errorTypes.length"); |
| </script> |
| |
| <script> |
| // Test throwing uncaught errors with 'name' getters set. |
| testedErrorTypeCount = 0; |
| installNameGettersToCheckErrorMessageForSecrets(); |
| </script> |
| <script> doTest(0) </script> |
| <script> doTest(1) </script> |
| <script> doTest(2) </script> |
| <script> doTest(3) </script> |
| <script> doTest(4) </script> |
| <script> doTest(5) </script> |
| <script> doTest(6) </script> |
| <script> |
| assert("testedErrorTypeCount == errorTypes.length"); |
| resetNameGetters(); |
| </script> |
| |
| <script> |
| // Test throwing uncaught errors with 'toString' getters set. |
| testedErrorTypeCount = 0; |
| installToStringGettersToCheckErrorMessageForSecrets(); |
| </script> |
| <script> doTest(0) </script> |
| <script> doTest(1) </script> |
| <script> doTest(2) </script> |
| <script> doTest(3) </script> |
| <script> doTest(4) </script> |
| <script> doTest(5) </script> |
| <script> doTest(6) </script> |
| <script> |
| assert("testedErrorTypeCount == errorTypes.length"); |
| resetToStringGetters(); |
| </script> |
| |
| |
| <script> |
| // Test loading a document from another domain that has a SyntaxError with no getters. |
| logTitle("Test uncaught error from a script from another domain"); |
| incCaseIndex(); |
| </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-syntax-error.js"></script/> |
| |
| <script> |
| // Test loading a document from another domain that has a SyntaxError with 'name' getters installed. |
| logTitle("Test uncaught error from a script from another domain with 'name' getters installed"); |
| incCaseIndex(); |
| installNameGettersToCheckErrorMessageForSecrets(); |
| </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-syntax-error.js"></script/> |
| <script> |
| resetNameGetters(); |
| </script> |
| |
| <script> |
| // Test loading a document from another domain that has a SyntaxError with 'toString' getters installed. |
| logTitle("Test uncaught error from a script from another domain with 'toString' getters installed"); |
| incCaseIndex(); |
| installToStringGettersToCheckErrorMessageForSecrets(); |
| </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-syntax-error.js"></script/> |
| <script> |
| resetToStringGetters(); |
| </script> |
| |
| <script> |
| // Test throwing from other domain script with no getters installed. |
| </script> |
| <script> errorTypeIndexToTest = 0; </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-throw-error.js"></script/> |
| <script> errorTypeIndexToTest = 1; </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-throw-error.js"></script/> |
| <script> errorTypeIndexToTest = 2; </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-throw-error.js"></script/> |
| <script> errorTypeIndexToTest = 3; </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-throw-error.js"></script/> |
| <script> errorTypeIndexToTest = 4; </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-throw-error.js"></script/> |
| <script> errorTypeIndexToTest = 5; </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-throw-error.js"></script/> |
| <script> errorTypeIndexToTest = 6; </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-throw-error.js"></script/> |
| |
| <script> |
| // Test throwing from other domain script when Error.prototype has a 'name' getter. |
| installNameGettersToCheckErrorMessageForSecrets(); |
| </script> |
| <script> errorTypeIndexToTest = 0; </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-throw-error.js"></script/> |
| <script> errorTypeIndexToTest = 1; </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-throw-error.js"></script/> |
| <script> errorTypeIndexToTest = 2; </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-throw-error.js"></script/> |
| <script> errorTypeIndexToTest = 3; </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-throw-error.js"></script/> |
| <script> errorTypeIndexToTest = 4; </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-throw-error.js"></script/> |
| <script> errorTypeIndexToTest = 5; </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-throw-error.js"></script/> |
| <script> errorTypeIndexToTest = 6; </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-throw-error.js"></script/> |
| <script> resetNameGetters(); </script> |
| |
| <script> |
| // Test throwing from other domain script when Error.prototype has a 'toString' getter. |
| installToStringGettersToCheckErrorMessageForSecrets(); |
| </script> |
| <script> errorTypeIndexToTest = 0; </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-throw-error.js"></script/> |
| <script> errorTypeIndexToTest = 1; </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-throw-error.js"></script/> |
| <script> errorTypeIndexToTest = 2; </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-throw-error.js"></script/> |
| <script> errorTypeIndexToTest = 3; </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-throw-error.js"></script/> |
| <script> errorTypeIndexToTest = 4; </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-throw-error.js"></script/> |
| <script> errorTypeIndexToTest = 5; </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-throw-error.js"></script/> |
| <script> errorTypeIndexToTest = 6; </script> |
| <script src="../../resources/redirect.py?url=http://localhost:8000/security/resources/regress-52192-throw-error.js"></script/> |
| <script> resetToStringGetters(); </script> |
| |
| <script> |
| if (window.testRunner) { |
| // Allow the console message to be dumped out. |
| setTimeout(function() { |
| testRunner.notifyDone(); |
| }, 0); |
| } |
| </script> |
| |
| </body> |
| </html> |