Move a bunch of stuff around (#10101)

* Move devtools.

* Merge stop_guard & rename memzero

* Move price-info to miner.

* Group account management

* Clean up workspace members.

* Move local store closer to miner.

* Move clib examples.

* Move registrar and hash-fetch

* Move rpc_cli/rpc_client

* Move stratum closer to miner.

* Fix naming convention of crates.

* Update Cpp examples path.

* Fix paths for clib-example.

* Fix removing build.
This commit is contained in:
Tomasz Drwięga
2018-12-28 10:33:49 +01:00
committed by Wei Tang
parent bf9fedc4ee
commit ff0095ac5e
225 changed files with 111 additions and 181 deletions

View File

@@ -0,0 +1,74 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity 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 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. If not, see <http://www.gnu.org/licenses/>.
use std::{ops, str};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde::de::Error;
use rustc_hex::{ToHex, FromHex, FromHexError};
#[derive(Debug, PartialEq)]
pub struct Bytes(Vec<u8>);
impl ops::Deref for Bytes {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<'a> Deserialize<'a> for Bytes {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'a>
{
let s = String::deserialize(deserializer)?;
let data = s.from_hex().map_err(|e| Error::custom(format!("Invalid hex value {}", e)))?;
Ok(Bytes(data))
}
}
impl Serialize for Bytes {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer {
serializer.serialize_str(&self.0.to_hex())
}
}
impl str::FromStr for Bytes {
type Err = FromHexError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
s.from_hex().map(Bytes)
}
}
impl From<&'static str> for Bytes {
fn from(s: &'static str) -> Self {
s.parse().expect(&format!("invalid string literal for {}: '{}'", stringify!(Self), s))
}
}
impl From<Vec<u8>> for Bytes {
fn from(v: Vec<u8>) -> Self {
Bytes(v)
}
}
impl From<Bytes> for Vec<u8> {
fn from(b: Bytes) -> Self {
b.0
}
}

View File

@@ -0,0 +1,96 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity 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 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. If not, see <http://www.gnu.org/licenses/>.
use std::fmt;
use serde::{Serialize, Serializer, Deserialize, Deserializer};
use serde::de::{Visitor, Error as SerdeError};
use super::{Error, H128};
#[derive(Debug, PartialEq)]
pub enum CipherSer {
Aes128Ctr,
}
impl Serialize for CipherSer {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer {
match *self {
CipherSer::Aes128Ctr => serializer.serialize_str("aes-128-ctr"),
}
}
}
impl<'a> Deserialize<'a> for CipherSer {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'a> {
deserializer.deserialize_any(CipherSerVisitor)
}
}
struct CipherSerVisitor;
impl<'a> Visitor<'a> for CipherSerVisitor {
type Value = CipherSer;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a valid cipher identifier")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: SerdeError {
match value {
"aes-128-ctr" => Ok(CipherSer::Aes128Ctr),
_ => Err(SerdeError::custom(Error::UnsupportedCipher))
}
}
fn visit_string<E>(self, value: String) -> Result<Self::Value, E> where E: SerdeError {
self.visit_str(value.as_ref())
}
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Aes128Ctr {
pub iv: H128,
}
#[derive(Debug, PartialEq)]
pub enum CipherSerParams {
Aes128Ctr(Aes128Ctr),
}
impl Serialize for CipherSerParams {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer {
match *self {
CipherSerParams::Aes128Ctr(ref params) => params.serialize(serializer),
}
}
}
impl<'a> Deserialize<'a> for CipherSerParams {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'a> {
Aes128Ctr::deserialize(deserializer)
.map(CipherSerParams::Aes128Ctr)
.map_err(|_| Error::InvalidCipherParams)
.map_err(SerdeError::custom)
}
}
#[derive(Debug, PartialEq)]
pub enum Cipher {
Aes128Ctr(Aes128Ctr),
}

View File

