mirror of
https://github.com/servo/servo.git
synced 2025-08-03 04:30:10 +01:00
Auto merge of #6505 - ttaubert:issue/4666-crypto-getRandomValues, r=Ms2ger
Implement crypto.getRandomValues() 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. <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/6505) <!-- Reviewable:end -->
This commit is contained in:
commit
c022262826
14 changed files with 138 additions and 0 deletions
|
@ -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);
|
||||
|
|
82
components/script/dom/crypto.rs
Normal file
82
components/script/dom/crypto.rs
Normal file
|
@ -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;
|
||||
|
|
25
components/script/dom/webidls/Crypto.webidl
Normal file
25
components/script/dom/webidls/Crypto.webidl
Normal file
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue