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 248885 da03d6aff37d92878b0c19897fd759db92600f59
parent 248884 b206ea15cb59f9b0ae591404e811d0eff9e7a459
child 248886 0c40a9e043cea4f5c3bf9e2e51f1ce6531b32567
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgabor
bugs1116269
milestone37.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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