@@ -0,0 +1,190 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity 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 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. If not, see <http://www.gnu.org/licenses/>.
use std::{fmt, str};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde::ser::SerializeStruct;
use serde::de::{Visitor, MapAccess, Error};
use serde_json;
use super::{Cipher, CipherSer, CipherSerParams, Kdf, KdfSer, KdfSerParams, H256, Bytes};
pub type CipherText = Bytes;
#[derive(Debug, PartialEq)]
pub struct Crypto {
pub cipher: Cipher,
pub ciphertext: CipherText,
pub kdf: Kdf,
pub mac: H256,
}
impl str::FromStr for Crypto {
type Err = serde_json::error::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
serde_json::from_str(s)
}
}
impl From<Crypto> for String {
fn from(c: Crypto) -> Self {
serde_json::to_string(&c).expect("serialization cannot fail, cause all crypto keys are strings")
}
}
enum CryptoField {
Cipher,
CipherParams,
CipherText,
Kdf,
KdfParams,
Mac,
}
impl<'a> Deserialize<'a> for CryptoField {
fn deserialize<D>(deserializer: D) -> Result<CryptoField, D::Error>
where D: Deserializer<'a>
{
deserializer.deserialize_any(CryptoFieldVisitor)
}
}
struct CryptoFieldVisitor;
impl<'a> Visitor<'a> for CryptoFieldVisitor {
type Value = CryptoField;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a valid crypto struct description")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where E: Error
{
match value {
"cipher" => Ok(CryptoField::Cipher),
"cipherparams" => Ok(CryptoField::CipherParams),
"ciphertext" => Ok(CryptoField::CipherText),
"kdf" => Ok(CryptoField::Kdf),
"kdfparams" => Ok(CryptoField::KdfParams),
"mac" => Ok(CryptoField::Mac),
_ => Err(Error::custom(format!("Unknown field: '{}'", value))),
}
}
}
impl<'a> Deserialize<'a> for Crypto {
fn deserialize<D>(deserializer: D) -> Result<Crypto, D::Error>
where D: Deserializer<'a>
{
static FIELDS: &'static [&'static str] = &["id", "version", "crypto", "Crypto", "address"];
deserializer.deserialize_struct("Crypto", FIELDS, CryptoVisitor)
}
}
struct CryptoVisitor;
impl<'a> Visitor<'a> for CryptoVisitor {
type Value = Crypto;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a valid vault crypto object")
}
fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
where V: MapAccess<'a>
{
let mut cipher = None;
let mut cipherparams = None;
let mut ciphertext = None;
let mut kdf = None;
let mut kdfparams = None;
let mut mac = None;
loop {
match visitor.next_key()? {
Some(CryptoField::Cipher) => { cipher = Some(visitor.next_value()?); }
Some(CryptoField::CipherParams) => { cipherparams = Some(visitor.next_value()?); }
Some(CryptoField::CipherText) => { ciphertext = Some(visitor.next_value()?); }
Some(CryptoField::Kdf) => { kdf = Some(visitor.next_value()?); }
Some(CryptoField::KdfParams) => { kdfparams = Some(visitor.next_value()?); }
Some(CryptoField::Mac) => { mac = Some(visitor.next_value()?); }
None => { break; }
}
}
let cipher = match (cipher, cipherparams) {
(Some(CipherSer::Aes128Ctr), Some(CipherSerParams::Aes128Ctr(params))) => Cipher::Aes128Ctr(params),
(None, _) => return Err(V::Error::missing_field("cipher")),
(Some(_), None) => return Err(V::Error::missing_field("cipherparams")),
};
let ciphertext = match ciphertext {
Some(ciphertext) => ciphertext,
None => return Err(V::Error::missing_field("ciphertext")),
};
let kdf = match (kdf, kdfparams) {
(Some(KdfSer::Pbkdf2), Some(KdfSerParams::Pbkdf2(params))) => Kdf::Pbkdf2(params),
(Some(KdfSer::Scrypt), Some(KdfSerParams::Scrypt(params))) => Kdf::Scrypt(params),
(Some(_), Some(_)) => return Err(V::Error::custom("Invalid cipherparams")),
(None, _) => return Err(V::Error::missing_field("kdf")),
(Some(_), None) => return Err(V::Error::missing_field("kdfparams")),
};
let mac = match mac {
Some(mac) => mac,
None => return Err(V::Error::missing_field("mac")),
};
let result = Crypto {
cipher: cipher,
ciphertext: ciphertext,
kdf: kdf,
mac: mac,
};
Ok(result)
}
}
impl Serialize for Crypto {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
let mut crypto = serializer.serialize_struct("Crypto", 6)?;
match self.cipher {
Cipher::Aes128Ctr(ref params) => {
crypto.serialize_field("cipher", &CipherSer::Aes128Ctr)?;
crypto.serialize_field("cipherparams", params)?;
},
}
crypto.serialize_field("ciphertext", &self.ciphertext)?;
match self.kdf {
Kdf::Pbkdf2(ref params) => {
crypto.serialize_field("kdf", &KdfSer::Pbkdf2)?;
crypto.serialize_field("kdfparams", params)?;
},
Kdf::Scrypt(ref params) => {
crypto.serialize_field("kdf", &KdfSer::Scrypt)?;
crypto.serialize_field("kdfparams", params)?;
},
}
crypto.serialize_field("mac", &self.mac)?;
crypto.end()
}
}

View File

@@ -0,0 +1,50 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity 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 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. If not, see <http://www.gnu.org/licenses/>.
use std::fmt;
#[derive(Debug, PartialEq)]
pub enum Error {
UnsupportedCipher,
InvalidCipherParams,
UnsupportedKdf,
InvalidUuid,
UnsupportedVersion,
InvalidCiphertext,
InvalidH256,
InvalidPrf,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
Error::InvalidUuid => write!(f, "Invalid Uuid"),
Error::UnsupportedVersion => write!(f, "Unsupported version"),
Error::UnsupportedKdf => write!(f, "Unsupported kdf"),
Error::InvalidCiphertext => write!(f, "Invalid ciphertext"),
Error::UnsupportedCipher => write!(f, "Unsupported cipher"),
Error::InvalidCipherParams => write!(f, "Invalid cipher params"),
Error::InvalidH256 => write!(f, "Invalid hash"),
Error::InvalidPrf => write!(f, "Invalid prf"),
}
}
}
impl Into<String> for Error {
fn into(self) -> String {
format!("{}", self)
}
}

View File

