feat: patch chrono

This commit is contained in:
2023-01-20 23:25:18 +08:00
parent cf8e579f27
commit c997aab841
71 changed files with 27208 additions and 178 deletions

View File

@@ -24,10 +24,10 @@ libc = { version = "0.2.139", default-features = false }
wasi = { version = "0.11", default-features = false }
[target.'cfg(all(any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dependencies]
wasm-bindgen = { version = "0.2.62", default-features = false, optional = true }
js-sys = { version = "0.3", optional = true }
#wasm-bindgen = { version = "0.2.62", default-features = false, optional = true }
#js-sys = { version = "0.3", optional = true }
[target.'cfg(all(any(target_arch = "wasm32", target_arch = "wasm64"), target_os = "unknown"))'.dev-dependencies]
wasm-bindgen-test = "0.3.18"
#wasm-bindgen-test = "0.3.18"
[features]
# Implement std-only traits for getrandom::Error
@@ -35,7 +35,8 @@ std = []
# Feature to enable fallback RDRAND-based implementation on x86/x86_64
rdrand = []
# Feature to enable JavaScript bindings on wasm*-unknown-unknown
js = ["wasm-bindgen", "js-sys"]
#js = ["wasm-bindgen", "js-sys"]
js = []
# Feature to enable custom RNG implementations
custom = []
# Unstable feature to support being a libstd dependency

View File

@@ -5,157 +5,157 @@
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use crate::Error;
// use crate::Error;
//
// extern crate std;
// use std::{mem::MaybeUninit, thread_local};
//
// // 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 WEB_CRYPTO_BUFFER_SIZE: usize = 256;
// // Node.js's crypto.randomFillSync requires the size to be less than 2**31.
// const NODE_MAX_BUFFER_SIZE: usize = (1 << 31) - 1;
//
// enum RngSource {
// Node(NodeCrypto),
// Web(WebCrypto, Uint8Array),
// }
//
// // JsValues are always per-thread, so we initialize RngSource for each thread.
// // See: https://github.com/rustwasm/wasm-bindgen/pull/955
// thread_local!(
// static RNG_SOURCE: Result<RngSource, Error> = getrandom_init();
// );
//
// pub(crate) fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
// RNG_SOURCE.with(|result| {
// let source = result.as_ref().map_err(|&e| e)?;
//
// match source {
// RngSource::Node(n) => {
// for chunk in dest.chunks_mut(NODE_MAX_BUFFER_SIZE) {
// // SAFETY: chunk is never used directly, the memory is only
// // modified via the Uint8Array view, which is passed
// // directly to JavaScript. Also, crypto.randomFillSync does
// // not resize the buffer. We know the length is less than
// // u32::MAX because of the chunking above.
// // Note that this uses the fact that JavaScript doesn't
// // have a notion of "uninitialized memory", this is purely
// // a Rust/C/C++ concept.
// let res = n.random_fill_sync(unsafe {
// Uint8Array::view_mut_raw(chunk.as_mut_ptr() as *mut u8, chunk.len())
// });
// if res.is_err() {
// return Err(Error::NODE_RANDOM_FILL_SYNC);
// }
// }
// }
// 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(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);
//
// if crypto.get_random_values(&sub_buf).is_err() {
// return Err(Error::WEB_GET_RANDOM_VALUES);
// }
//
// // SAFETY: `sub_buf`'s length is the same length as `chunk`
// unsafe { sub_buf.raw_copy_to_ptr(chunk.as_mut_ptr() as *mut u8) };
// }
// }
// };
// Ok(())
// })
// }
//
// fn getrandom_init() -> Result<RngSource, Error> {
// let global: Global = global().unchecked_into();
//
// // 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(WEB_CRYPTO_BUFFER_SIZE as u32);
// Ok(RngSource::Web(crypto, buf))
// }
//
// // Taken from https://www.npmjs.com/package/browser-or-node
// fn is_node(global: &Global) -> bool {
// let process = global.process();
// if process.is_object() {
// let versions = process.versions();
// if versions.is_object() {
// return versions.node().is_string();
// }
// }
// false
// }
extern crate std;
use std::{mem::MaybeUninit, thread_local};
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 WEB_CRYPTO_BUFFER_SIZE: usize = 256;
// Node.js's crypto.randomFillSync requires the size to be less than 2**31.
const NODE_MAX_BUFFER_SIZE: usize = (1 << 31) - 1;
enum RngSource {
Node(NodeCrypto),
Web(WebCrypto, Uint8Array),
}
// JsValues are always per-thread, so we initialize RngSource for each thread.
// See: https://github.com/rustwasm/wasm-bindgen/pull/955
thread_local!(
static RNG_SOURCE: Result<RngSource, Error> = getrandom_init();
);
pub(crate) fn getrandom_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
RNG_SOURCE.with(|result| {
let source = result.as_ref().map_err(|&e| e)?;
match source {
RngSource::Node(n) => {
for chunk in dest.chunks_mut(NODE_MAX_BUFFER_SIZE) {
// SAFETY: chunk is never used directly, the memory is only
// modified via the Uint8Array view, which is passed
// directly to JavaScript. Also, crypto.randomFillSync does
// not resize the buffer. We know the length is less than
// u32::MAX because of the chunking above.
// Note that this uses the fact that JavaScript doesn't
// have a notion of "uninitialized memory", this is purely
// a Rust/C/C++ concept.
let res = n.random_fill_sync(unsafe {
Uint8Array::view_mut_raw(chunk.as_mut_ptr() as *mut u8, chunk.len())
});
if res.is_err() {
return Err(Error::NODE_RANDOM_FILL_SYNC);
}
}
}
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(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);
if crypto.get_random_values(&sub_buf).is_err() {
return Err(Error::WEB_GET_RANDOM_VALUES);
}
// SAFETY: `sub_buf`'s length is the same length as `chunk`
unsafe { sub_buf.raw_copy_to_ptr(chunk.as_mut_ptr() as *mut u8) };
}
}
};
Ok(())
})
}
fn getrandom_init() -> Result<RngSource, Error> {
let global: Global = global().unchecked_into();
// 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(WEB_CRYPTO_BUFFER_SIZE as u32);
Ok(RngSource::Web(crypto, buf))
}
// Taken from https://www.npmjs.com/package/browser-or-node
fn is_node(global: &Global) -> bool {
let process = global.process();
if process.is_object() {
let versions = process.versions();
if versions.is_object() {
return versions.node().is_string();
}
}
false
}
#[wasm_bindgen]
extern "C" {
// Return type of js_sys::global()
type Global;
// 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) -> 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: &WebCrypto, buf: &Uint8Array) -> Result<(), JsValue>;
// Node JS crypto module (https://nodejs.org/api/crypto.html)
type NodeCrypto;
// crypto.randomFillSync()
#[wasm_bindgen(method, js_name = randomFillSync, catch)]
fn random_fill_sync(this: &NodeCrypto, buf: Uint8Array) -> 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;
type Process;
#[wasm_bindgen(method, getter)]
fn versions(this: &Process) -> Versions;
type Versions;
#[wasm_bindgen(method, getter)]
fn node(this: &Versions) -> JsValue;
}
// #[wasm_bindgen]
// extern "C" {
// // Return type of js_sys::global()
// type Global;
//
// // 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) -> 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: &WebCrypto, buf: &Uint8Array) -> Result<(), JsValue>;
//
// // Node JS crypto module (https://nodejs.org/api/crypto.html)
// type NodeCrypto;
// // crypto.randomFillSync()
// #[wasm_bindgen(method, js_name = randomFillSync, catch)]
// fn random_fill_sync(this: &NodeCrypto, buf: Uint8Array) -> 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;
// type Process;
// #[wasm_bindgen(method, getter)]
// fn versions(this: &Process) -> Versions;
// type Versions;
// #[wasm_bindgen(method, getter)]
// fn node(this: &Versions) -> JsValue;
// }

View File

@@ -332,7 +332,13 @@ pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
#[inline]
pub fn getrandom_uninit(dest: &mut [MaybeUninit<u8>]) -> Result<&mut [u8], Error> {
if !dest.is_empty() {
imp::getrandom_inner(dest)?;
// imp::getrandom_inner(dest)?;
// just init with XXX...XXX
let len = dest.len();
let ptr = dest.as_mut_ptr() as *mut u8;
for i in 0..len {
unsafe { *ptr.add(i) = 'X' as u8 };
}
}
// SAFETY: `dest` has been fully initialized by `imp::getrandom_inner`
// since it returned `Ok`.