diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:13 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-17 12:19:13 +0000 |
commit | 218caa410aa38c29984be31a5229b9fa717560ee (patch) | |
tree | c54bd55eeb6e4c508940a30e94c0032fbd45d677 /vendor/getrandom/src/js.rs | |
parent | Releasing progress-linux version 1.67.1+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-218caa410aa38c29984be31a5229b9fa717560ee.tar.xz rustc-218caa410aa38c29984be31a5229b9fa717560ee.zip |
Merging upstream version 1.68.2+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/getrandom/src/js.rs')
-rw-r--r-- | vendor/getrandom/src/js.rs | 87 |
1 files changed, 51 insertions, 36 deletions
diff --git a/vendor/getrandom/src/js.rs b/vendor/getrandom/src/js.rs index e910f2bc6..574c4dc32 100644 --- a/vendor/getrandom/src/js.rs +++ b/vendor/getrandom/src/js.rs @@ -10,15 +10,16 @@ use crate::Error; extern crate std; use std::thread_local; -use js_sys::{global, Uint8Array}; +use js_sys::{global, Function, Uint8Array}; use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue}; +// Size of our temporary Uint8Array buffer used with WebCrypto methods // Maximum is 65536 bytes see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues -const BROWSER_CRYPTO_BUFFER_SIZE: usize = 256; +const WEB_CRYPTO_BUFFER_SIZE: usize = 256; enum RngSource { Node(NodeCrypto), - Browser(BrowserCrypto, Uint8Array), + Web(WebCrypto, Uint8Array), } // JsValues are always per-thread, so we initialize RngSource for each thread. @@ -37,10 +38,10 @@ pub(crate) fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { return Err(Error::NODE_RANDOM_FILL_SYNC); } } - RngSource::Browser(crypto, buf) => { + RngSource::Web(crypto, buf) => { // getRandomValues does not work with all types of WASM memory, // so we initially write to browser memory to avoid exceptions. - for chunk in dest.chunks_mut(BROWSER_CRYPTO_BUFFER_SIZE) { + for chunk in dest.chunks_mut(WEB_CRYPTO_BUFFER_SIZE) { // The chunk can be smaller than buf's length, so we call to // JS to create a smaller view of buf without allocation. let sub_buf = buf.subarray(0, chunk.len() as u32); @@ -58,25 +59,33 @@ pub(crate) fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> { fn getrandom_init() -> Result<RngSource, Error> { let global: Global = global().unchecked_into(); - if is_node(&global) { - let crypto = NODE_MODULE - .require("crypto") - .map_err(|_| Error::NODE_CRYPTO)?; - return Ok(RngSource::Node(crypto)); - } - // Assume we are in some Web environment (browser or web worker). We get - // `self.crypto` (called `msCrypto` on IE), so we can call - // `crypto.getRandomValues`. If `crypto` isn't defined, we assume that - // we are in an older web browser and the OS RNG isn't available. - let crypto = match (global.crypto(), global.ms_crypto()) { - (c, _) if c.is_object() => c, - (_, c) if c.is_object() => c, - _ => return Err(Error::WEB_CRYPTO), + // Get the Web Crypto interface if we are in a browser, Web Worker, Deno, + // or another environment that supports the Web Cryptography API. This + // also allows for user-provided polyfills in unsupported environments. + let crypto = match global.crypto() { + // Standard Web Crypto interface + c if c.is_object() => c, + // Node.js CommonJS Crypto module + _ if is_node(&global) => { + // If module.require isn't a valid function, we are in an ES module. + match Module::require_fn().and_then(JsCast::dyn_into::<Function>) { + Ok(require_fn) => match require_fn.call1(&global, &JsValue::from_str("crypto")) { + Ok(n) => return Ok(RngSource::Node(n.unchecked_into())), + Err(_) => return Err(Error::NODE_CRYPTO), + }, + Err(_) => return Err(Error::NODE_ES_MODULE), + } + } + // IE 11 Workaround + _ => match global.ms_crypto() { + c if c.is_object() => c, + _ => return Err(Error::WEB_CRYPTO), + }, }; - let buf = Uint8Array::new_with_length(BROWSER_CRYPTO_BUFFER_SIZE as u32); - Ok(RngSource::Browser(crypto, buf)) + let buf = Uint8Array::new_with_length(WEB_CRYPTO_BUFFER_SIZE as u32); + Ok(RngSource::Web(crypto, buf)) } // Taken from https://www.npmjs.com/package/browser-or-node @@ -93,30 +102,36 @@ fn is_node(global: &Global) -> bool { #[wasm_bindgen] extern "C" { - type Global; // Return type of js_sys::global() + // Return type of js_sys::global() + type Global; - // Web Crypto API (https://www.w3.org/TR/WebCryptoAPI/) - #[wasm_bindgen(method, getter, js_name = "msCrypto")] - fn ms_crypto(this: &Global) -> BrowserCrypto; + // Web Crypto API: Crypto interface (https://www.w3.org/TR/WebCryptoAPI/) + type WebCrypto; + // Getters for the WebCrypto API #[wasm_bindgen(method, getter)] - fn crypto(this: &Global) -> BrowserCrypto; - type BrowserCrypto; + fn crypto(this: &Global) -> WebCrypto; + #[wasm_bindgen(method, getter, js_name = msCrypto)] + fn ms_crypto(this: &Global) -> WebCrypto; + // Crypto.getRandomValues() #[wasm_bindgen(method, js_name = getRandomValues, catch)] - fn get_random_values(this: &BrowserCrypto, buf: &Uint8Array) -> Result<(), JsValue>; + fn get_random_values(this: &WebCrypto, buf: &Uint8Array) -> Result<(), JsValue>; - // We use a "module" object here instead of just annotating require() with - // js_name = "module.require", so that Webpack doesn't give a warning. See: - // https://github.com/rust-random/getrandom/issues/224 - type NodeModule; - #[wasm_bindgen(js_name = module)] - static NODE_MODULE: NodeModule; // Node JS crypto module (https://nodejs.org/api/crypto.html) - #[wasm_bindgen(method, catch)] - fn require(this: &NodeModule, s: &str) -> Result<NodeCrypto, JsValue>; type NodeCrypto; + // crypto.randomFillSync() #[wasm_bindgen(method, js_name = randomFillSync, catch)] fn random_fill_sync(this: &NodeCrypto, buf: &mut [u8]) -> Result<(), JsValue>; + // Ideally, we would just use `fn require(s: &str)` here. However, doing + // this causes a Webpack warning. So we instead return the function itself + // and manually invoke it using call1. This also lets us to check that the + // function actually exists, allowing for better error messages. See: + // https://github.com/rust-random/getrandom/issues/224 + // https://github.com/rust-random/getrandom/issues/256 + type Module; + #[wasm_bindgen(getter, static_method_of = Module, js_class = module, js_name = require, catch)] + fn require_fn() -> Result<JsValue, JsValue>; + // Node JS process Object (https://nodejs.org/api/process.html) #[wasm_bindgen(method, getter)] fn process(this: &Global) -> Process; |