@@ -0,0 +1,119 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity 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 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. If not, see <http://www.gnu.org/licenses/>.
use std::{ops, fmt, str};
use rustc_hex::{FromHex, ToHex};
use serde::{Serialize, Serializer, Deserialize, Deserializer};
use serde::de::{Visitor, Error as SerdeError};
use super::Error;
macro_rules! impl_hash {
($name: ident, $size: expr) => {
pub struct $name([u8; $size]);
impl fmt::Debug for $name {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let self_ref: &[u8] = &self.0;
write!(f, "{:?}", self_ref)
}
}
impl PartialEq for $name {
fn eq(&self, other: &Self) -> bool {
let self_ref: &[u8] = &self.0;
let other_ref: &[u8] = &other.0;
self_ref == other_ref
}
}
impl ops::Deref for $name {
type Target = [u8];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Serialize for $name {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer {
serializer.serialize_str(&self.0.to_hex())
}
}
impl<'a> Deserialize<'a> for $name {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'a> {
struct HashVisitor;
impl<'b> Visitor<'b> for HashVisitor {
type Value = $name;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a hex-encoded {}", stringify!($name))
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: SerdeError {
value.parse().map_err(SerdeError::custom)
}
fn visit_string<E>(self, value: String) -> Result<Self::Value, E> where E: SerdeError {
self.visit_str(value.as_ref())
}
}
deserializer.deserialize_any(HashVisitor)
}
}
impl str::FromStr for $name {
type Err = Error;
fn from_str(value: &str) -> Result<Self, Self::Err> {
match value.from_hex() {
Ok(ref hex) if hex.len() == $size => {
let mut hash = [0u8; $size];
hash.clone_from_slice(hex);
Ok($name(hash))
}
_ => Err(Error::InvalidH256),
}
}
}
impl From<&'static str> for $name {
fn from(s: &'static str) -> Self {
s.parse().expect(&format!("invalid string literal for {}: '{}'", stringify!($name), s))
}
}
impl From<[u8; $size]> for $name {
fn from(bytes: [u8; $size]) -> Self {
$name(bytes)
}
}
impl Into<[u8; $size]> for $name {
fn into(self) -> [u8; $size] {
self.0
}
}
}
}
impl_hash!(H128, 16);
impl_hash!(H160, 20);
impl_hash!(H256, 32);

View File

@@ -0,0 +1,153 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity 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 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. If not, see <http://www.gnu.org/licenses/>.
//! Universaly unique identifier.
use std::{fmt, str};
use rustc_hex::{ToHex, FromHex};
use serde::{Deserialize, Serialize, Deserializer, Serializer};
use serde::de::{Visitor, Error as SerdeError};
use super::Error;
/// Universaly unique identifier.
#[derive(Debug, PartialEq)]
pub struct Uuid([u8; 16]);
impl From<[u8; 16]> for Uuid {
fn from(uuid: [u8; 16]) -> Self {
Uuid(uuid)
}
}
impl<'a> Into<String> for &'a Uuid {
fn into(self) -> String {
let d1 = &self.0[0..4];
let d2 = &self.0[4..6];
let d3 = &self.0[6..8];
let d4 = &self.0[8..10];
let d5 = &self.0[10..16];
[d1, d2, d3, d4, d5].into_iter().map(|d| d.to_hex()).collect::<Vec<String>>().join("-")
}
}
impl Into<String> for Uuid {
fn into(self) -> String {
Into::into(&self)
}
}
impl Into<[u8; 16]> for Uuid {
fn into(self) -> [u8; 16] {
self.0
}
}
impl fmt::Display for Uuid {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
let s: String = (self as &Uuid).into();
write!(f, "{}", s)
}
}
fn copy_into(from: &str, into: &mut [u8]) -> Result<(), Error> {
let from = from.from_hex().map_err(|_| Error::InvalidUuid)?;
if from.len() != into.len() {
return Err(Error::InvalidUuid);
}
into.copy_from_slice(&from);
Ok(())
}
impl str::FromStr for Uuid {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts: Vec<&str> = s.split("-").collect();
if parts.len() != 5 {
return Err(Error::InvalidUuid);
}
let mut uuid = [0u8; 16];
copy_into(parts[0], &mut uuid[0..4])?;
copy_into(parts[1], &mut uuid[4..6])?;
copy_into(parts[2], &mut uuid[6..8])?;
copy_into(parts[3], &mut uuid[8..10])?;
copy_into(parts[4], &mut uuid[10..16])?;
Ok(Uuid(uuid))
}
}
impl From<&'static str> for Uuid {
fn from(s: &'static str) -> Self {
s.parse().expect(&format!("invalid string literal for {}: '{}'", stringify!(Self), s))
}
}
impl Serialize for Uuid {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer {
let s: String = self.into();
serializer.serialize_str(&s)
}
}
impl<'a> Deserialize<'a> for Uuid {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'a> {
deserializer.deserialize_any(UuidVisitor)
}
}
struct UuidVisitor;
impl<'a> Visitor<'a> for UuidVisitor {
type Value = Uuid;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a valid hex-encoded UUID")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: SerdeError {
value.parse().map_err(SerdeError::custom)
}
fn visit_string<E>(self, value: String) -> Result<Self::Value, E> where E: SerdeError {
self.visit_str(value.as_ref())
}
}
#[cfg(test)]
mod tests {
use super::Uuid;
#[test]
fn uuid_from_str() {
let uuid: Uuid = "3198bc9c-6672-5ab3-d995-4942343ae5b6".into();
assert_eq!(uuid, Uuid::from([0x31, 0x98, 0xbc, 0x9c, 0x66, 0x72, 0x5a, 0xb3, 0xd9, 0x95, 0x49, 0x42, 0x34, 0x3a, 0xe5, 0xb6]));
}
#[test]
fn uuid_from_and_to_str() {
let from = "3198bc9c-6672-5ab3-d995-4942343ae5b6";
let uuid: Uuid = from.into();
let to: String = uuid.into();
assert_eq!(from, &to);
}
}

