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:
74
accounts/ethstore/src/json/bytes.rs
Normal file
74
accounts/ethstore/src/json/bytes.rs
Normal 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
|
||||
}
|
||||
}
|
||||
96
accounts/ethstore/src/json/cipher.rs
Normal file
96
accounts/ethstore/src/json/cipher.rs
Normal 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),
|
||||
}
|
||||
190
accounts/ethstore/src/json/crypto.rs
Normal file
190
accounts/ethstore/src/json/crypto.rs
Normal 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()
|
||||
}
|
||||
}
|
||||
50
accounts/ethstore/src/json/error.rs
Normal file
50
accounts/ethstore/src/json/error.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
119
accounts/ethstore/src/json/hash.rs
Normal file
119
accounts/ethstore/src/json/hash.rs
Normal 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);
|
||||
153
accounts/ethstore/src/json/id.rs
Normal file
153
accounts/ethstore/src/json/id.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
159
accounts/ethstore/src/json/kdf.rs
Normal file
159
accounts/ethstore/src/json/kdf.rs
Normal 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),
|
||||
}
|
||||
329
accounts/ethstore/src/json/key_file.rs
Normal file
329
accounts/ethstore/src/json/key_file.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
43
accounts/ethstore/src/json/mod.rs
Normal file
43
accounts/ethstore/src/json/mod.rs
Normal 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;
|
||||
80
accounts/ethstore/src/json/presale.rs
Normal file
80
accounts/ethstore/src/json/presale.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
94
accounts/ethstore/src/json/vault_file.rs
Normal file
94
accounts/ethstore/src/json/vault_file.rs
Normal 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);
|
||||
}
|
||||
}
|
||||
172
accounts/ethstore/src/json/vault_key_file.rs
Normal file
172
accounts/ethstore/src/json/vault_key_file.rs
Normal 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());
|
||||
}
|
||||
}
|
||||
58
accounts/ethstore/src/json/version.rs
Normal file
58
accounts/ethstore/src/json/version.rs
Normal 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))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user