Skip to content
Permalink
Browse files

Implement window.crypto.getRandomValues()

  • Loading branch information...
ttaubert committed Jun 26, 2015
1 parent 73b52c0 commit 92874a89d260bf4f17849ed93bddfe5a70cd312a
@@ -78,3 +78,4 @@ string_cache = "0.1"
string_cache_plugin = "0.1"
euclid = "0.1"
tendril = "0.1.1"
rand = "0.3"
@@ -62,6 +62,10 @@ pub enum Error {
DataClone,
/// NoModificationAllowedError DOMException
NoModificationAllowed,
/// QuotaExceededError DOMException
QuotaExceeded,
/// TypeMismatchError DOMException
TypeMismatch,

/// TypeError JavaScript Error
Type(DOMString),
@@ -101,6 +105,8 @@ pub fn throw_dom_exception(cx: *mut JSContext, global: GlobalRef,
Error::InvalidNodeType => DOMErrorName::InvalidNodeTypeError,
Error::DataClone => DOMErrorName::DataCloneError,
Error::NoModificationAllowed => DOMErrorName::NoModificationAllowedError,
Error::QuotaExceeded => DOMErrorName::QuotaExceededError,
Error::TypeMismatch => DOMErrorName::TypeMismatchError,
Error::Type(message) => {
assert!(unsafe { JS_IsExceptionPending(cx) } == 0);
throw_type_error(cx, &message);
@@ -0,0 +1,82 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::CryptoBinding;
use dom::bindings::codegen::Bindings::CryptoBinding::CryptoMethods;
use dom::bindings::error::{Error, Fallible};
use dom::bindings::global::GlobalRef;
use dom::bindings::js::Root;
use dom::bindings::utils::{Reflector, reflect_dom_object};
use dom::bindings::cell::DOMRefCell;

use js::jsapi::{JSContext, JSObject};
use js::jsapi::{JS_GetObjectAsArrayBufferView, JS_GetArrayBufferViewType, Type};

use std::ptr;
use std::slice;

use rand::{Rng, OsRng};

no_jsmanaged_fields!(OsRng);

// https://developer.mozilla.org/en-US/docs/Web/API/Crypto
#[dom_struct]
pub struct Crypto {
reflector_: Reflector,
rng: DOMRefCell<OsRng>,
}

impl Crypto {
fn new_inherited() -> Crypto {
Crypto {
reflector_: Reflector::new(),
rng: DOMRefCell::new(OsRng::new().unwrap()),
}
}

pub fn new(global: GlobalRef) -> Root<Crypto> {
reflect_dom_object(box Crypto::new_inherited(), global, CryptoBinding::Wrap)
}
}

impl<'a> CryptoMethods for &'a Crypto {
// https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#Crypto-method-getRandomValues
#[allow(unsafe_code)]
fn GetRandomValues(self, _cx: *mut JSContext, input: *mut JSObject)
-> Fallible<*mut JSObject> {
let mut length = 0;
let mut data = ptr::null_mut();
if unsafe { JS_GetObjectAsArrayBufferView(input, &mut length, &mut data).is_null() } {
return Err(Error::Type("Argument to Crypto.getRandomValues is not an ArrayBufferView".to_owned()));
}
if !is_integer_buffer(input) {
return Err(Error::TypeMismatch);
}
if length > 65536 {
return Err(Error::QuotaExceeded);
}

let mut buffer = unsafe {
slice::from_raw_parts_mut(data, length as usize)
};

self.rng.borrow_mut().fill_bytes(&mut buffer);

Ok(input)
}
}

#[allow(unsafe_code)]
fn is_integer_buffer(input: *mut JSObject) -> bool {
match unsafe { JS_GetArrayBufferViewType(input) } {
Type::Uint8 |
Type::Uint8Clamped |
Type::Int8 |
Type::Uint16 |
Type::Int16 |
Type::Uint32 |
Type::Int32 => true,
_ => false
}
}
@@ -32,6 +32,7 @@ pub enum DOMErrorName {
NetworkError = DOMExceptionConstants::NETWORK_ERR,
AbortError = DOMExceptionConstants::ABORT_ERR,
URLMismatchError = DOMExceptionConstants::URL_MISMATCH_ERR,
TypeMismatchError = DOMExceptionConstants::TYPE_MISMATCH_ERR,
QuotaExceededError = DOMExceptionConstants::QUOTA_EXCEEDED_ERR,
TimeoutError = DOMExceptionConstants::TIMEOUT_ERR,
InvalidNodeTypeError = DOMExceptionConstants::INVALID_NODE_TYPE_ERR,
@@ -93,6 +94,7 @@ impl<'a> DOMExceptionMethods for &'a DOMException {
DOMErrorName::NetworkError => "A network error occurred.",
DOMErrorName::AbortError => "The operation was aborted.",
DOMErrorName::URLMismatchError => "The given URL does not match another URL.",
DOMErrorName::TypeMismatchError => "The given type does not match any expected type.",
DOMErrorName::QuotaExceededError => "The quota has been exceeded.",
DOMErrorName::TimeoutError => "The operation timed out.",
DOMErrorName::InvalidNodeTypeError =>
@@ -197,6 +197,7 @@ pub mod closeevent;
pub mod comment;
pub mod console;
mod create;
pub mod crypto;
pub mod customevent;
pub mod dedicatedworkerglobalscope;
pub mod document;
@@ -0,0 +1,25 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html#crypto-interface
*
*/

[NoInterfaceObject]
interface GlobalCrypto {
readonly attribute Crypto crypto;
};

Window implements GlobalCrypto;
WorkerGlobalScope implements GlobalCrypto;

//[Exposed=(Window,Worker)]
interface Crypto {
//readonly attribute SubtleCrypto subtle;
//ArrayBufferView getRandomValues(ArrayBufferView array);
[Throws]
ArrayBufferView getRandomValues(object array);
};
@@ -19,6 +19,7 @@ use dom::bindings::num::Finite;
use dom::bindings::utils::{GlobalStaticData, Reflectable, WindowProxyHandler};
use dom::browsercontext::BrowserContext;
use dom::console::Console;
use dom::crypto::Crypto;
use dom::document::{Document, DocumentHelpers};
use dom::element::Element;
use dom::eventtarget::{EventTarget, EventTargetHelpers, EventTargetTypeId};
@@ -100,6 +101,7 @@ pub struct Window {
script_chan: Box<ScriptChan+Send>,
control_chan: ScriptControlChan,
console: MutNullableHeap<JS<Console>>,
crypto: MutNullableHeap<JS<Crypto>>,
navigator: MutNullableHeap<JS<Navigator>>,
image_cache_task: ImageCacheTask,
image_cache_chan: ImageCacheChan,
@@ -360,6 +362,10 @@ impl<'a> WindowMethods for &'a Window {
self.console.or_init(|| Console::new(GlobalRef::Window(self)))
}

fn Crypto(self) -> Root<Crypto> {
self.crypto.or_init(|| Crypto::new(GlobalRef::Window(self)))
}

// https://html.spec.whatwg.org/#dom-frameelement
fn GetFrameElement(self) -> Option<Root<Element>> {
// FIXME(https://github.com/rust-lang/rust/issues/23338)
@@ -981,6 +987,7 @@ impl Window {
image_cache_chan: image_cache_chan,
control_chan: control_chan,
console: Default::default(),
crypto: Default::default(),
compositor: DOMRefCell::new(compositor),
page: page,
navigator: Default::default(),
@@ -11,6 +11,7 @@ use dom::bindings::global::GlobalRef;
use dom::bindings::js::{JS, Root, MutNullableHeap};
use dom::bindings::utils::Reflectable;
use dom::console::Console;
use dom::crypto::Crypto;
use dom::dedicatedworkerglobalscope::DedicatedWorkerGlobalScopeHelpers;
use dom::eventtarget::{EventTarget, EventTargetTypeId};
use dom::workerlocation::WorkerLocation;
@@ -49,6 +50,7 @@ pub struct WorkerGlobalScope {
location: MutNullableHeap<JS<WorkerLocation>>,
navigator: MutNullableHeap<JS<WorkerNavigator>>,
console: MutNullableHeap<JS<Console>>,
crypto: MutNullableHeap<JS<Crypto>>,
timers: TimerManager,
devtools_chan: Option<DevtoolsControlChan>,
}
@@ -68,6 +70,7 @@ impl WorkerGlobalScope {
location: Default::default(),
navigator: Default::default(),
console: Default::default(),
crypto: Default::default(),
timers: TimerManager::new(),
devtools_chan: devtools_chan,
}
@@ -157,6 +160,10 @@ impl<'a> WorkerGlobalScopeMethods for &'a WorkerGlobalScope {
self.console.or_init(|| Console::new(GlobalRef::Worker(self)))
}

fn Crypto(self) -> Root<Crypto> {
self.crypto.or_init(|| Crypto::new(GlobalRef::Worker(self)))
}

fn Btoa(self, btoa: DOMString) -> Fallible<DOMString> {
base64_btoa(btoa)
}
@@ -53,6 +53,7 @@ extern crate rustc_serialize;
extern crate time;
extern crate canvas;
extern crate canvas_traits;
extern crate rand;
extern crate profile_traits;
extern crate script_traits;
extern crate selectors;

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.

Some generated files are not rendered by default. Learn more.

Oops, something went wrong.
@@ -107,3 +107,5 @@ skip: true
skip: false
[hr-time]
skip: false
[WebCryptoAPI]
skip: false
@@ -15,6 +15,7 @@
"ArrayBuffer",
"Atomics",
"Boolean",
"Crypto",
"DataView",
"Date",
"Error",

0 comments on commit 92874a8

Please sign in to comment.
You can’t perform that action at this time.