View File

@@ -0,0 +1,159 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity 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 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. If not, see <http://www.gnu.org/licenses/>.
use std::fmt;
use serde::{Serialize, Serializer, Deserialize, Deserializer};
use serde::de::{Visitor, Error as SerdeError};
use super::{Error, H256};
#[derive(Debug, PartialEq)]
pub enum KdfSer {
Pbkdf2,
Scrypt,
}
impl Serialize for KdfSer {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer {
match *self {
KdfSer::Pbkdf2 => serializer.serialize_str("pbkdf2"),
KdfSer::Scrypt => serializer.serialize_str("scrypt"),
}
}
}
impl<'a> Deserialize<'a> for KdfSer {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'a> {
deserializer.deserialize_any(KdfSerVisitor)
}
}
struct KdfSerVisitor;
impl<'a> Visitor<'a> for KdfSerVisitor {
type Value = KdfSer;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a kdf algorithm identifier")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: SerdeError {
match value {
"pbkdf2" => Ok(KdfSer::Pbkdf2),
"scrypt" => Ok(KdfSer::Scrypt),
_ => Err(SerdeError::custom(Error::UnsupportedKdf))
}
}
fn visit_string<E>(self, value: String) -> Result<Self::Value, E> where E: SerdeError {
self.visit_str(value.as_ref())
}
}
#[derive(Debug, PartialEq)]
pub enum Prf {
HmacSha256,
}
impl Serialize for Prf {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer {
match *self {
Prf::HmacSha256 => serializer.serialize_str("hmac-sha256"),
}
}
}
impl<'a> Deserialize<'a> for Prf {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'a> {
deserializer.deserialize_any(PrfVisitor)
}
}
struct PrfVisitor;
impl<'a> Visitor<'a> for PrfVisitor {
type Value = Prf;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a prf algorithm identifier")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: SerdeError {
match value {
"hmac-sha256" => Ok(Prf::HmacSha256),
_ => Err(SerdeError::custom(Error::InvalidPrf)),
}
}
fn visit_string<E>(self, value: String) -> Result<Self::Value, E> where E: SerdeError {
self.visit_str(value.as_ref())
}
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Pbkdf2 {
pub c: u32,
pub dklen: u32,
pub prf: Prf,
pub salt: H256,
}
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct Scrypt {
pub dklen: u32,
pub p: u32,
pub n: u32,
pub r: u32,
pub salt: H256,
}
#[derive(Debug, PartialEq)]
pub enum KdfSerParams {
Pbkdf2(Pbkdf2),
Scrypt(Scrypt),
}
impl Serialize for KdfSerParams {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer {
match *self {
KdfSerParams::Pbkdf2(ref params) => params.serialize(serializer),
KdfSerParams::Scrypt(ref params) => params.serialize(serializer),
}
}
}
impl<'a> Deserialize<'a> for KdfSerParams {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where D: Deserializer<'a> {
use serde_json::{Value, from_value};
let v: Value = Deserialize::deserialize(deserializer)?;
from_value(v.clone()).map(KdfSerParams::Pbkdf2)
.or_else(|_| from_value(v).map(KdfSerParams::Scrypt))
.map_err(|_| D::Error::custom("Invalid KDF algorithm"))
}
}
#[derive(Debug, PartialEq)]
pub enum Kdf {
Pbkdf2(Pbkdf2),
Scrypt(Scrypt),
}

View File

