Bug 1116269 - Add 'crypto' to sandbox global properties, r=gabor
authorMartin Thomson <martin.thomson@gmail.com>
Fri, 09 Jan 2015 10:55:44 -0800
changeset 236090 da03d6aff37d92878b0c19897fd759db92600f59
parent 236089 b206ea15cb59f9b0ae591404e811d0eff9e7a459
child 236091 0c40a9e043cea4f5c3bf9e2e51f1ce6531b32567
push id384
push usermartin.thomson@gmail.com
push dateFri, 09 Jan 2015 21:26:39 +0000
reviewersgabor
bugs1116269
milestone37.0a1
Bug 1116269 - Add 'crypto' to sandbox global properties, r=gabor
js/xpconnect/src/Sandbox.cpp
js/xpconnect/src/xpcprivate.h
js/xpconnect/tests/unit/test_crypto.js
js/xpconnect/tests/unit/xpcshell.ini
--- a/js/xpconnect/src/Sandbox.cpp
+++ b/js/xpconnect/src/Sandbox.cpp
@@ -22,18 +22,20 @@
 #include "nsNetUtil.h"
 #include "nsNullPrincipal.h"
 #include "nsPrincipal.h"
 #include "nsXMLHttpRequest.h"
 #include "WrapperFactory.h"
 #include "xpcprivate.h"
 #include "XPCWrapper.h"
 #include "XrayWrapper.h"
+#include "Crypto.h"
 #include "mozilla/dom/BindingUtils.h"
 #include "mozilla/dom/BlobBinding.h"
+#include "mozilla/dom/CryptoBinding.h"
 #include "mozilla/dom/CSSBinding.h"
 #include "mozilla/dom/indexedDB/IndexedDatabaseManager.h"
 #include "mozilla/dom/FileBinding.h"
 #include "mozilla/dom/PromiseBinding.h"
 #include "mozilla/dom/ScriptSettings.h"
 #include "mozilla/dom/TextDecoderBinding.h"
 #include "mozilla/dom/TextEncoderBinding.h"
 #include "mozilla/dom/URLBinding.h"
@@ -213,16 +215,30 @@ SandboxCreateXMLHttpRequest(JSContext *c
     rv = nsContentUtils::WrapNative(cx, xhr, args.rval());
     if (NS_FAILED(rv))
         return false;
 
     return true;
 }
 
 static bool
+SandboxCreateCrypto(JSContext *cx, JS::HandleObject obj)
+{
+    MOZ_ASSERT(JS_IsGlobalObject(obj));
+
+    nsIGlobalObject* native = xpc::NativeGlobal(obj);
+    MOZ_ASSERT(native);
+
+    dom::Crypto* crypto = new dom::Crypto();
+    crypto->Init(native);
+    JS::RootedObject wrapped(cx, dom::CryptoBinding::Wrap(cx, crypto));
+    return JS_DefineProperty(cx, obj, "crypto", wrapped, JSPROP_ENUMERATE);
+}
+
+static bool
 SandboxIsProxy(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() < 1) {
         JS_ReportError(cx, "Function requires at least 1 argument");
         return false;
     }
     if (!args[0].isObject()) {
@@ -778,16 +794,18 @@ xpc::GlobalProperties::Parse(JSContext *
         } else if (!strcmp(name.ptr(), "atob")) {
             atob = true;
         } else if (!strcmp(name.ptr(), "btoa")) {
             btoa = true;
         } else if (!strcmp(name.ptr(), "Blob")) {
             Blob = true;
         } else if (!strcmp(name.ptr(), "File")) {
             File = true;
+        } else if (!strcmp(name.ptr(), "crypto")) {
+            crypto = true;
         } else {
             JS_ReportError(cx, "Unknown property name: %s", name.ptr());
             return false;
         }
     }
     return true;
 }
 
@@ -832,16 +850,19 @@ xpc::GlobalProperties::Define(JSContext 
     if (Blob &&
         !dom::BlobBinding::GetConstructorObject(cx, obj))
         return false;
 
     if (File &&
         !dom::FileBinding::GetConstructorObject(cx, obj))
         return false;
 
+    if (crypto && !SandboxCreateCrypto(cx, obj))
+        return false;
+
     return true;
 }
 
 nsresult
 xpc::CreateSandboxObject(JSContext *cx, MutableHandleValue vp, nsISupports *prinOrSop,
                          SandboxOptions& options)
 {
     // Create the sandbox global object
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -3366,16 +3366,17 @@ struct GlobalProperties {
     bool TextDecoder : 1;
     bool TextEncoder : 1;
     bool URL : 1;
     bool URLSearchParams : 1;
     bool atob : 1;
     bool btoa : 1;
     bool Blob : 1;
     bool File : 1;
+    bool crypto : 1;
 };
 
 // Infallible.
 already_AddRefed<nsIXPCComponents_utils_Sandbox>
 NewSandboxConstructor();
 
 // Returns true if class of 'obj' is SandboxClass.
 bool
new file mode 100644
--- /dev/null
+++ b/js/xpconnect/tests/unit/test_crypto.js
@@ -0,0 +1,28 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+function run_test() {
+  let Cu = Components.utils;
+  let sb = new Cu.Sandbox('https://www.example.com',
+                          { wantGlobalProperties:
+                            ["crypto", "TextEncoder", "TextDecoder"]
+                          });
+  sb.ok = ok;
+  Cu.evalInSandbox('ok(this.crypto);', sb);
+  Cu.evalInSandbox('ok(this.crypto.subtle);', sb);
+  sb.do_check_eq = do_check_eq;
+  let innerPromise = new Promise(r => (sb.test_done = r));
+  Cu.evalInSandbox('crypto.subtle.digest("SHA-256", ' +
+                   '                     new TextEncoder("utf-8").encode("abc"))' +
+                   '  .then(h => do_check_eq(new Uint16Array(h)[0], 30906))' +
+                   '  .then(test_done);', sb);
+
+  Cu.importGlobalProperties(["crypto"]);
+  ok(crypto);
+  ok(crypto.subtle);
+  let outerPromise = crypto.subtle.digest("SHA-256", new TextEncoder("utf-8").encode("abc"))
+      .then(h => do_check_eq(new Uint16Array(h)[0], 30906));
+
+  do_test_pending();
+  Promise.all([innerPromise, outerPromise]).then(() => do_test_finished());
+}
--- a/js/xpconnect/tests/unit/xpcshell.ini
+++ b/js/xpconnect/tests/unit/xpcshell.ini
@@ -86,16 +86,17 @@ fail-if = os == "android"
 [test_sandbox_metadata.js]
 [test_exportFunction.js]
 [test_promise.js]
 [test_returncode.js]
 skip-if = os == "android" # native test components aren't available on Android
 [test_textDecoder.js]
 [test_url.js]
 [test_URLSearchParams.js]
+[test_crypto.js]
 [test_css.js]
 [test_sandbox_atob.js]
 [test_isProxy.js]
 [test_getObjectPrincipal.js]
 [test_watchdog_enable.js]
 head = head_watchdog.js
 [test_watchdog_disable.js]
 head = head_watchdog.js