dom/xbl/test/file_bug821850.xhtml

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/xbl/test/file_bug821850.xhtml	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,298 @@
     1.4 +<html xmlns="http://www.w3.org/1999/xhtml">
     1.5 +<!--
     1.6 +https://bugzilla.mozilla.org/show_bug.cgi?id=821850
     1.7 +-->
     1.8 +<head>
     1.9 +  <bindings xmlns="http://www.mozilla.org/xbl">
    1.10 +    <binding id="testBinding">
    1.11 +      <implementation>
    1.12 +        <constructor>
    1.13 +          // Store a property as an expando on the bound element.
    1.14 +          this._prop = "propVal";
    1.15 +
    1.16 +          // Wait for both constructors to fire.
    1.17 +          window.constructorCount = (window.constructorCount + 1) || 1;
    1.18 +          if (window.constructorCount != 2)
    1.19 +            return;
    1.20 +
    1.21 +          // Grab some basic infrastructure off the content window.
    1.22 +          var win = XPCNativeWrapper.unwrap(window);
    1.23 +          SpecialPowers = win.SpecialPowers;
    1.24 +          Cu = SpecialPowers.Cu;
    1.25 +          is = win.is;
    1.26 +          ok = win.ok;
    1.27 +          SimpleTest = win.SimpleTest;
    1.28 +
    1.29 +          // Stick some expandos on the content window.
    1.30 +          window.xrayExpando = 3;
    1.31 +          win.primitiveExpando = 11;
    1.32 +          win.stringExpando = "stringExpando";
    1.33 +          win.objectExpando = { foo: 12 };
    1.34 +          win.globalExpando = SpecialPowers.unwrap(Cu.getGlobalForObject({}));
    1.35 +          win.functionExpando = function() { return "called" };
    1.36 +          win.functionExpando.prop = 2;
    1.37 +
    1.38 +          // Make sure we're Xraying.
    1.39 +          ok(Cu.isXrayWrapper(window), "Window is Xrayed");
    1.40 +          ok(Cu.isXrayWrapper(document), "Document is Xrayed");
    1.41 +
    1.42 +          var bound = document.getElementById('bound');
    1.43 +          ok(bound, "bound is non-null");
    1.44 +          is(bound.method('baz'), "method:baz", "Xray methods work");
    1.45 +          is(bound.prop, "propVal", "Property Xrays work");
    1.46 +          is(bound.primitiveField, undefined, "Xrays don't show fields");
    1.47 +          is(bound.wrappedJSObject.primitiveField, 2, "Waiving Xrays show fields");
    1.48 +
    1.49 +          // Check exposure behavior.
    1.50 +          is(typeof bound.unexposedMethod, 'function',
    1.51 +             "Unexposed method should be visible to XBL");
    1.52 +          is(typeof bound.wrappedJSObject.unexposedMethod, 'undefined',
    1.53 +             "Unexposed method should not be defined in content");
    1.54 +          is(typeof bound.unexposedProperty, 'number',
    1.55 +             "Unexposed property should be visible to XBL");
    1.56 +          is(typeof bound.wrappedJSObject.unexposedProperty, 'undefined',
    1.57 +             "Unexposed property should not be defined in content");
    1.58 +
    1.59 +          // Check that here HTMLImageElement.QueryInterface works
    1.60 +          var img = document.querySelector("img");
    1.61 +          ok("QueryInterface" in img,
    1.62 +             "Should have a img.QueryInterface here");
    1.63 +          is(img.QueryInterface(Components.interfaces.nsIImageLoadingContent),
    1.64 +             img, "Should be able to QI the image");
    1.65 +
    1.66 +          // Make sure standard constructors work right in the presence of
    1.67 +          // sandboxPrototype and Xray-resolved constructors.
    1.68 +          is(window.Function, XPCNativeWrapper(window.wrappedJSObject.Function),
    1.69 +             "window.Function comes from the window, not the global");
    1.70 +          ok(Function != window.Function, "Function constructors are distinct");
    1.71 +          is(Object.getPrototypeOf(Function.prototype), Object.getPrototypeOf({foo: 42}),
    1.72 +             "Function constructor is local");
    1.73 +
    1.74 +          // This gets invoked by an event handler.
    1.75 +          window.finish = function() {
    1.76 +            // Content messed with stuff. Make sure we still see the right thing.
    1.77 +            is(bound.method('bay'), "method:bay", "Xray methods work");
    1.78 +            is(bound.wrappedJSObject.method('bay'), "hah", "Xray waived methods work");
    1.79 +            is(bound.prop, "set:someOtherVal", "Xray props work");
    1.80 +            is(bound.wrappedJSObject.prop, "redefined", "Xray waived props work");
    1.81 +            is(bound.wrappedJSObject.primitiveField, 321, "Can't do anything about redefined fields");
    1.82 +
    1.83 +            SimpleTest.finish();
    1.84 +          }
    1.85 +
    1.86 +          // Hand things off to content. Content will call us back.
    1.87 +          win.go();
    1.88 +        </constructor>
    1.89 +        <field name="primitiveField">2</field>
    1.90 +        <method name="unexposedMethod"><body></body></method>
    1.91 +        <property name="unexposedProperty" onget="return 2;" readonly="true"></property>
    1.92 +        <method name="method" exposeToUntrustedContent="true">
    1.93 +          <parameter name="arg" />
    1.94 +          <body>
    1.95 +            return "method:" + arg;
    1.96 +          </body>
    1.97 +        </method>
    1.98 +        <method name="passMeAJSObject" exposeToUntrustedContent="true">
    1.99 +          <parameter name="arg" />
   1.100 +          <body>
   1.101 +            is(typeof arg.prop, 'undefined', "No properties");
   1.102 +            is(Object.getOwnPropertyNames(arg).length, 0, "Should have no own properties");
   1.103 +            try {
   1.104 +              arg.foo = 2;
   1.105 +              ok(true, "Stuff fails silently");
   1.106 +            } catch (e) {
   1.107 +              ok(false, "Stuff should fail silently");
   1.108 +            }
   1.109 +            is(typeof arg.foo, 'undefined', "Shouldn't place props");
   1.110 +          </body>
   1.111 +        </method>
   1.112 +        <property name="prop" exposeToUntrustedContent="true">
   1.113 +          <getter>return this._prop;</getter>
   1.114 +          <setter>this._prop = "set:" + val;</setter>
   1.115 +        </property>
   1.116 +      </implementation>
   1.117 +      <handlers>
   1.118 +        <handler event="testevent" action="ok(true, 'called event handler'); finish();" allowuntrusted="true"/>
   1.119 +        <handler event="testtrusted" action="ok(true, 'called trusted handler'); window.wrappedJSObject.triggeredTrustedHandler = true;"/>
   1.120 +        <handler event="keyup" action="ok(true, 'called untrusted key handler'); window.wrappedJSObject.triggeredUntrustedKeyHandler = true;" allowuntrusted="true"/>
   1.121 +        <handler event="keydown" action="ok(true, 'called trusted key handler'); window.wrappedJSObject.triggeredTrustedKeyHandler = true;"/>
   1.122 +      </handlers>
   1.123 +    </binding>
   1.124 +  </bindings>
   1.125 +  <script type="application/javascript">
   1.126 +  <![CDATA[
   1.127 +
   1.128 +  ok = parent.ok;
   1.129 +  is = parent.is;
   1.130 +  SimpleTest = parent.SimpleTest;
   1.131 +  SpecialPowers = parent.SpecialPowers;
   1.132 +
   1.133 +  // Test the Xray waiving behavior when accessing fields. We should be able to
   1.134 +  // see sequential JS-implemented properties, but should regain Xrays when we
   1.135 +  // hit a native property.
   1.136 +  window.contentVal = { foo: 10, rabbit: { hole: { bar: 100, win: window} } };
   1.137 +  ok(true, "Set contentVal");
   1.138 +
   1.139 +  // Check that we're not exposing QueryInterface to non-XBL code
   1.140 +  ok(!("QueryInterface" in document),
   1.141 +     "Should not have a document.QueryInterface here");
   1.142 +
   1.143 +  function go() {
   1.144 +    "use strict";
   1.145 +
   1.146 +    // Test what we can and cannot access in the XBL scope.
   1.147 +    is(typeof window.xrayExpando, "undefined", "Xray expandos are private to the caller");
   1.148 +    is(window.primitiveExpando, 11, "Can see waived expandos");
   1.149 +    is(window.stringExpando, "stringExpando", "Can see waived expandos");
   1.150 +    is(typeof window.objectExpando, "object", "object expando exists");
   1.151 +    checkThrows(function() window.objectExpando.foo);
   1.152 +    is(SpecialPowers.wrap(window.objectExpando).foo, 12, "SpecialPowers sees the right thing");
   1.153 +    is(typeof window.globalExpando, "object", "Can see global object");
   1.154 +    checkThrows(function() window.globalExpando.win);
   1.155 +    is(window.functionExpando(), "called", "XBL functions are callable");
   1.156 +    checkThrows(function() window.functionExpando.prop);
   1.157 +
   1.158 +    // Inspect the bound element.
   1.159 +    var bound = document.getElementById('bound');
   1.160 +    is(bound.primitiveField, 2, "Can see primitive fields");
   1.161 +    is(bound.method("foo"), "method:foo", "Can invoke XBL method from content");
   1.162 +    is(bound.prop, "propVal", "Can access properties from content");
   1.163 +    bound.prop = "someOtherVal";
   1.164 +    is(bound.prop, "set:someOtherVal", "Can set properties from content");
   1.165 +
   1.166 +    // Make sure we can't pass JS objects to the XBL scope.
   1.167 +    var proto = bound.__proto__;
   1.168 +    proto.passMeAJSObject({prop: 2});
   1.169 +
   1.170 +    //
   1.171 +    // Try sticking a bunch of stuff on the prototype object.
   1.172 +    //
   1.173 +
   1.174 +    proto.someExpando = 201;
   1.175 +    is(bound.someExpando, 201, "Can stick non-XBL properties on the proto");
   1.176 +
   1.177 +    // Previously, this code checked that content couldn't tamper with its XBL
   1.178 +    // prototype. But we decided to allow this to reduce regression risk, so for
   1.179 +    // now just check that this works.
   1.180 +    function checkMayTamper(obj, propName, desc) {
   1.181 +      var accessor = !('value' in Object.getOwnPropertyDescriptor(obj, propName));
   1.182 +      if (!accessor)
   1.183 +        checkAllowed(function() { obj[propName] = function() {} }, desc + ": assign");
   1.184 +      checkAllowed(function() { Object.defineProperty(obj, propName, {configurable: true, value: 3}) }, desc + ": define with value");
   1.185 +      checkAllowed(function() { Object.defineProperty(obj, propName, {configurable: true, writable: true}) }, desc + ": make writable");
   1.186 +      checkAllowed(function() { Object.defineProperty(obj, propName, {configurable: true}) }, desc + ": make configurable");
   1.187 +      checkAllowed(function() { Object.defineProperty(obj, propName, {configurable: true, get: function() {}}) }, desc + ": define with getter");
   1.188 +      checkAllowed(function() { Object.defineProperty(obj, propName, {configurable: true, set: function() {}}) }, desc + ": define with setter");
   1.189 +
   1.190 +      // Windows are implemented as proxies, and Proxy::delete_ doesn't currently
   1.191 +      // pass strict around. Work around it in the window.binding case by just
   1.192 +      // checking if delete returns false.
   1.193 +      // manually.
   1.194 +      checkAllowed(function() { delete obj[propName]; }, desc + ": delete");
   1.195 +
   1.196 +      if (!accessor)
   1.197 +        checkAllowed(function() { obj[propName] = function() {} }, desc + ": assign (again)");
   1.198 +    }
   1.199 +
   1.200 +    // Make sure content can do whatever it wants with the prototype.
   1.201 +    checkMayTamper(proto, 'method', "XBL Proto Method");
   1.202 +    checkMayTamper(proto, 'prop', "XBL Proto Prop");
   1.203 +    checkMayTamper(proto, 'primitiveField', "XBL Field Accessor");
   1.204 +
   1.205 +    // Tamper with the derived object. This doesn't affect the XBL scope thanks
   1.206 +    // to Xrays.
   1.207 +    bound.method = function() { return "heh"; };
   1.208 +    Object.defineProperty(bound, 'method', {value: function() { return "hah" }});
   1.209 +    Object.defineProperty(bound, 'prop', {value: "redefined"});
   1.210 +    bound.primitiveField = 321;
   1.211 +
   1.212 +    // We need a chrome window to create trusted events. This isn't really doable
   1.213 +    // in child processes, so let's just skip if that's the case.
   1.214 +    if (SpecialPowers.isMainProcess()) {
   1.215 +      var Ci = SpecialPowers.Ci;
   1.216 +      var chromeWin = SpecialPowers.wrap(window.top)
   1.217 +                                   .QueryInterface(Ci.nsIInterfaceRequestor)
   1.218 +                                   .getInterface(Ci.nsIWebNavigation)
   1.219 +                                   .QueryInterface(Ci.nsIDocShell)
   1.220 +                                   .chromeEventHandler.ownerDocument.defaultView;
   1.221 +
   1.222 +      // Untrusted events should not trigger event handlers without
   1.223 +      // exposeToUntrustedContent=true.
   1.224 +      window.triggeredTrustedHandler = false;
   1.225 +      var untrustedEvent = new CustomEvent('testtrusted');
   1.226 +      ok(!untrustedEvent.isTrusted, "Created an untrusted event");
   1.227 +      is(untrustedEvent.type, 'testtrusted', "Constructor should see type");
   1.228 +      bound.dispatchEvent(untrustedEvent);
   1.229 +      ok(!window.triggeredTrustedHandler, "untrusted events should not trigger trusted handler");
   1.230 +      var trustedEvent = new chromeWin.CustomEvent('testtrusted');
   1.231 +      ok(trustedEvent.isTrusted, "Created a trusted event");
   1.232 +      is(trustedEvent.type, 'testtrusted', "Wrapped constructor should see type");
   1.233 +      SpecialPowers.wrap(bound).dispatchEvent(trustedEvent);
   1.234 +      ok(window.triggeredTrustedHandler, "trusted events should trigger trusted handler");
   1.235 +
   1.236 +      //
   1.237 +      // We check key events as well, since they're implemented differently.
   1.238 +      //
   1.239 +      // NB: We don't check isTrusted on the events we create here, because
   1.240 +      // according to smaug, old-style event initialization doesn't mark the
   1.241 +      // event as trusted until it's dispatched.
   1.242 +      //
   1.243 +
   1.244 +      window.triggeredUntrustedKeyHandler = false;
   1.245 +      window.triggeredTrustedKeyHandler = false;
   1.246 +
   1.247 +      // Untrusted event, permissive handler.
   1.248 +      var untrustedKeyEvent = document.createEvent('KeyboardEvent');
   1.249 +      untrustedKeyEvent.initEvent('keyup', true, true);
   1.250 +      bound.dispatchEvent(untrustedKeyEvent);
   1.251 +      ok(window.triggeredUntrustedKeyHandler, "untrusted key events should trigger untrusted handler");
   1.252 +
   1.253 +      // Untrusted event, strict handler.
   1.254 +      var fakeTrustedKeyEvent = document.createEvent('KeyboardEvent');
   1.255 +      fakeTrustedKeyEvent.initEvent('keydown', true, true);
   1.256 +      bound.dispatchEvent(fakeTrustedKeyEvent);
   1.257 +      ok(!window.triggeredTrustedKeyHandler, "untrusted key events should not trigger trusted handler");
   1.258 +
   1.259 +      // Trusted event, strict handler.
   1.260 +      var trustedKeyEvent = chromeWin.document.createEvent('KeyboardEvent');
   1.261 +      trustedKeyEvent.initEvent('keydown', true, true);
   1.262 +      SpecialPowers.wrap(bound).dispatchEvent(trustedKeyEvent);
   1.263 +      ok(window.triggeredTrustedKeyHandler, "trusted key events should trigger trusted handler");
   1.264 +    }
   1.265 +
   1.266 +    // Hand control back to the XBL scope by dispatching an event on the bound element.
   1.267 +    bound.dispatchEvent(new CustomEvent('testevent'));
   1.268 +  }
   1.269 +
   1.270 +  function checkThrows(fn) {
   1.271 +    try { fn(); ok(false, "Should have thrown"); }
   1.272 +    catch (e) { ok(!!/denied|insecure/.exec(e), "Should have thrown security exception: " + e); }
   1.273 +  }
   1.274 +
   1.275 +  function checkAllowed(fn, desc) {
   1.276 +    try { fn(); ok(true, desc + ": Didn't throw"); }
   1.277 +    catch (e) { ok(false, desc + ": Threw: " + e); }
   1.278 +  }
   1.279 +
   1.280 +  function setup() {
   1.281 +    // When the bindings are applied, the constructor will be invoked and the
   1.282 +    // test will continue.
   1.283 +    document.getElementById('bound').style.MozBinding = 'url(#testBinding)';
   1.284 +    document.getElementById('bound2').style.MozBinding = 'url(#testBinding)';
   1.285 +  }
   1.286 +
   1.287 +  ]]>
   1.288 +</script>
   1.289 +</head>
   1.290 +<body onload="setup()">
   1.291 +<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=821850">Mozilla Bug 821850</a>
   1.292 +<p id="display"></p>
   1.293 +<div id="content">
   1.294 +  <div id="bound">Bound element</div>
   1.295 +  <div id="bound2">Bound element</div>
   1.296 +  <img/>
   1.297 +</div>
   1.298 +<pre id="test">
   1.299 +</pre>
   1.300 +</body>
   1.301 +</html>

mercurial