@@ -0,0 +1,329 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity 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 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. If not, see <http://www.gnu.org/licenses/>.
use std::fmt;
use std::io::{Read, Write};
use serde::{Serialize, Serializer, Deserialize, Deserializer};
use serde::de::{Error, Visitor, MapAccess, DeserializeOwned};
use serde_json;
use super::{Uuid, Version, Crypto, H160};
/// Public opaque type representing serializable `KeyFile`.
#[derive(Debug, PartialEq)]
pub struct OpaqueKeyFile {
key_file: KeyFile
}
impl Serialize for OpaqueKeyFile {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where
S: Serializer,
{
self.key_file.serialize(serializer)
}
}
impl<T> From<T> for OpaqueKeyFile where T: Into<KeyFile> {
fn from(val: T) -> Self {
OpaqueKeyFile { key_file: val.into() }
}
}
#[derive(Debug, PartialEq, Serialize)]
pub struct KeyFile {
pub id: Uuid,
pub version: Version,
pub crypto: Crypto,
pub address: H160,
pub name: Option<String>,
pub meta: Option<String>,
}
enum KeyFileField {
Id,
Version,
Crypto,
Address,
Name,
Meta,
}
impl<'a> Deserialize<'a> for KeyFileField {
fn deserialize<D>(deserializer: D) -> Result<KeyFileField, D::Error>
where D: Deserializer<'a>
{
deserializer.deserialize_any(KeyFileFieldVisitor)
}
}
struct KeyFileFieldVisitor;
impl<'a> Visitor<'a> for KeyFileFieldVisitor {
type Value = KeyFileField;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a valid key file field")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where E: Error
{
match value {
"id" => Ok(KeyFileField::Id),
"version" => Ok(KeyFileField::Version),
"crypto" => Ok(KeyFileField::Crypto),
"Crypto" => Ok(KeyFileField::Crypto),
"address" => Ok(KeyFileField::Address),
"name" => Ok(KeyFileField::Name),
"meta" => Ok(KeyFileField::Meta),
_ => Err(Error::custom(format!("Unknown field: '{}'", value))),
}
}
}
impl<'a> Deserialize<'a> for KeyFile {
fn deserialize<D>(deserializer: D) -> Result<KeyFile, D::Error>
where D: Deserializer<'a>
{
static FIELDS: &'static [&'static str] = &["id", "version", "crypto", "Crypto", "address"];
deserializer.deserialize_struct("KeyFile", FIELDS, KeyFileVisitor)
}
}
fn none_if_empty<'a, T>(v: Option<serde_json::Value>) -> Option<T> where
T: DeserializeOwned
{
v.and_then(|v| if v.is_null() {
None
} else {
serde_json::from_value(v).ok()
})
}
struct KeyFileVisitor;
impl<'a> Visitor<'a> for KeyFileVisitor {
type Value = KeyFile;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a valid key object")
}
fn visit_map<V>(self, mut visitor: V) -> Result<Self::Value, V::Error>
where V: MapAccess<'a>
{
let mut id = None;
let mut version = None;
let mut crypto = None;
let mut address = None;
let mut name = None;
let mut meta = None;
loop {
match visitor.next_key()? {
Some(KeyFileField::Id) => { id = Some(visitor.next_value()?); }
Some(KeyFileField::Version) => { version = Some(visitor.next_value()?); }
Some(KeyFileField::Crypto) => { crypto = Some(visitor.next_value()?); }
Some(KeyFileField::Address) => { address = Some(visitor.next_value()?); }
Some(KeyFileField::Name) => { name = none_if_empty(visitor.next_value().ok()) }
Some(KeyFileField::Meta) => { meta = none_if_empty(visitor.next_value().ok()) }
None => { break; }
}
}
let id = match id {
Some(id) => id,
None => return Err(V::Error::missing_field("id")),
};
let version = match version {
Some(version) => version,
None => return Err(V::Error::missing_field("version")),
};
let crypto = match crypto {
Some(crypto) => crypto,
None => return Err(V::Error::missing_field("crypto")),
};
let address = match address {
Some(address) => address,
None => return Err(V::Error::missing_field("address")),
};
let result = KeyFile {
id: id,
version: version,
crypto: crypto,
address: address,
name: name,
meta: meta,
};
Ok(result)
}
}
impl KeyFile {
pub fn load<R>(reader: R) -> Result<Self, serde_json::Error> where R: Read {
serde_json::from_reader(reader)
}
pub fn write<W>(&self, writer: &mut W) -> Result<(), serde_json::Error> where W: Write {
serde_json::to_writer(writer, self)
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use serde_json;
use json::{KeyFile, Uuid, Version, Crypto, Cipher, Aes128Ctr, Kdf, Scrypt};
#[test]
fn basic_keyfile() {
let json = r#"
{
"address": "6edddfc6349aff20bc6467ccf276c5b52487f7a8",
"crypto": {
"cipher": "aes-128-ctr",
"ciphertext": "7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc",
"cipherparams": {
"iv": "b5a7ec855ec9e2c405371356855fec83"
},
"kdf": "scrypt",
"kdfparams": {
"dklen": 32,
"n": 262144,
"p": 1,
"r": 8,
"salt": "1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209"
},
"mac": "46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f"
},
"id": "8777d9f6-7860-4b9b-88b7-0b57ee6b3a73",
"version": 3,
"name": "Test",
"meta": "{}"
}"#;
let expected = KeyFile {
id: Uuid::from_str("8777d9f6-7860-4b9b-88b7-0b57ee6b3a73").unwrap(),
version: Version::V3,
address: "6edddfc6349aff20bc6467ccf276c5b52487f7a8".into(),
crypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: "b5a7ec855ec9e2c405371356855fec83".into(),
}),
ciphertext: "7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc".into(),
kdf: Kdf::Scrypt(Scrypt {
n: 262144,
dklen: 32,
p: 1,
r: 8,
salt: "1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209".into(),
}),
mac: "46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f".into(),
},
name: Some("Test".to_owned()),
meta: Some("{}".to_owned()),
};
let keyfile: KeyFile = serde_json::from_str(json).unwrap();
assert_eq!(keyfile, expected);
}
#[test]
fn capital_crypto_keyfile() {
let json = r#"
{
"address": "6edddfc6349aff20bc6467ccf276c5b52487f7a8",
"Crypto": {
"cipher": "aes-128-ctr",
"ciphertext": "7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc",
"cipherparams": {
"iv": "b5a7ec855ec9e2c405371356855fec83"
},
"kdf": "scrypt",
"kdfparams": {
"dklen": 32,
"n": 262144,
"p": 1,
"r": 8,
"salt": "1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209"
},
"mac": "46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f"
},
"id": "8777d9f6-7860-4b9b-88b7-0b57ee6b3a73",
"version": 3
}"#;
let expected = KeyFile {
id: "8777d9f6-7860-4b9b-88b7-0b57ee6b3a73".into(),
version: Version::V3,
address: "6edddfc6349aff20bc6467ccf276c5b52487f7a8".into(),
crypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: "b5a7ec855ec9e2c405371356855fec83".into(),
}),
ciphertext: "7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc".into(),
kdf: Kdf::Scrypt(Scrypt {
n: 262144,
dklen: 32,
p: 1,
r: 8,
salt: "1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209".into(),
}),
mac: "46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f".into(),
},
name: None,
meta: None,
};
let keyfile: KeyFile = serde_json::from_str(json).unwrap();
assert_eq!(keyfile, expected);
}
#[test]
fn to_and_from_json() {
let file = KeyFile {
id: "8777d9f6-7860-4b9b-88b7-0b57ee6b3a73".into(),
version: Version::V3,
address: "6edddfc6349aff20bc6467ccf276c5b52487f7a8".into(),
crypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: "b5a7ec855ec9e2c405371356855fec83".into(),
}),
ciphertext: "7203da0676d141b138cd7f8e1a4365f59cc1aa6978dc5443f364ca943d7cb4bc".into(),
kdf: Kdf::Scrypt(Scrypt {
n: 262144,
dklen: 32,
p: 1,
r: 8,
salt: "1e8642fdf1f87172492c1412fc62f8db75d796cdfa9c53c3f2b11e44a2a1b209".into(),
}),
mac: "46325c5d4e8c991ad2683d525c7854da387138b6ca45068985aa4959fa2b8c8f".into(),
},
name: Some("Test".to_owned()),
meta: None,
};
let serialized = serde_json::to_string(&file).unwrap();
println!("{}", serialized);
let deserialized = serde_json::from_str(&serialized).unwrap();
assert_eq!(file, deserialized);
}
}

