// Copyright 2018 Developers of the Rand project. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Implementation for WASM via stdweb use std::mem; use stdweb::unstable::TryInto; use stdweb::web::error::Error as WebError; use rand_core::{Error, ErrorKind}; use super::OsRngImpl; #[derive(Clone, Debug)] enum OsRngMethod { Browser, Node } #[derive(Clone, Debug)] pub struct OsRng(OsRngMethod); impl OsRngImpl for OsRng { fn new() -> Result { let result = js! { try { if ( typeof self === "object" && typeof self.crypto === "object" && typeof self.crypto.getRandomValues === "function" ) { return { success: true, ty: 1 }; } if (typeof require("crypto").randomBytes === "function") { return { success: true, ty: 2 }; } return { success: false, error: new Error("not supported") }; } catch(err) { return { success: false, error: err }; } }; if js!{ return @{ result.as_ref() }.success } == true { let ty = js!{ return @{ result }.ty }; if ty == 1 { Ok(OsRng(OsRngMethod::Browser)) } else if ty == 2 { Ok(OsRng(OsRngMethod::Node)) } else { unreachable!() } } else { let err: WebError = js!{ return @{ result }.error }.try_into().unwrap(); Err(Error::with_cause(ErrorKind::Unavailable, "WASM Error", err)) } } fn fill_chunk(&mut self, dest: &mut [u8]) -> Result<(), Error> { assert_eq!(mem::size_of::(), 4); let len = dest.len() as u32; let ptr = dest.as_mut_ptr() as i32; let result = match self.0 { OsRngMethod::Browser => js! { try { let array = new Uint8Array(@{ len }); self.crypto.getRandomValues(array); HEAPU8.set(array, @{ ptr }); return { success: true }; } catch(err) { return { success: false, error: err }; } }, OsRngMethod::Node => js! { try { let bytes = require("crypto").randomBytes(@{ len }); HEAPU8.set(new Uint8Array(bytes), @{ ptr }); return { success: true }; } catch(err) { return { success: false, error: err }; } } }; if js!{ return @{ result.as_ref() }.success } == true { Ok(()) } else { let err: WebError = js!{ return @{ result }.error }.try_into().unwrap(); Err(Error::with_cause(ErrorKind::Unexpected, "WASM Error", err)) } } fn max_chunk_size(&self) -> usize { 65536 } fn method_str(&self) -> &'static str { match self.0 { OsRngMethod::Browser => "Crypto.getRandomValues", OsRngMethod::Node => "crypto.randomBytes", } } }