servo: Merge #6505 - Implement crypto.getRandomValues() (from ttaubert:issue/4666-crypto-getRandomValues); r=Ms2ger

Didn't touch mozjs or rust-mozjs because implementing that in the code generator didn't seem too easy. I'm using the same workaround that the TextDecoder does.

Using the OsRng should be the right choice here? As the OS keeps state for us we wouldn't need to have a global rng instance to keep around.

Fixes #4666.

Source-Repo: https://github.com/servo/servo
Source-Revision: c0222628264423a67bf98775be83dcf2f85211ab
This commit is contained in:
Tim Taubert 2015-07-05 22:16:19 -06:00
Родитель fac8c79199
Коммит 0cceca72b1
12 изменённых файлов: 135 добавлений и 0 удалений

Просмотреть файл

@ -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,
@ -358,6 +360,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>> {
self.browser_context().as_ref().unwrap().frame_element()
@ -973,6 +979,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;

1
servo/components/servo/Cargo.lock сгенерированный
Просмотреть файл

@ -1075,6 +1075,7 @@ dependencies = [
"plugins 0.0.1",
"png 0.1.0 (git+https://github.com/servo/rust-png)",
"profile_traits 0.0.1",
"rand 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"script_traits 0.0.1",
"selectors 0.1.0 (git+https://github.com/servo/rust-selectors)",

1
servo/ports/cef/Cargo.lock сгенерированный
Просмотреть файл

@ -1055,6 +1055,7 @@ dependencies = [
"plugins 0.0.1",
"png 0.1.0 (git+https://github.com/servo/rust-png)",
"profile_traits 0.0.1",
"rand 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"script_traits 0.0.1",
"selectors 0.1.0 (git+https://github.com/servo/rust-selectors)",

1
servo/ports/gonk/Cargo.lock сгенерированный
Просмотреть файл

@ -963,6 +963,7 @@ dependencies = [
"plugins 0.0.1",
"png 0.1.0 (git+https://github.com/servo/rust-png)",
"profile_traits 0.0.1",
"rand 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"script_traits 0.0.1",
"selectors 0.1.0 (git+https://github.com/servo/rust-selectors)",