View File

@@ -0,0 +1,43 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity 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 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. If not, see <http://www.gnu.org/licenses/>.
//! Contract interface specification.
mod bytes;
mod cipher;
mod crypto;
mod error;
mod hash;
mod id;
mod kdf;
mod key_file;
mod presale;
mod vault_file;
mod vault_key_file;
mod version;
pub use self::bytes::Bytes;
pub use self::cipher::{Cipher, CipherSer, CipherSerParams, Aes128Ctr};
pub use self::crypto::{Crypto, CipherText};
pub use self::error::Error;
pub use self::hash::{H128, H160, H256};
pub use self::id::Uuid;
pub use self::kdf::{Kdf, KdfSer, Prf, Pbkdf2, Scrypt, KdfSerParams};
pub use self::key_file::{KeyFile, OpaqueKeyFile};
pub use self::presale::{PresaleWallet, Encseed};
pub use self::vault_file::VaultFile;
pub use self::vault_key_file::{VaultKeyFile, VaultKeyMeta, insert_vault_name_to_json_meta, remove_vault_name_from_json_meta};
pub use self::version::Version;

View File

@@ -0,0 +1,80 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity 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 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. If not, see <http://www.gnu.org/licenses/>.
use std::io::Read;
use serde_json;
use super::{H160, Bytes};
pub type Encseed = Bytes;
#[derive(Debug, PartialEq, Deserialize)]
pub struct PresaleWallet {
pub encseed: Encseed,
#[serde(rename = "ethaddr")]
pub address: H160,
}
impl PresaleWallet {
pub fn load<R>(reader: R) -> Result<Self, serde_json::Error> where R: Read {
serde_json::from_reader(reader)
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use serde_json;
use json::{PresaleWallet, H160};
#[test]
fn presale_wallet() {
let json = r#"
{
"encseed": "137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066",
"ethaddr": "ede84640d1a1d3e06902048e67aa7db8d52c2ce1",
"email": "123@gmail.com",
"btcaddr": "1JvqEc6WLhg6GnyrLBe2ztPAU28KRfuseH"
} "#;
let expected = PresaleWallet {
encseed: "137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066".into(),
address: H160::from_str("ede84640d1a1d3e06902048e67aa7db8d52c2ce1").unwrap(),
};
let wallet: PresaleWallet = serde_json::from_str(json).unwrap();
assert_eq!(expected, wallet);
}
#[test]
fn long_presale_wallet() {
let json = r#"
{
"encseed":
"137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0d",
"ethaddr": "ede84640d1a1d3e06902048e67aa7db8d52c2ce1",
"email": "123@gmail.com",
"btcaddr": "1JvqEc6WLhg6GnyrLBe2ztPAU28KRfuseH"
} "#;
let expected = PresaleWallet {
encseed: "137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dedb3bc0a9ac6c79b9c426c5878ca2c9d06ff42a23cb648312fc32ba83649de0928e066137103c28caeebbcea5d7f95edb97a289ded151b72159137cb7b2671f394f54cff8c121589dcb373e267225547b3c71cbdb54f6e48ec85cd549f96cf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0dcf0d".into(),
address: H160::from_str("ede84640d1a1d3e06902048e67aa7db8d52c2ce1").unwrap(),
};
let wallet: PresaleWallet = serde_json::from_str(json).unwrap();
assert_eq!(expected, wallet);
}
}

View File

@@ -0,0 +1,94 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity 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 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. If not, see <http://www.gnu.org/licenses/>.
use std::io::{Read, Write};
use serde_json;
use super::Crypto;
/// Vault meta file
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct VaultFile {
/// Vault password, encrypted with vault password
pub crypto: Crypto,
/// Vault metadata string
pub meta: Option<String>,
}
impl VaultFile {
pub fn load<R>(reader: R) -> Result<Self, serde_json::Error> where R: Read {
serde_json::from_reader(reader)
}
pub fn write<W>(&self, writer: &mut W) -> Result<(), serde_json::Error> where W: Write {
serde_json::to_writer(writer, self)
}
}
#[cfg(test)]
mod test {
use serde_json;
use json::{VaultFile, Crypto, Cipher, Aes128Ctr, Kdf, Pbkdf2, Prf};
#[test]
fn to_and_from_json() {
let file = VaultFile {
crypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: "0155e3690be19fbfbecabcd440aa284b".into(),
}),
ciphertext: "4d6938a1f49b7782".into(),
kdf: Kdf::Pbkdf2(Pbkdf2 {
c: 1024,
dklen: 32,
prf: Prf::HmacSha256,
salt: "b6a9338a7ccd39288a86dba73bfecd9101b4f3db9c9830e7c76afdbd4f6872e5".into(),
}),
mac: "16381463ea11c6eb2239a9f339c2e780516d29d234ce30ac5f166f9080b5a262".into(),
},
meta: Some("{}".into()),
};
let serialized = serde_json::to_string(&file).unwrap();
let deserialized = serde_json::from_str(&serialized).unwrap();
assert_eq!(file, deserialized);
}
#[test]
fn to_and_from_json_no_meta() {
let file = VaultFile {
crypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: "0155e3690be19fbfbecabcd440aa284b".into(),
}),
ciphertext: "4d6938a1f49b7782".into(),
kdf: Kdf::Pbkdf2(Pbkdf2 {
c: 1024,
dklen: 32,
prf: Prf::HmacSha256,
salt: "b6a9338a7ccd39288a86dba73bfecd9101b4f3db9c9830e7c76afdbd4f6872e5".into(),
}),
mac: "16381463ea11c6eb2239a9f339c2e780516d29d234ce30ac5f166f9080b5a262".into(),
},
meta: None,
};
let serialized = serde_json::to_string(&file).unwrap();
let deserialized = serde_json::from_str(&serialized).unwrap();
assert_eq!(file, deserialized);
}
}

