> {
- self.session.clone()
- }
-}
-
-/// Implementation of whisper RPC.
-pub struct WhisperClient {
- store: Arc>,
- pool: P,
- filter_manager: Arc,
- _meta: ::std::marker::PhantomData,
-}
-
-impl WhisperClient
{
- /// Create a new whisper client with basic metadata.
- pub fn with_simple_meta(pool: P, filter_manager: Arc) -> Self {
- WhisperClient::new(pool, filter_manager)
- }
-}
-
-impl WhisperClient
{
- /// Create a new whisper client.
- pub fn new(pool: P, filter_manager: Arc) -> Self {
- WhisperClient {
- store: filter_manager.key_store(),
- pool: pool,
- filter_manager: filter_manager,
- _meta: ::std::marker::PhantomData,
- }
- }
-
- fn delete_filter_kind(&self, id: H256, kind: filter::Kind) -> bool {
- match self.filter_manager.kind(&id) {
- Some(k) if k == kind => {
- self.filter_manager.remove(&id);
- true
- }
- None | Some(_) => false,
- }
- }
-}
-
-impl Whisper for WhisperClient {
- fn info(&self) -> Result {
- let status = self.pool.pool_status();
-
- Ok(types::NodeInfo {
- required_pow: status.required_pow,
- messages: status.message_count,
- memory: status.cumulative_size,
- target_memory: status.target_size,
- })
- }
-
- fn new_key_pair(&self) -> Result {
- let mut store = self.store.write();
- let key_pair = Key::new_asymmetric(store.rng());
-
- Ok(HexEncode(store.insert(key_pair)))
- }
-
- fn add_private_key(&self, private: types::Private) -> Result {
- let key_pair = Key::from_secret(private.into_inner().into())
- .ok_or_else(|| whisper_error("Invalid private key"))?;
-
- Ok(HexEncode(self.store.write().insert(key_pair)))
- }
-
- fn new_sym_key(&self) -> Result {
- let mut store = self.store.write();
- let key = Key::new_symmetric(store.rng());
-
- Ok(HexEncode(store.insert(key)))
- }
-
- fn add_sym_key(&self, raw_key: types::Symmetric) -> Result {
- let raw_key = raw_key.into_inner().0;
- let key = Key::from_raw_symmetric(raw_key);
-
- Ok(HexEncode(self.store.write().insert(key)))
- }
-
- fn get_public(&self, id: types::Identity) -> Result {
- self.store.read().public(&id.into_inner())
- .cloned()
- .map(HexEncode)
- .ok_or_else(|| whisper_error("Unknown identity"))
- }
-
- fn get_private(&self, id: types::Identity) -> Result {
- self.store.read().secret(&id.into_inner())
- .map(|x| (&**x).clone())
- .map(HexEncode)
- .ok_or_else(|| whisper_error("Unknown identity"))
- }
-
- fn get_symmetric(&self, id: types::Identity) -> Result {
- self.store.read().symmetric(&id.into_inner())
- .cloned()
- .map(H256)
- .map(HexEncode)
- .ok_or_else(|| whisper_error("Unknown identity"))
- }
-
- fn remove_key(&self, id: types::Identity) -> Result {
- Ok(self.store.write().remove(&id.into_inner()))
- }
-
- fn post(&self, req: types::PostRequest) -> Result {
- use self::crypto::EncryptionInstance;
-
- let encryption = match req.to {
- Some(types::Receiver::Public(public)) => EncryptionInstance::ecies(public.into_inner())
- .map_err(whisper_error)?,
- Some(types::Receiver::Identity(id)) => self.store.read().encryption_instance(&id.into_inner())
- .map_err(whisper_error)?,
- None => {
- use rand::{Rng, rngs::OsRng};
-
- // broadcast mode: use fixed nonce and fresh key each time.
-
- let mut rng = OsRng::new()
- .map_err(|_| whisper_error("unable to acquire secure randomness"))?;
-
- let key = Zeroizing::new(rng.gen::<[u8; 32]>());
- if req.topics.is_empty() {
- return Err(whisper_error("must supply at least one topic for broadcast message"));
- }
-
- EncryptionInstance::broadcast(
- key,
- req.topics.iter().map(|x| topic_hash(&x)).collect()
- )
- }
- };
-
- let sign_with = match req.from {
- Some(from) => {
- Some(
- self.store.read().secret(&from.into_inner())
- .cloned()
- .ok_or_else(|| whisper_error("Unknown identity `from`"))?
- )
- }
- None => None,
- };
-
- let encrypted = {
- let payload = payload::encode(payload::EncodeParams {
- message: &req.payload.into_inner(),
- padding: req.padding.map(|p| p.into_inner()).as_ref().map(|x| &x[..]),
- sign_with: sign_with.as_ref(),
- }).map_err(whisper_error)?;
-
- encryption.encrypt(&payload).ok_or(whisper_error("encryption error"))?
- };
-
- // mining the packet is the heaviest item of work by far.
- // there may be a benefit to dispatching this onto the CPU pool
- // and returning a future. but then things get _less_ efficient
- // if the server infrastructure has more threads than the CPU pool.
- let message = Message::create(CreateParams {
- ttl: req.ttl,
- payload: encrypted,
- topics: req.topics.into_iter().map(|x| abridge_topic(&x.into_inner())).collect(),
- work: req.priority,
- }).map_err(|_| whisper_error("Empty topics"))?;
-
- if !self.pool.relay(message) {
- Err(whisper_error("PoW too low to compete with other messages"))
- } else {
- Ok(true)
- }
- }
-
- fn new_filter(&self, req: types::FilterRequest) -> Result {
- let filter = Filter::new(req).map_err(whisper_error)?;
-
- self.filter_manager.insert_polled(filter)
- .map(HexEncode)
- .map_err(whisper_error)
- }
-
- fn poll_changes(&self, id: types::Identity) -> Result, Error> {
- match self.filter_manager.poll_changes(&id.into_inner()) {
- None => Err(whisper_error("no such message filter")),
- Some(items) => Ok(items),
- }
- }
-
- fn delete_filter(&self, id: types::Identity) -> Result {
- Ok(self.delete_filter_kind(id.into_inner(), filter::Kind::Poll))
- }
-}
-
-impl WhisperPubSub for WhisperClient {
- type Metadata = M;
-
- fn subscribe(
- &self,
- _meta: Self::Metadata,
- subscriber: Subscriber,
- req: types::FilterRequest,
- ) {
- match Filter::new(req) {
- Ok(filter) => {
- if let Err(e) = self.filter_manager.insert_subscription(filter, subscriber) {
- debug!(target: "whisper", "Failed to add subscription: {}", e);
- }
- }
- Err(reason) => { let _ = subscriber.reject(whisper_error(reason)); }
- }
- }
-
- fn unsubscribe(&self, _: Option, id: SubscriptionId) -> Result {
- use std::str::FromStr;
-
- let res = match id {
- SubscriptionId::String(s) => H256::from_str(&s)
- .map_err(|_| "unrecognized ID")
- .map(|id| self.delete_filter_kind(id, filter::Kind::Subscription)),
- SubscriptionId::Number(_) => Err("unrecognized ID"),
- };
-
- res.map_err(whisper_error)
- }
-}
diff --git a/whisper/src/rpc/payload.rs b/whisper/src/rpc/payload.rs
deleted file mode 100644
index 326a6b6e2..000000000
--- a/whisper/src/rpc/payload.rs
+++ /dev/null
@@ -1,356 +0,0 @@
-// Copyright 2015-2019 Parity Technologies (UK) Ltd.
-// This file is part of Parity Ethereum.
-
-// Parity Ethereum is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Parity Ethereum is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Parity Ethereum. If not, see .
-
-//! Common payload format definition, construction, and decoding.
-//!
-//! Format:
-//! flags: 1 byte
-//!
-//! payload size: 0..4 bytes, BE, determined by flags.
-//! optional padding: byte array up to 2^24 bytes in length. encoded in payload size.
-//! optional signature: 65 bytes (r, s, v)
-//!
-//! payload: byte array of length of arbitrary size.
-//!
-//! flag bits used:
-//! 0, 1 => how many bytes indicate padding length (up to 3)
-//! 2 => whether signature is present
-//!
-//! padding is used to mask information about size of message.
-//!
-//! AES-256-GCM will append 12 bytes of metadata to the front of the message.
-
-use ethereum_types::H256;
-use byteorder::{BigEndian, ByteOrder, WriteBytesExt};
-use ethkey::{Public, Secret};
-use tiny_keccak::keccak256;
-
-const SIGNATURE_LEN: usize = 65;
-
-const STANDARD_PAYLOAD_VERSION: u8 = 1;
-
-bitflags! {
- struct Flags: u8 {
- const FLAG_PAD_LEN_HIGH = 0b10000000;
- const FLAG_PAD_LEN_LOW = 0b01000000;
- const FLAG_SIGNED = 0b00100000;
- }
-}
-
-// number of bytes of padding length (in the range 0..4)
-fn padding_length_bytes(flags: Flags) -> usize {
- match (flags & FLAG_PAD_LEN_HIGH, flags & FLAG_PAD_LEN_LOW) {
- (FLAG_PAD_LEN_HIGH, FLAG_PAD_LEN_LOW) => 3,
- (FLAG_PAD_LEN_HIGH, _) => 2,
- (_, FLAG_PAD_LEN_LOW) => 1,
- (_, _) => 0,
- }
-}
-
-// how many bytes are necessary to encode the given length. Range 0..4.
-// `None` if too large.
-fn num_padding_length_bytes(padding_len: usize) -> Option {
- let bits = 64 - (padding_len as u64).leading_zeros();
- match bits {
- 0 => Some(0),
- 0 ... 8 => Some(1),
- 0 ... 16 => Some(2),
- 0 ... 24 => Some(3),
- _ => None,
- }
-}
-
-/// Parameters for encoding a standard payload.
-pub struct EncodeParams<'a> {
- /// Message to encode.
- pub message: &'a [u8],
- /// Padding bytes. Maximum padding allowed is 65536 bytes.
- pub padding: Option<&'a [u8]>,
- /// Private key to sign with.
- pub sign_with: Option<&'a Secret>,
-}
-
-impl<'a> Default for EncodeParams<'a> {
- fn default() -> Self {
- EncodeParams {
- message: &[],
- padding: None,
- sign_with: None,
- }
- }
-}
-
-/// Parameters for decoding a standard payload.
-pub struct Decoded<'a> {
- /// Decoded message.
- pub message: &'a [u8],
- /// optional padding.
- pub padding: Option<&'a [u8]>,
- /// Recovered signature.
- pub from: Option,
-}
-
-/// Encode using provided parameters.
-pub fn encode(params: EncodeParams) -> Result, &'static str> {
- const VEC_WRITE_INFALLIBLE: &'static str = "writing to a Vec can never fail; qed";
-
- let padding_len = params.padding.map_or(0, |x| x.len());
- let padding_len_bytes = num_padding_length_bytes(padding_len)
- .ok_or_else(|| "padding size too long")?;
-
- let signature = params.sign_with.map(|secret| {
- let hash = H256(keccak256(params.message));
- ::ethkey::sign(secret, &hash)
- });
-
- let signature = match signature {
- Some(Ok(sig)) => Some(sig),
- Some(Err(_)) => return Err("invalid signing key provided"),
- None => None,
- };
-
- let (flags, plaintext_size) = {
- let mut flags = Flags::empty();
-
- // 1 byte each for flags and version.
- let mut plaintext_size = 2
- + padding_len_bytes
- + padding_len
- + params.message.len();
-
- flags.bits = (padding_len_bytes << 6) as u8;
- debug_assert_eq!(padding_length_bytes(flags), padding_len_bytes);
-
- if let Some(ref sig) = signature {
- plaintext_size += sig.len();
- flags |= FLAG_SIGNED;
- }
-
- (flags, plaintext_size)
- };
-
- let mut plaintext = Vec::with_capacity(plaintext_size);
-
- plaintext.push(STANDARD_PAYLOAD_VERSION);
- plaintext.push(flags.bits);
-
- if let Some(padding) = params.padding {
- plaintext.write_uint::(padding_len as u64, padding_len_bytes)
- .expect(VEC_WRITE_INFALLIBLE);
-
- plaintext.extend(padding)
- }
-
- if let Some(signature) = signature {
- plaintext.extend(signature.r());
- plaintext.extend(signature.s());
- plaintext.push(signature.v());
- }
-
- plaintext.extend(params.message);
-
- Ok(plaintext)
-}
-
-/// Decode using provided parameters
-pub fn decode(payload: &[u8]) -> Result {
- let mut offset = 0;
-
- let (padding, signature) = {
- // use a closure for reading slices since std::io::Read would require
- // us to copy.
- let mut next_slice = |len| {
- let end = offset + len;
- if payload.len() >= end {
- let slice = &payload[offset .. end];
- offset = end;
-
- Ok(slice)
- } else {
- return Err("unexpected end of payload")
- }
- };
-
- if next_slice(1)?[0] != STANDARD_PAYLOAD_VERSION {
- return Err("unknown payload version.");
- }
-
- let flags = Flags::from_bits_truncate(next_slice(1)?[0]);
-
- let padding_len_bytes = padding_length_bytes(flags);
- let padding = if padding_len_bytes != 0 {
- let padding_len = BigEndian::read_uint(
- next_slice(padding_len_bytes)?,
- padding_len_bytes,
- );
-
- Some(next_slice(padding_len as usize)?)
- } else {
- None
- };
-
- let signature = if flags & FLAG_SIGNED == FLAG_SIGNED {
- let slice = next_slice(SIGNATURE_LEN)?;
- let mut arr = [0; SIGNATURE_LEN];
-
- arr.copy_from_slice(slice);
- let signature = ::ethkey::Signature::from(arr);
-
- let not_rsv = signature.r() != &slice[..32]
- || signature.s() != &slice[32..64]
- || signature.v() != slice[64];
-
- if not_rsv {
- return Err("signature not in RSV format");
- } else {
- Some(signature)
- }
- } else {
- None
- };
-
- (padding, signature)
- };
-
- // remaining data is the message.
- let message = &payload[offset..];
-
- let from = match signature {
- None => None,
- Some(sig) => {
- let hash = H256(keccak256(message));
- Some(::ethkey::recover(&sig, &hash).map_err(|_| "invalid signature")?)
- }
- };
-
- Ok(Decoded {
- message: message,
- padding: padding,
- from: from,
- })
-}
-
-#[cfg(test)]
-mod tests {
- use ethkey::{Generator, Random};
- use super::*;
-
- #[test]
- fn padding_len_bytes_sanity() {
- const U24_MAX: usize = (1 << 24) - 1;
-
- assert_eq!(padding_length_bytes(FLAG_PAD_LEN_HIGH | FLAG_PAD_LEN_LOW), 3);
- assert_eq!(padding_length_bytes(FLAG_PAD_LEN_HIGH), 2);
- assert_eq!(padding_length_bytes(FLAG_PAD_LEN_LOW), 1);
- assert_eq!(padding_length_bytes(Flags::empty()), 0);
-
- assert!(num_padding_length_bytes(u32::max_value() as _).is_none());
- assert!(num_padding_length_bytes(U24_MAX + 1).is_none());
-
- assert_eq!(num_padding_length_bytes(U24_MAX), Some(3));
-
- assert_eq!(num_padding_length_bytes(u16::max_value() as usize + 1), Some(3));
- assert_eq!(num_padding_length_bytes(u16::max_value() as usize), Some(2));
-
- assert_eq!(num_padding_length_bytes(u8::max_value() as usize + 1), Some(2));
- assert_eq!(num_padding_length_bytes(u8::max_value() as usize), Some(1));
-
- assert_eq!(num_padding_length_bytes(1), Some(1));
- assert_eq!(num_padding_length_bytes(0), Some(0));
- }
-
- #[test]
- fn encode_decode_roundtrip() {
- let message = [1, 2, 3, 4, 5];
- let encoded = encode(EncodeParams {
- message: &message,
- padding: None,
- sign_with: None,
- }).unwrap();
-
- let decoded = decode(&encoded).unwrap();
-
- assert_eq!(message, decoded.message);
- }
-
- #[test]
- fn encode_empty() {
- let encoded = encode(EncodeParams {
- message: &[],
- padding: None,
- sign_with: None,
- }).unwrap();
-
- let decoded = decode(&encoded).unwrap();
-
- assert!(decoded.message.is_empty());
- }
-
- #[test]
- fn encode_with_signature() {
- let key_pair = Random.generate().unwrap();
- let message = [1, 3, 5, 7, 9];
-
- let encoded = encode(EncodeParams {
- message: &message,
- padding: None,
- sign_with: Some(key_pair.secret()),
- }).unwrap();
-
- let decoded = decode(&encoded).unwrap();
-
- assert_eq!(decoded.message, message);
- assert_eq!(decoded.from, Some(key_pair.public().clone()));
- assert!(decoded.padding.is_none());
- }
-
- #[test]
- fn encode_with_padding() {
- let message = [1, 3, 5, 7, 9];
- let padding = [0xff; 1024 - 5];
-
- let encoded = encode(EncodeParams {
- message: &message,
- padding: Some(&padding),
- sign_with: None,
- }).unwrap();
-
- let decoded = decode(&encoded).unwrap();
-
- assert_eq!(decoded.message, message);
- assert_eq!(decoded.padding, Some(&padding[..]));
- assert!(decoded.from.is_none());
- }
-
- #[test]
- fn encode_with_padding_and_signature() {
- let key_pair = Random.generate().unwrap();
- let message = [1, 3, 5, 7, 9];
- let padding = [0xff; 1024 - 5];
-
- let encoded = encode(EncodeParams {
- message: &message,
- padding: Some(&padding),
- sign_with: Some(key_pair.secret()),
- }).unwrap();
-
- let decoded = decode(&encoded).unwrap();
-
- assert_eq!(decoded.message, message);
- assert_eq!(decoded.padding, Some(&padding[..]));
- assert_eq!(decoded.from, Some(key_pair.public().clone()));
- }
-}
diff --git a/whisper/src/rpc/types.rs b/whisper/src/rpc/types.rs
deleted file mode 100644
index b5550dbff..000000000
--- a/whisper/src/rpc/types.rs
+++ /dev/null
@@ -1,298 +0,0 @@
-// Copyright 2015-2019 Parity Technologies (UK) Ltd.
-// This file is part of Parity Ethereum.
-
-// Parity Ethereum is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Parity Ethereum is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Parity Ethereum. If not, see .
-
-//! Types for Whisper RPC.
-
-use std::fmt;
-use std::convert::AsRef;
-use std::ops::Deref;
-
-use ethereum_types::{H32, H64, H128, H256, H264, H512};
-use hex::{ToHex, FromHex};
-
-use serde::{Serialize, Serializer, Deserialize, Deserializer};
-use serde::de::{Error, Visitor};
-
-/// Helper trait for generic hex bytes encoding.
-pub trait HexEncodable: Sized + AsRef<[u8]> {
- fn from_bytes(bytes: Vec) -> Option;
-}
-
-impl HexEncodable for Vec {
- fn from_bytes(bytes: Vec) -> Option { Some(bytes) }
-}
-
-macro_rules! impl_hex_for_hash {
- ($($t: ident)*) => {
- $(
- impl HexEncodable for $t {
- fn from_bytes(bytes: Vec) -> Option {
- if bytes.len() != $t::len_bytes() {
- None
- } else {
- Some($t::from_slice(&bytes))
- }
- }
- }
- )*
- }
-}
-
-impl_hex_for_hash!(
- H32 H64 H128 H256 H264 H512
-);
-
-/// Wrapper structure around hex-encoded data.
-#[derive(Debug, PartialEq, Eq, Default, Hash, Clone)]
-pub struct HexEncode(pub T);
-
-impl From for HexEncode {
- fn from(x: T) -> Self {
- HexEncode(x)
- }
-}
-
-impl HexEncode {
- /// Create a new wrapper from the inner value.
- pub fn new(x: T) -> Self { HexEncode(x) }
-
- /// Consume the wrapper, yielding the inner value.
- pub fn into_inner(self) -> T { self.0 }
-}
-
-impl Deref for HexEncode {
- type Target = T;
-
- fn deref(&self) -> &T { &self.0 }
-}
-
-/// Hex-encoded arbitrary-byte vector.
-pub type Bytes = HexEncode>;
-
-/// 32-byte local identity
-pub type Identity = HexEncode;
-
-/// Public key for ECIES, SECP256k1
-pub type Public = HexEncode<::ethkey::Public>;
-
-/// Unvalidated private key for ECIES, SECP256k1
-pub type Private = HexEncode;
-
-/// Abridged topic is four bytes.
-// only used in tests for now.
-#[cfg(test)]
-pub type AbridgedTopic = HexEncode;
-
-/// 32-byte AES key.
-pub type Symmetric = HexEncode;
-
-impl