@@ -11,7 +11,7 @@ extern crate std;
1111use std:: thread_local;
1212
1313use js_sys:: Uint8Array ;
14- use wasm_bindgen:: prelude:: * ;
14+ use wasm_bindgen:: { prelude:: * , JsCast } ;
1515
1616// Maximum is 65536 bytes see https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues
1717const BROWSER_CRYPTO_BUFFER_SIZE : usize = 256 ;
@@ -57,50 +57,65 @@ pub(crate) fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
5757}
5858
5959fn getrandom_init ( ) -> Result < RngSource , Error > {
60- if let Ok ( self_) = Global :: get_self ( ) {
61- // If `self` is defined then we're in a browser somehow (main window
62- // or web worker). We get `self.crypto` (called `msCrypto` on IE), so we
63- // can call `crypto.getRandomValues`. If `crypto` isn't defined, we
64- // assume we're in an older web browser and the OS RNG isn't available.
65-
66- let crypto: BrowserCrypto = match ( self_. crypto ( ) , self_. ms_crypto ( ) ) {
67- ( crypto, _) if !crypto. is_undefined ( ) => crypto,
68- ( _, crypto) if !crypto. is_undefined ( ) => crypto,
69- _ => return Err ( Error :: WEB_CRYPTO ) ,
70- } ;
71-
72- let buf = Uint8Array :: new_with_length ( BROWSER_CRYPTO_BUFFER_SIZE as u32 ) ;
73- return Ok ( RngSource :: Browser ( crypto, buf) ) ;
60+ let global: Global = js_sys:: global ( ) . unchecked_into ( ) ;
61+ if is_node ( & global) {
62+ let crypto = require ( "crypto" ) . map_err ( |_| Error :: NODE_CRYPTO ) ?;
63+ return Ok ( RngSource :: Node ( crypto) ) ;
7464 }
7565
76- let crypto = MODULE . require ( "crypto" ) . map_err ( |_| Error :: NODE_CRYPTO ) ?;
77- Ok ( RngSource :: Node ( crypto) )
66+ // Assume we are in some Web environment (browser or web worker). We get
67+ // `self.crypto` (called `msCrypto` on IE), so we can call
68+ // `crypto.getRandomValues`. If `crypto` isn't defined, we assume that
69+ // we are in an older web browser and the OS RNG isn't available.
70+ let crypto = match ( global. crypto ( ) , global. ms_crypto ( ) ) {
71+ ( c, _) if c. is_object ( ) => c,
72+ ( _, c) if c. is_object ( ) => c,
73+ _ => return Err ( Error :: WEB_CRYPTO ) ,
74+ } ;
75+
76+ let buf = Uint8Array :: new_with_length ( BROWSER_CRYPTO_BUFFER_SIZE as u32 ) ;
77+ Ok ( RngSource :: Browser ( crypto, buf) )
78+ }
79+
80+ // Taken from https://www.npmjs.com/package/browser-or-node
81+ fn is_node ( global : & Global ) -> bool {
82+ let process = global. process ( ) ;
83+ if process. is_object ( ) {
84+ let versions = process. versions ( ) ;
85+ if versions. is_object ( ) {
86+ return versions. node ( ) . is_string ( ) ;
87+ }
88+ }
89+ false
7890}
7991
8092#[ wasm_bindgen]
8193extern "C" {
82- type Global ;
83- #[ wasm_bindgen( getter, catch, static_method_of = Global , js_class = self , js_name = self ) ]
84- fn get_self ( ) -> Result < Self_ , JsValue > ;
94+ type Global ; // Return type of js_sys::global()
8595
86- type Self_ ;
96+ // Web Crypto API (https://www.w3.org/TR/WebCryptoAPI/)
8797 #[ wasm_bindgen( method, getter, js_name = "msCrypto" ) ]
88- fn ms_crypto ( me : & Self_ ) -> BrowserCrypto ;
98+ fn ms_crypto ( this : & Global ) -> BrowserCrypto ;
8999 #[ wasm_bindgen( method, getter) ]
90- fn crypto ( me : & Self_ ) -> BrowserCrypto ;
91-
100+ fn crypto ( this : & Global ) -> BrowserCrypto ;
92101 type BrowserCrypto ;
93102 #[ wasm_bindgen( method, js_name = getRandomValues, catch) ]
94- fn get_random_values ( me : & BrowserCrypto , buf : & Uint8Array ) -> Result < ( ) , JsValue > ;
95-
96- #[ wasm_bindgen( js_name = module) ]
97- static MODULE : NodeModule ;
98-
99- type NodeModule ;
100- #[ wasm_bindgen( method, catch) ]
101- fn require ( this : & NodeModule , s : & str ) -> Result < NodeCrypto , JsValue > ;
103+ fn get_random_values ( this : & BrowserCrypto , buf : & Uint8Array ) -> Result < ( ) , JsValue > ;
102104
105+ // Node JS crypto module (https://nodejs.org/api/crypto.html)
106+ #[ wasm_bindgen( catch, js_name = "module.require" ) ]
107+ fn require ( s : & str ) -> Result < NodeCrypto , JsValue > ;
103108 type NodeCrypto ;
104109 #[ wasm_bindgen( method, js_name = randomFillSync, catch) ]
105- fn random_fill_sync ( crypto : & NodeCrypto , buf : & mut [ u8 ] ) -> Result < ( ) , JsValue > ;
110+ fn random_fill_sync ( this : & NodeCrypto , buf : & mut [ u8 ] ) -> Result < ( ) , JsValue > ;
111+
112+ // Node JS process Object (https://nodejs.org/api/process.html)
113+ #[ wasm_bindgen( method, getter) ]
114+ fn process ( this : & Global ) -> Process ;
115+ type Process ;
116+ #[ wasm_bindgen( method, getter) ]
117+ fn versions ( this : & Process ) -> Versions ;
118+ type Versions ;
119+ #[ wasm_bindgen( method, getter) ]
120+ fn node ( this : & Versions ) -> JsValue ;
106121}
0 commit comments