View File

@@ -0,0 +1,172 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity 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 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. If not, see <http://www.gnu.org/licenses/>.
use std::io::{Read, Write};
use serde::de::Error;
use serde_json;
use serde_json::value::Value;
use serde_json::error;
use super::{Uuid, Version, Crypto, H160};
/// Meta key name for vault field
const VAULT_NAME_META_KEY: &'static str = "vault";
/// Key file as stored in vaults
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct VaultKeyFile {
/// Key id
pub id: Uuid,
/// Key version
pub version: Version,
/// Secret, encrypted with account password
pub crypto: Crypto,
/// Serialized `VaultKeyMeta`, encrypted with vault password
pub metacrypto: Crypto,
}
/// Data, stored in `VaultKeyFile::metacrypto`
#[derive(Debug, PartialEq, Serialize, Deserialize)]
pub struct VaultKeyMeta {
/// Key address
pub address: H160,
/// Key name
pub name: Option<String>,
/// Key metadata
pub meta: Option<String>,
}
/// Insert vault name to the JSON meta field
pub fn insert_vault_name_to_json_meta(meta: &str, vault_name: &str) -> Result<String, error::Error> {
let mut meta = if meta.is_empty() {
Value::Object(serde_json::Map::new())
} else {
serde_json::from_str(meta)?
};
if let Some(meta_obj) = meta.as_object_mut() {
meta_obj.insert(VAULT_NAME_META_KEY.to_owned(), Value::String(vault_name.to_owned()));
serde_json::to_string(meta_obj)
} else {
Err(error::Error::custom("Meta is expected to be a serialized JSON object"))
}
}
/// Remove vault name from the JSON meta field
pub fn remove_vault_name_from_json_meta(meta: &str) -> Result<String, error::Error> {
let mut meta = if meta.is_empty() {
Value::Object(serde_json::Map::new())
} else {
serde_json::from_str(meta)?
};
if let Some(meta_obj) = meta.as_object_mut() {
meta_obj.remove(VAULT_NAME_META_KEY);
serde_json::to_string(meta_obj)
} else {
Err(error::Error::custom("Meta is expected to be a serialized JSON object"))
}
}
impl VaultKeyFile {
pub fn load<R>(reader: R) -> Result<Self, serde_json::Error> where R: Read {
serde_json::from_reader(reader)
}
pub fn write<W>(&self, writer: &mut W) -> Result<(), serde_json::Error> where W: Write {
serde_json::to_writer(writer, self)
}
}
impl VaultKeyMeta {
pub fn load(bytes: &[u8]) -> Result<Self, serde_json::Error> {
serde_json::from_slice(&bytes)
}
pub fn write(&self) -> Result<Vec<u8>, serde_json::Error> {
let s = serde_json::to_string(self)?;
Ok(s.as_bytes().into())
}
}
#[cfg(test)]
mod test {
use serde_json;
use json::{VaultKeyFile, Version, Crypto, Cipher, Aes128Ctr, Kdf, Pbkdf2, Prf,
insert_vault_name_to_json_meta, remove_vault_name_from_json_meta};
#[test]
fn to_and_from_json() {
let file = VaultKeyFile {
id: "08d82c39-88e3-7a71-6abb-89c8f36c3ceb".into(),
version: Version::V3,
crypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: "fecb968bbc8c7e608a89ebcfe53a41d0".into(),
}),
ciphertext: "4befe0a66d9a4b6fec8e39eb5c90ac5dafdeaab005fff1af665fd1f9af925c91".into(),
kdf: Kdf::Pbkdf2(Pbkdf2 {
c: 10240,
dklen: 32,
prf: Prf::HmacSha256,
salt: "f17731e84ecac390546692dbd4ccf6a3a2720dc9652984978381e61c28a471b2".into(),
}),
mac: "7c7c3daafb24cf11eb3079dfb9064a11e92f309a0ee1dd676486bab119e686b7".into(),
},
metacrypto: Crypto {
cipher: Cipher::Aes128Ctr(Aes128Ctr {
iv: "9c353fb3f894fc05946843616c26bb3f".into(),
}),
ciphertext: "fef0d113d7576c1702daf380ad6f4c5408389e57991cae2a174facd74bd549338e1014850bddbab7eb486ff5f5c9c5532800c6a6d4db2be2212cd5cd3769244ab230e1f369e8382a9e6d7c0a".into(),
kdf: Kdf::Pbkdf2(Pbkdf2 {
c: 10240,
dklen: 32,
prf: Prf::HmacSha256,
salt: "aca82865174a82249a198814b263f43a631f272cbf7ed329d0f0839d259c652a".into(),
}),
mac: "b7413946bfe459d2801268dc331c04b3a84d92be11ef4dd9a507f895e8d9b5bd".into(),
}
};
let serialized = serde_json::to_string(&file).unwrap();
let deserialized = serde_json::from_str(&serialized).unwrap();
assert_eq!(file, deserialized);
}
#[test]
fn vault_name_inserted_to_json_meta() {
assert_eq!(insert_vault_name_to_json_meta(r#""#, "MyVault").unwrap(), r#"{"vault":"MyVault"}"#);
assert_eq!(insert_vault_name_to_json_meta(r#"{"tags":["kalabala"]}"#, "MyVault").unwrap(), r#"{"tags":["kalabala"],"vault":"MyVault"}"#);
}
#[test]
fn vault_name_not_inserted_to_json_meta() {
assert!(insert_vault_name_to_json_meta(r#"///3533"#, "MyVault").is_err());
assert!(insert_vault_name_to_json_meta(r#""string""#, "MyVault").is_err());
}
#[test]
fn vault_name_removed_from_json_meta() {
assert_eq!(remove_vault_name_from_json_meta(r#"{"vault":"MyVault"}"#).unwrap(), r#"{}"#);
assert_eq!(remove_vault_name_from_json_meta(r#"{"tags":["kalabala"],"vault":"MyVault"}"#).unwrap(), r#"{"tags":["kalabala"]}"#);
}
#[test]
fn vault_name_not_removed_from_json_meta() {
assert!(remove_vault_name_from_json_meta(r#"///3533"#).is_err());
assert!(remove_vault_name_from_json_meta(r#""string""#).is_err());
}
}

View File

@@ -0,0 +1,58 @@
// Copyright 2015-2018 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity 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 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. If not, see <http://www.gnu.org/licenses/>.
use std::fmt;
use serde::{Serialize, Serializer, Deserialize, Deserializer};
use serde::de::{Error as SerdeError, Visitor};
use super::Error;
#[derive(Debug, PartialEq)]
pub enum Version {
V3,
}
impl Serialize for Version {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer {
match *self {
Version::V3 => serializer.serialize_u64(3)
}
}
}
impl<'a> Deserialize<'a> for Version {
fn deserialize<D>(deserializer: D) -> Result<Version, D::Error>
where D: Deserializer<'a> {
deserializer.deserialize_any(VersionVisitor)
}
}
struct VersionVisitor;
impl<'a> Visitor<'a> for VersionVisitor {
type Value = Version;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a valid key version identifier")
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E> where E: SerdeError {
match value {
3 => Ok(Version::V3),
_ => Err(SerdeError::custom(Error::UnsupportedVersion))
}
}
}