Skip to content

Commit

Permalink
Update documentation and error messages
Browse files Browse the repository at this point in the history
This allows users to get an actionable error message about this
particular problem. We also add detection for this problem.

Signed-off-by: Joe Richey <joerichey@google.com>
  • Loading branch information
josephlr committed Sep 13, 2022
1 parent d69e8e0 commit 0579fe3
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 11 deletions.
4 changes: 4 additions & 0 deletions src/error.rs
Expand Up @@ -53,6 +53,9 @@ impl Error {
pub const NODE_CRYPTO: Error = internal_error(12);
/// Calling Node.js function `crypto.randomFillSync` failed.
pub const NODE_RANDOM_FILL_SYNC: Error = internal_error(13);
/// Called from an ES module on Node.js. This is unsupported, see:
/// https://docs.rs/getrandom#nodejs-es6-module-support.
pub const NODE_ES_MODULE: Error = internal_error(14);

/// Codes below this point represent OS Errors (i.e. positive i32 values).
/// Codes at or above this point, but below [`Error::CUSTOM_START`] are
Expand Down Expand Up @@ -170,6 +173,7 @@ fn internal_desc(error: Error) -> Option<&'static str> {
Error::VXWORKS_RAND_SECURE => Some("randSecure: VxWorks RNG module is not initialized"),
Error::NODE_CRYPTO => Some("Node.js crypto CommonJS module is unavailable"),
Error::NODE_RANDOM_FILL_SYNC => Some("Calling Node.js API crypto.randomFillSync failed"),
Error::NODE_ES_MODULE => Some("Node.js ES modules are not directly supported, see https://docs.rs/getrandom#nodejs-es6-module-support"),
_ => None,
}
}
Expand Down
20 changes: 11 additions & 9 deletions src/js.rs
Expand Up @@ -10,7 +10,7 @@ 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
Expand Down Expand Up @@ -68,10 +68,14 @@ fn getrandom_init() -> Result<RngSource, Error> {
c if c.is_object() => c,
// Node.js CommonJS Crypto module
_ if is_node(&global) => {
match MODULE.require("crypto") {
Ok(n) if n.is_object() => return Ok(RngSource::Node(n)),
_ => return Err(Error::NODE_CRYPTO),
};
// If require isn't a valid function, we are in an ES module.
match Module::require_fn().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() {
Expand Down Expand Up @@ -122,10 +126,8 @@ extern "C" {
// js_name = "module.require", so that Webpack doesn't give a warning. See:
// https://github.com/rust-random/getrandom/issues/224
type Module;
#[wasm_bindgen(js_name = module)]
static MODULE: Module;
#[wasm_bindgen(method, catch)]
fn require(this: &Module, s: &str) -> Result<NodeCrypto, JsValue>;
#[wasm_bindgen(getter, static_method_of = Module, js_class = module, js_name = require)]
fn require_fn() -> JsValue;

// Node JS process Object (https://nodejs.org/api/process.html)
#[wasm_bindgen(method, getter)]
Expand Down
19 changes: 17 additions & 2 deletions src/lib.rs
Expand Up @@ -31,7 +31,7 @@
//! | Emscripten | `*‑emscripten` | `/dev/random` (identical to `/dev/urandom`)
//! | WASI | `wasm32‑wasi` | [`random_get`]
//! | Web Browser | `wasm32‑*‑unknown` | [`Crypto.getRandomValues`], see [WebAssembly support]
//! | Node.js | `wasm32‑*‑unknown` | [`crypto.randomBytes`], see [WebAssembly support]
//! | Node.js | `wasm32‑*‑unknown` | [`crypto.randomFillSync`], see [WebAssembly support]
//! | SOLID | `*-kmc-solid_*` | `SOLID_RNG_SampleRandomBytes`
//! | Nintendo 3DS | `armv6k-nintendo-3ds` | [`getrandom`][1]
//!
Expand Down Expand Up @@ -91,6 +91,18 @@
//!
//! This feature has no effect on targets other than `wasm32-unknown-unknown`.
//!
//! #### Node.js ES module support
//!
//! Node.js supports both [CommonJS modules] and [ES modules]. Due to
//! limitations in wasm-bindgen's [`module`] support, we cannot directly
//! support ES Modules running on Node.js. However, on Node v15 and later, the
//! module author can add a simple shim to support the Web Cryptography API:
//! ```js
//! import { webcrypto } from 'node:crypto'
//! globalThis.crypto = webcrypto
//! ```
//! This crate will then use the provided `webcrypto` implementation.
//!
//! ### Custom implementations
//!
//! The [`register_custom_getrandom!`] macro allows a user to mark their own
Expand Down Expand Up @@ -154,11 +166,14 @@
//! [`RDRAND`]: https://software.intel.com/en-us/articles/intel-digital-random-number-generator-drng-software-implementation-guide
//! [`SecRandomCopyBytes`]: https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc
//! [`cprng_draw`]: https://fuchsia.dev/fuchsia-src/zircon/syscalls/cprng_draw
//! [`crypto.randomBytes`]: https://nodejs.org/api/crypto.html#crypto_crypto_randombytes_size_callback
//! [`crypto.randomFillSync`]: https://nodejs.org/api/crypto.html#cryptorandomfillsyncbuffer-offset-size
//! [`esp_fill_random`]: https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/random.html#_CPPv415esp_fill_randomPv6size_t
//! [`random_get`]: https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#-random_getbuf-pointeru8-buf_len-size---errno
//! [WebAssembly support]: #webassembly-support
//! [`wasm-bindgen`]: https://github.com/rustwasm/wasm-bindgen
//! [`module`]: https://rustwasm.github.io/wasm-bindgen/reference/attributes/on-js-imports/module.html
//! [CommonJS modules]: https://nodejs.org/api/modules.html
//! [ES modules]: https://nodejs.org/api/esm.html

#![doc(
html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk.png",
Expand Down

0 comments on commit 0579fe3

Please sign in to comment.