mirror of
https://github.com/fluencelabs/rust-libp2p
synced 2025-06-23 14:51:34 +00:00
Fix the WASM build with stable futures (#1322)
* Fix the WASM build with stable futures * Fix duplicate dependencies error
This commit is contained in:
@ -33,7 +33,6 @@ sha2 = "0.8.0"
|
|||||||
smallvec = "1.0"
|
smallvec = "1.0"
|
||||||
unsigned-varint = "0.2"
|
unsigned-varint = "0.2"
|
||||||
void = "1"
|
void = "1"
|
||||||
wasm-timer = "0.1"
|
|
||||||
zeroize = "1"
|
zeroize = "1"
|
||||||
|
|
||||||
[target.'cfg(not(any(target_os = "emscripten", target_os = "unknown")))'.dependencies]
|
[target.'cfg(not(any(target_os = "emscripten", target_os = "unknown")))'.dependencies]
|
||||||
@ -48,7 +47,6 @@ libp2p-secio = { version = "0.13.0", path = "../protocols/secio" }
|
|||||||
libp2p-swarm = { version = "0.3.0", path = "../swarm" }
|
libp2p-swarm = { version = "0.3.0", path = "../swarm" }
|
||||||
libp2p-tcp = { version = "0.13.0", path = "../transports/tcp" }
|
libp2p-tcp = { version = "0.13.0", path = "../transports/tcp" }
|
||||||
quickcheck = "0.9.0"
|
quickcheck = "0.9.0"
|
||||||
rand = "0.7.2"
|
|
||||||
wasm-timer = "0.2"
|
wasm-timer = "0.2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
@ -35,7 +35,7 @@ untrusted = "0.7.0"
|
|||||||
js-sys = "0.3.10"
|
js-sys = "0.3.10"
|
||||||
parity-send-wrapper = "0.1"
|
parity-send-wrapper = "0.1"
|
||||||
wasm-bindgen = "0.2.33"
|
wasm-bindgen = "0.2.33"
|
||||||
wasm-bindgen-futures = "0.3.10"
|
wasm-bindgen-futures = "0.4.5"
|
||||||
web-sys = { version = "0.3.10", features = ["Crypto", "CryptoKey", "SubtleCrypto", "Window"] }
|
web-sys = { version = "0.3.10", features = ["Crypto", "CryptoKey", "SubtleCrypto", "Window"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
use crate::{KeyAgreement, SecioError};
|
use crate::{KeyAgreement, SecioError};
|
||||||
use futures::prelude::*;
|
use futures::prelude::*;
|
||||||
use parity_send_wrapper::SendWrapper;
|
use parity_send_wrapper::SendWrapper;
|
||||||
use std::io;
|
use std::{io, pin::Pin, task::Context, task::Poll};
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
/// Opaque private key type. Contains the private key and the `SubtleCrypto` object.
|
/// Opaque private key type. Contains the private key and the `SubtleCrypto` object.
|
||||||
@ -35,12 +35,11 @@ pub type AgreementPrivateKey = SendSyncHack<(JsValue, web_sys::SubtleCrypto)>;
|
|||||||
pub struct SendSyncHack<T>(SendWrapper<T>);
|
pub struct SendSyncHack<T>(SendWrapper<T>);
|
||||||
|
|
||||||
impl<T> Future for SendSyncHack<T>
|
impl<T> Future for SendSyncHack<T>
|
||||||
where T: Future {
|
where T: Future + Unpin {
|
||||||
type Item = T::Item;
|
type Output = T::Output;
|
||||||
type Error = T::Error;
|
|
||||||
|
|
||||||
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
|
||||||
self.0.poll()
|
self.0.poll_unpin(cx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,128 +47,114 @@ where T: Future {
|
|||||||
///
|
///
|
||||||
/// Returns the opaque private key and the corresponding public key.
|
/// Returns the opaque private key and the corresponding public key.
|
||||||
pub fn generate_agreement(algorithm: KeyAgreement)
|
pub fn generate_agreement(algorithm: KeyAgreement)
|
||||||
-> impl Future<Item = (AgreementPrivateKey, Vec<u8>), Error = SecioError>
|
-> impl Future<Output = Result<(AgreementPrivateKey, Vec<u8>), SecioError>>
|
||||||
{
|
{
|
||||||
// First step is to create the `SubtleCrypto` object.
|
let future = async move {
|
||||||
let crypto = build_crypto_future();
|
// First step is to create the `SubtleCrypto` object.
|
||||||
|
let crypto = build_crypto_future().await?;
|
||||||
|
|
||||||
// We then generate the ephemeral key.
|
// We then generate the ephemeral key.
|
||||||
let key_promise = crypto.and_then(move |crypto| {
|
let key_pair = {
|
||||||
let crypto = crypto.clone();
|
let obj = build_curve_obj(algorithm);
|
||||||
let obj = build_curve_obj(algorithm);
|
|
||||||
|
|
||||||
let usages = js_sys::Array::new();
|
let usages = js_sys::Array::new();
|
||||||
usages.push(&JsValue::from_str("deriveKey"));
|
usages.push(&JsValue::from_str("deriveKey"));
|
||||||
usages.push(&JsValue::from_str("deriveBits"));
|
usages.push(&JsValue::from_str("deriveBits"));
|
||||||
|
|
||||||
crypto.generate_key_with_object(&obj, true, usages.as_ref())
|
let promise = crypto.generate_key_with_object(&obj, true, usages.as_ref())?;
|
||||||
.map(wasm_bindgen_futures::JsFuture::from)
|
wasm_bindgen_futures::JsFuture::from(promise).await?
|
||||||
.into_future()
|
};
|
||||||
.flatten()
|
|
||||||
.map(|key_pair| (key_pair, crypto))
|
|
||||||
});
|
|
||||||
|
|
||||||
// WebCrypto has generated a key-pair. Let's split this key pair into a private key and a
|
// WebCrypto has generated a key-pair. Let's split this key pair into a private key and a
|
||||||
// public key.
|
// public key.
|
||||||
let split_key = key_promise.and_then(move |(key_pair, crypto)| {
|
let (private, public) = {
|
||||||
let private = js_sys::Reflect::get(&key_pair, &JsValue::from_str("privateKey"));
|
let private = js_sys::Reflect::get(&key_pair, &JsValue::from_str("privateKey"));
|
||||||
let public = js_sys::Reflect::get(&key_pair, &JsValue::from_str("publicKey"));
|
let public = js_sys::Reflect::get(&key_pair, &JsValue::from_str("publicKey"));
|
||||||
match (private, public) {
|
match (private, public) {
|
||||||
(Ok(pr), Ok(pu)) => Ok((pr, pu, crypto)),
|
(Ok(pr), Ok(pu)) => (pr, pu),
|
||||||
(Err(err), _) => Err(err),
|
(Err(err), _) => return Err(err),
|
||||||
(_, Err(err)) => Err(err),
|
(_, Err(err)) => return Err(err),
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
|
||||||
// Then we turn the public key into an `ArrayBuffer`.
|
// Then we turn the public key into an `ArrayBuffer`.
|
||||||
let export_key = split_key.and_then(move |(private, public, crypto)| {
|
let public = {
|
||||||
crypto.export_key("raw", &public.into())
|
let promise = crypto.export_key("raw", &public.into())?;
|
||||||
.map(wasm_bindgen_futures::JsFuture::from)
|
wasm_bindgen_futures::JsFuture::from(promise).await?
|
||||||
.into_future()
|
};
|
||||||
.flatten()
|
|
||||||
.map(|public| ((private, crypto), public))
|
|
||||||
});
|
|
||||||
|
|
||||||
// And finally we convert this `ArrayBuffer` into a `Vec<u8>`.
|
// And finally we convert this `ArrayBuffer` into a `Vec<u8>`.
|
||||||
let future = export_key
|
let public = js_sys::Uint8Array::new(&public);
|
||||||
.map(|((private, crypto), public)| {
|
let mut public_buf = vec![0; public.length() as usize];
|
||||||
let public = js_sys::Uint8Array::new(&public);
|
public.copy_to(&mut public_buf);
|
||||||
let mut public_buf = vec![0; public.length() as usize];
|
Ok((SendSyncHack(SendWrapper::new((private, crypto))), public_buf))
|
||||||
public.copy_to(&mut public_buf);
|
};
|
||||||
(SendSyncHack(SendWrapper::new((private, crypto))), public_buf)
|
|
||||||
|
let future = future
|
||||||
|
.map_err(|err| {
|
||||||
|
SecioError::IoError(io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))
|
||||||
});
|
});
|
||||||
|
SendSyncHack(SendWrapper::new(Box::pin(future)))
|
||||||
SendSyncHack(SendWrapper::new(future.map_err(|err| {
|
|
||||||
SecioError::IoError(io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))
|
|
||||||
})))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finish the agreement. On success, returns the shared key that both remote agreed upon.
|
/// Finish the agreement. On success, returns the shared key that both remote agreed upon.
|
||||||
pub fn agree(algorithm: KeyAgreement, key: AgreementPrivateKey, other_public_key: &[u8], out_size: usize)
|
pub fn agree(algorithm: KeyAgreement, key: AgreementPrivateKey, other_public_key: &[u8], out_size: usize)
|
||||||
-> impl Future<Item = Vec<u8>, Error = SecioError>
|
-> impl Future<Output = Result<Vec<u8>, SecioError>>
|
||||||
{
|
{
|
||||||
let (private_key, crypto) = key.0.take();
|
let other_public_key = {
|
||||||
|
// This unsafe is here because the lifetime of `other_public_key` must not outlive the
|
||||||
// We start by importing the remote's public key into the WebCrypto world.
|
// `tmp_view`. This is guaranteed by the fact that we clone this array right below.
|
||||||
let import_promise = {
|
// See also https://github.com/rustwasm/wasm-bindgen/issues/1303
|
||||||
let other_public_key = {
|
let tmp_view = unsafe { js_sys::Uint8Array::view(other_public_key) };
|
||||||
// This unsafe is here because the lifetime of `other_public_key` must not outlive the
|
js_sys::Uint8Array::new(tmp_view.as_ref())
|
||||||
// `tmp_view`. This is guaranteed by the fact that we clone this array right below.
|
|
||||||
// See also https://github.com/rustwasm/wasm-bindgen/issues/1303
|
|
||||||
let tmp_view = unsafe { js_sys::Uint8Array::view(other_public_key) };
|
|
||||||
js_sys::Uint8Array::new(tmp_view.as_ref())
|
|
||||||
};
|
|
||||||
|
|
||||||
// Note: contrary to what one might think, we shouldn't add the "deriveBits" usage.
|
|
||||||
crypto
|
|
||||||
.import_key_with_object(
|
|
||||||
"raw", &js_sys::Object::from(other_public_key.buffer()),
|
|
||||||
&build_curve_obj(algorithm), false, &js_sys::Array::new()
|
|
||||||
)
|
|
||||||
.into_future()
|
|
||||||
.map(wasm_bindgen_futures::JsFuture::from)
|
|
||||||
.flatten()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// We then derive the final private key.
|
let future = async move {
|
||||||
let derive = import_promise.and_then({
|
let (private_key, crypto) = key.0.take();
|
||||||
let crypto = crypto.clone();
|
|
||||||
move |public_key| {
|
// We start by importing the remote's public key into the WebCrypto world.
|
||||||
|
let public_key = {
|
||||||
|
// Note: contrary to what one might think, we shouldn't add the "deriveBits" usage.
|
||||||
|
let promise = crypto
|
||||||
|
.import_key_with_object(
|
||||||
|
"raw", &js_sys::Object::from(other_public_key.buffer()),
|
||||||
|
&build_curve_obj(algorithm), false, &js_sys::Array::new()
|
||||||
|
)?;
|
||||||
|
wasm_bindgen_futures::JsFuture::from(promise).await?
|
||||||
|
};
|
||||||
|
|
||||||
|
// We then derive the final private key.
|
||||||
|
let bytes = {
|
||||||
let derive_params = build_curve_obj(algorithm);
|
let derive_params = build_curve_obj(algorithm);
|
||||||
let _ = js_sys::Reflect::set(derive_params.as_ref(), &JsValue::from_str("public"), &public_key);
|
let _ = js_sys::Reflect::set(derive_params.as_ref(), &JsValue::from_str("public"), &public_key);
|
||||||
crypto
|
let promise = crypto
|
||||||
.derive_bits_with_object(
|
.derive_bits_with_object(
|
||||||
&derive_params,
|
&derive_params,
|
||||||
&web_sys::CryptoKey::from(private_key),
|
&web_sys::CryptoKey::from(private_key),
|
||||||
8 * out_size as u32
|
8 * out_size as u32
|
||||||
)
|
)?;
|
||||||
.into_future()
|
wasm_bindgen_futures::JsFuture::from(promise).await?
|
||||||
.map(wasm_bindgen_futures::JsFuture::from)
|
};
|
||||||
.flatten()
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let future = derive
|
let bytes = js_sys::Uint8Array::new(&bytes);
|
||||||
.map(|bytes| {
|
let mut buf = vec![0; bytes.length() as usize];
|
||||||
let bytes = js_sys::Uint8Array::new(&bytes);
|
bytes.copy_to(&mut buf);
|
||||||
let mut buf = vec![0; bytes.length() as usize];
|
Ok(buf)
|
||||||
bytes.copy_to(&mut buf);
|
};
|
||||||
buf
|
|
||||||
})
|
let future = future
|
||||||
.map_err(|err| {
|
.map_err(|err: JsValue| {
|
||||||
SecioError::IoError(io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))
|
SecioError::IoError(io::Error::new(io::ErrorKind::Other, format!("{:?}", err)))
|
||||||
});
|
});
|
||||||
|
SendSyncHack(SendWrapper::new(Box::pin(future)))
|
||||||
SendSyncHack(SendWrapper::new(future))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a future that returns the `SubtleCrypto` object.
|
/// Builds a future that returns the `SubtleCrypto` object.
|
||||||
fn build_crypto_future() -> impl Future<Item = web_sys::SubtleCrypto, Error = JsValue> {
|
async fn build_crypto_future() -> Result<web_sys::SubtleCrypto, JsValue> {
|
||||||
web_sys::window()
|
web_sys::window()
|
||||||
.ok_or_else(|| JsValue::from_str("Window object not available"))
|
.ok_or_else(|| JsValue::from_str("Window object not available"))
|
||||||
.and_then(|window| window.crypto())
|
.and_then(|window| window.crypto())
|
||||||
.map(|crypto| crypto.subtle())
|
.map(|crypto| crypto.subtle())
|
||||||
.into_future()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a `EcKeyGenParams` object.
|
/// Builds a `EcKeyGenParams` object.
|
||||||
|
Reference in New Issue
Block a user