documentation effort
This commit is contained in:
parent
1c57214786
commit
f198e53891
@ -14,19 +14,18 @@
|
|||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
//! SecretStore
|
//! Keys Directory
|
||||||
//! module for managing key files, decrypting and encrypting arbitrary data
|
|
||||||
|
|
||||||
use common::*;
|
use common::*;
|
||||||
use std::path::{PathBuf};
|
use std::path::{PathBuf};
|
||||||
|
|
||||||
const CURRENT_DECLARED_VERSION: u64 = 3;
|
const CURRENT_DECLARED_VERSION: u64 = 3;
|
||||||
|
|
||||||
const MAX_KEY_FILE_LEN: u64 = 1024 * 80;
|
const MAX_KEY_FILE_LEN: u64 = 1024 * 80;
|
||||||
|
|
||||||
|
/// Cipher type (currently only aes-128-ctr)
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
enum CryptoCipherType {
|
pub enum CryptoCipherType {
|
||||||
// aes-128-ctr with 128-bit initialisation vector(iv)
|
/// aes-128-ctr with 128-bit initialisation vector(iv)
|
||||||
Aes128Ctr(U128)
|
Aes128Ctr(U128)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -35,23 +34,25 @@ enum KeyFileVersion {
|
|||||||
V3(u64)
|
V3(u64)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// key generator function
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
enum Pbkdf2CryptoFunction {
|
pub enum Pbkdf2CryptoFunction {
|
||||||
|
/// keyed-hash generator (HMAC-256)
|
||||||
HMacSha256
|
HMacSha256
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
// Kdf of type `Pbkdf2`
|
/// Kdf of type `Pbkdf2`
|
||||||
// https://en.wikipedia.org/wiki/PBKDF2
|
/// https://en.wikipedia.org/wiki/PBKDF2
|
||||||
struct KdfPbkdf2Params {
|
pub struct KdfPbkdf2Params {
|
||||||
// desired length of the derived key, in octets
|
/// desired length of the derived key, in octets
|
||||||
dkLen: u32,
|
pub dkLen: u32,
|
||||||
// cryptographic salt
|
/// cryptographic salt
|
||||||
salt: H256,
|
pub salt: H256,
|
||||||
// number of iterations for derived key
|
/// number of iterations for derived key
|
||||||
c: u32,
|
pub c: u32,
|
||||||
// pseudo-random 2-parameters function
|
/// pseudo-random 2-parameters function
|
||||||
prf: Pbkdf2CryptoFunction
|
pub prf: Pbkdf2CryptoFunction
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -94,25 +95,24 @@ impl KdfPbkdf2Params {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
// Kdf of type `Scrypt`
|
/// Kdf of type `Scrypt`
|
||||||
// https://en.wikipedia.org/wiki/Scrypt
|
/// https://en.wikipedia.org/wiki/Scrypt
|
||||||
struct KdfScryptParams {
|
pub struct KdfScryptParams {
|
||||||
// desired length of the derived key, in octets
|
/// desired length of the derived key, in octets
|
||||||
dkLen: u32,
|
pub dkLen: u32,
|
||||||
// parallelization
|
/// parallelization
|
||||||
p: u32,
|
pub p: u32,
|
||||||
// cpu cost
|
/// cpu cost
|
||||||
n: u32,
|
pub n: u32,
|
||||||
// TODO: comment
|
/// TODO: comment
|
||||||
r: u32,
|
pub r: u32,
|
||||||
// cryptographic salt
|
/// cryptographic salt
|
||||||
salt: H256,
|
pub salt: H256,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum ScryptParseError {
|
enum ScryptParseError {
|
||||||
InvalidParameter(&'static str),
|
InvalidParameter(&'static str),
|
||||||
InvalidPrf(Mismatch<String>),
|
|
||||||
InvalidSaltFormat(UtilError),
|
InvalidSaltFormat(UtilError),
|
||||||
MissingParameter(&'static str),
|
MissingParameter(&'static str),
|
||||||
}
|
}
|
||||||
@ -148,15 +148,22 @@ impl KdfScryptParams {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum KeyFileKdf {
|
/// Settings for password derived key geberator function
|
||||||
|
pub enum KeyFileKdf {
|
||||||
|
/// Password-Based Key Derivation Function 2 (PBKDF2) type
|
||||||
|
/// https://en.wikipedia.org/wiki/PBKDF2
|
||||||
Pbkdf2(KdfPbkdf2Params),
|
Pbkdf2(KdfPbkdf2Params),
|
||||||
|
/// Scrypt password-based key derivation function
|
||||||
|
/// https://en.wikipedia.org/wiki/Scrypt
|
||||||
Scrypt(KdfScryptParams)
|
Scrypt(KdfScryptParams)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct KeyFileCrypto {
|
/// Encrypted password or other arbitrary message
|
||||||
cipher_type: CryptoCipherType,
|
/// with settings for password derived key generator for decrypting content
|
||||||
cipher_text: Bytes,
|
pub struct KeyFileCrypto {
|
||||||
kdf: KeyFileKdf,
|
pub cipher_type: CryptoCipherType,
|
||||||
|
pub cipher_text: Bytes,
|
||||||
|
pub kdf: KeyFileKdf,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KeyFileCrypto {
|
impl KeyFileCrypto {
|
||||||
@ -229,38 +236,185 @@ impl KeyFileCrypto {
|
|||||||
|
|
||||||
Json::Object(map)
|
Json::Object(map)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// New pbkdf2-type secret
|
||||||
|
/// `cipher-text` - encrypted cipher text
|
||||||
|
/// `dk-len` - desired length of the derived key, in octets
|
||||||
|
/// `c` - number of iterations for derived key
|
||||||
|
/// `salt` - cryptographic site, random 256-bit hash (ensure it's crypto-random)
|
||||||
|
/// `iv` - ini
|
||||||
|
pub fn new_pbkdf2(cipher_text: Bytes, iv: U128, salt: H256, c: u32, dk_len: u32) -> KeyFileCrypto {
|
||||||
|
KeyFileCrypto {
|
||||||
|
cipher_type: CryptoCipherType::Aes128Ctr(iv),
|
||||||
|
cipher_text: cipher_text,
|
||||||
|
kdf: KeyFileKdf::Pbkdf2(KdfPbkdf2Params {
|
||||||
|
dkLen: dk_len,
|
||||||
|
salt: salt,
|
||||||
|
c: c,
|
||||||
|
prf: Pbkdf2CryptoFunction::HMacSha256
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Uuid = String;
|
/// Universally unique identifier
|
||||||
|
pub type Uuid = H128;
|
||||||
|
|
||||||
struct KeyFileContent {
|
fn new_uuid() -> Uuid {
|
||||||
|
H128::random()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn uuid_to_string(uuid: &Uuid) -> String {
|
||||||
|
let d1 = &uuid.as_slice()[0..4];
|
||||||
|
let d2 = &uuid.as_slice()[4..6];
|
||||||
|
let d3 = &uuid.as_slice()[6..8];
|
||||||
|
let d4 = &uuid.as_slice()[8..10];
|
||||||
|
let d5 = &uuid.as_slice()[10..16];
|
||||||
|
format!("{}-{}-{}-{}-{}", d1.to_hex(), d2.to_hex(), d3.to_hex(), d4.to_hex(), d5.to_hex())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn uuid_from_string(s: &str) -> Result<Uuid, UtilError> {
|
||||||
|
let parts: Vec<&str> = s.split("-").collect();
|
||||||
|
if parts.len() != 5 { return Err(UtilError::BadSize); }
|
||||||
|
|
||||||
|
let mut uuid = H128::zero();
|
||||||
|
|
||||||
|
if parts[0].len() != 8 { return Err(UtilError::BadSize); }
|
||||||
|
uuid[0..4].clone_from_slice(&try!(FromHex::from_hex(parts[0])));
|
||||||
|
if parts[1].len() != 4 { return Err(UtilError::BadSize); }
|
||||||
|
uuid[4..6].clone_from_slice(&try!(FromHex::from_hex(parts[1])));
|
||||||
|
if parts[2].len() != 4 { return Err(UtilError::BadSize); }
|
||||||
|
uuid[6..8].clone_from_slice(&try!(FromHex::from_hex(parts[2])));
|
||||||
|
if parts[3].len() != 4 { return Err(UtilError::BadSize); }
|
||||||
|
uuid[8..10].clone_from_slice(&try!(FromHex::from_hex(parts[3])));
|
||||||
|
if parts[4].len() != 12 { return Err(UtilError::BadSize); }
|
||||||
|
uuid[10..16].clone_from_slice(&try!(FromHex::from_hex(parts[4])));
|
||||||
|
|
||||||
|
Ok(uuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Stored key file struct with encrypted message (cipher_text)
|
||||||
|
/// also contains password derivation function settings (PBKDF2/Scrypt)
|
||||||
|
pub struct KeyFileContent {
|
||||||
version: KeyFileVersion,
|
version: KeyFileVersion,
|
||||||
crypto: KeyFileCrypto,
|
/// holds cypher and decrypt function settings
|
||||||
id: Uuid
|
pub crypto: KeyFileCrypto,
|
||||||
|
/// identifier
|
||||||
|
pub id: Uuid
|
||||||
}
|
}
|
||||||
|
|
||||||
struct KeyDirectory {
|
#[derive(Debug)]
|
||||||
cache: HashMap<Uuid, KeyFileContent>,
|
enum CryptoParseError {
|
||||||
path: Path,
|
NoCipherText,
|
||||||
|
NoCipherType,
|
||||||
|
InvalidJsonFormat,
|
||||||
|
InvalidKdfType(Mismatch<String>),
|
||||||
|
InvalidCipherType(Mismatch<String>),
|
||||||
|
NoInitialVector,
|
||||||
|
NoCipherParameters,
|
||||||
|
InvalidInitialVector(FromHexError),
|
||||||
|
NoKdfType,
|
||||||
|
Scrypt(ScryptParseError),
|
||||||
|
KdfPbkdf2(Pbkdf2ParseError)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
enum KeyFileParseError {
|
||||||
|
InvalidVersion,
|
||||||
|
UnsupportedVersion(OutOfBounds<u64>),
|
||||||
|
InvalidJsonFormat,
|
||||||
|
InvalidIdentifier,
|
||||||
|
NoCryptoSection,
|
||||||
|
Crypto(CryptoParseError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KeyFileContent {
|
||||||
|
/// new stored key file struct with encrypted message (cipher_text)
|
||||||
|
/// also contains password derivation function settings (PBKDF2/Scrypt)
|
||||||
|
/// to decrypt cipher_text given the password is provided
|
||||||
|
pub fn new(crypto: KeyFileCrypto) -> KeyFileContent {
|
||||||
|
KeyFileContent {
|
||||||
|
id: new_uuid(),
|
||||||
|
version: KeyFileVersion::V3(3),
|
||||||
|
crypto: crypto
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_json(json: &Json) -> Result<KeyFileContent, KeyFileParseError> {
|
||||||
|
let as_object = match json.as_object() {
|
||||||
|
None => { return Err(KeyFileParseError::InvalidJsonFormat); },
|
||||||
|
Some(obj) => obj
|
||||||
|
};
|
||||||
|
|
||||||
|
let version = match as_object["version"].as_u64() {
|
||||||
|
None => { return Err(KeyFileParseError::InvalidVersion); },
|
||||||
|
Some(json_version) => {
|
||||||
|
if json_version <= 2 {
|
||||||
|
return Err(KeyFileParseError::UnsupportedVersion(OutOfBounds { min: Some(3), max: None, found: json_version }))
|
||||||
|
};
|
||||||
|
KeyFileVersion::V3(json_version)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let id_text = try!(as_object.get("id").and_then(|json| json.as_string()).ok_or(KeyFileParseError::InvalidIdentifier));
|
||||||
|
let id = match uuid_from_string(&id_text) {
|
||||||
|
Err(_) => { return Err(KeyFileParseError::InvalidIdentifier); },
|
||||||
|
Ok(id) => id
|
||||||
|
};
|
||||||
|
|
||||||
|
let crypto = match as_object.get("crypto") {
|
||||||
|
None => { return Err(KeyFileParseError::NoCryptoSection); }
|
||||||
|
Some(crypto_json) => match KeyFileCrypto::from_json(crypto_json) {
|
||||||
|
Ok(crypto) => crypto,
|
||||||
|
Err(crypto_error) => { return Err(KeyFileParseError::Crypto(crypto_error)); }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(KeyFileContent {
|
||||||
|
version: version,
|
||||||
|
id: id.clone(),
|
||||||
|
crypto: crypto
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_json(&self) -> Json {
|
||||||
|
let mut map = BTreeMap::new();
|
||||||
|
map.insert("id".to_owned(), Json::String(uuid_to_string(&self.id)));
|
||||||
|
map.insert("version".to_owned(), Json::U64(CURRENT_DECLARED_VERSION));
|
||||||
|
map.insert("crypto".to_owned(), self.crypto.to_json());
|
||||||
|
|
||||||
|
Json::Object(map)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum KeyLoadError {
|
enum KeyLoadError {
|
||||||
NotFound,
|
|
||||||
InvalidEncoding,
|
InvalidEncoding,
|
||||||
FileTooLarge(OutOfBounds<u64>),
|
FileTooLarge(OutOfBounds<u64>),
|
||||||
FileParseError(KeyFileParseError),
|
FileParseError(KeyFileParseError),
|
||||||
FileReadError(::std::io::Error)
|
FileReadError(::std::io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// represents directory for saving/loading key files
|
||||||
|
pub struct KeyDirectory {
|
||||||
|
/// directory path for key management
|
||||||
|
path: String,
|
||||||
|
cache: HashMap<Uuid, KeyFileContent>,
|
||||||
|
cache_usage: VecDeque<Uuid>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KeyDirectory {
|
impl KeyDirectory {
|
||||||
fn key_path(&self, id: &Uuid) -> PathBuf {
|
/// Initializes new cache directory context with a given `path`
|
||||||
let mut path = self.path.to_path_buf();
|
pub fn new(path: &Path) -> KeyDirectory {
|
||||||
path.push(&id);
|
KeyDirectory {
|
||||||
path
|
cache: HashMap::new(),
|
||||||
|
path: path.to_str().expect("Initialized key directory with empty path").to_owned(),
|
||||||
|
cache_usage: VecDeque::new(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn save(&mut self, key_file: KeyFileContent) -> Result<(), ::std::io::Error> {
|
/// saves (inserts or updates) given key
|
||||||
|
pub fn save(&mut self, key_file: KeyFileContent) -> Result<(), ::std::io::Error> {
|
||||||
{
|
{
|
||||||
let mut file = try!(fs::File::create(self.key_path(&key_file.id)));
|
let mut file = try!(fs::File::create(self.key_path(&key_file.id)));
|
||||||
let json = key_file.to_json();
|
let json = key_file.to_json();
|
||||||
@ -272,28 +426,40 @@ impl KeyDirectory {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&mut self, id: &Uuid) -> Option<&KeyFileContent> {
|
/// returns key given by id if corresponding file exists and no load error occured
|
||||||
let path = {
|
/// warns if any error occured during the key loading
|
||||||
let mut path = self.path.to_path_buf();
|
pub fn get(&mut self, id: &Uuid) -> Option<&KeyFileContent> {
|
||||||
path.push(&id);
|
let path = self.key_path(id);
|
||||||
path
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(self.cache.entry(id.to_owned()).or_insert(
|
Some(self.cache.entry(id.to_owned()).or_insert(
|
||||||
match KeyDirectory::load_key(&path, id) {
|
match KeyDirectory::load_key(&path) {
|
||||||
Ok(loaded_key) => loaded_key,
|
Ok(loaded_key) => loaded_key,
|
||||||
Err(error) => { return None; }
|
Err(error) => {
|
||||||
|
warn!(target: "sstore", "error loading key {:?}: {:?}", id, error);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_key(path: &PathBuf, id: &Uuid) -> Result<KeyFileContent, KeyLoadError> {
|
/// returns current path to the directory with keys
|
||||||
|
pub fn path(&self) -> &str {
|
||||||
|
&self.path
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key_path(&self, id: &Uuid) -> PathBuf {
|
||||||
|
let mut path = PathBuf::new();
|
||||||
|
path.push(self.path.clone());
|
||||||
|
path.push(uuid_to_string(&id));
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_key(path: &PathBuf) -> Result<KeyFileContent, KeyLoadError> {
|
||||||
match fs::File::open(path.clone()) {
|
match fs::File::open(path.clone()) {
|
||||||
Ok(mut open_file) => {
|
Ok(mut open_file) => {
|
||||||
match open_file.metadata() {
|
match open_file.metadata() {
|
||||||
Ok(metadata) =>
|
Ok(metadata) =>
|
||||||
if metadata.len() > MAX_KEY_FILE_LEN { Err(KeyLoadError::FileTooLarge(OutOfBounds { min: Some(2), max: Some(MAX_KEY_FILE_LEN), found: metadata.len() })) }
|
if metadata.len() > MAX_KEY_FILE_LEN { Err(KeyLoadError::FileTooLarge(OutOfBounds { min: Some(2), max: Some(MAX_KEY_FILE_LEN), found: metadata.len() })) }
|
||||||
else { KeyDirectory::load_from_file(&mut open_file, metadata.len()) },
|
else { KeyDirectory::load_from_file(&mut open_file, metadata.len()) },
|
||||||
Err(read_error) => Err(KeyLoadError::FileReadError(read_error))
|
Err(read_error) => Err(KeyLoadError::FileReadError(read_error))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -315,90 +481,31 @@ impl KeyDirectory {
|
|||||||
Ok(key_file_content) => Ok(key_file_content),
|
Ok(key_file_content) => Ok(key_file_content),
|
||||||
Err(parse_error) => Err(KeyLoadError::FileParseError(parse_error))
|
Err(parse_error) => Err(KeyLoadError::FileParseError(parse_error))
|
||||||
},
|
},
|
||||||
Err(json_error) => Err(KeyLoadError::FileParseError(KeyFileParseError::InvalidJsonFormat))
|
Err(_) => Err(KeyLoadError::FileParseError(KeyFileParseError::InvalidJsonFormat))
|
||||||
},
|
},
|
||||||
Err(error) => Err(KeyLoadError::InvalidEncoding)
|
Err(_) => Err(KeyLoadError::InvalidEncoding)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum CryptoParseError {
|
|
||||||
NoCryptoVersion,
|
|
||||||
NoCipherText,
|
|
||||||
NoCipherType,
|
|
||||||
InvalidJsonFormat,
|
|
||||||
InvalidCryptoVersion,
|
|
||||||
InvalidKdfType(Mismatch<String>),
|
|
||||||
InvalidCipherType(Mismatch<String>),
|
|
||||||
NoInitialVector,
|
|
||||||
NoCipherParameters,
|
|
||||||
InvalidInitialVector(FromHexError),
|
|
||||||
NoKdfType,
|
|
||||||
NoKdfParams,
|
|
||||||
Scrypt(ScryptParseError),
|
|
||||||
KdfPbkdf2(Pbkdf2ParseError)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum KeyFileParseError {
|
|
||||||
InvalidVersion,
|
|
||||||
UnsupportedVersion(OutOfBounds<u64>),
|
|
||||||
InvalidJsonFormat,
|
|
||||||
InvalidIdentifier,
|
|
||||||
NoCryptoSection,
|
|
||||||
Crypto(CryptoParseError),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl KeyFileContent {
|
|
||||||
fn from_json(json: &Json) -> Result<KeyFileContent, KeyFileParseError> {
|
|
||||||
let as_object = match json.as_object() {
|
|
||||||
None => { return Err(KeyFileParseError::InvalidJsonFormat); },
|
|
||||||
Some(obj) => obj
|
|
||||||
};
|
|
||||||
|
|
||||||
let version = match as_object["version"].as_u64() {
|
|
||||||
None => { return Err(KeyFileParseError::InvalidVersion); },
|
|
||||||
Some(json_version) => {
|
|
||||||
if json_version <= 2 {
|
|
||||||
return Err(KeyFileParseError::UnsupportedVersion(OutOfBounds { min: Some(3), max: None, found: json_version }))
|
|
||||||
};
|
|
||||||
KeyFileVersion::V3(json_version)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let id = try!(as_object.get("id").and_then(|json| json.as_string()).ok_or(KeyFileParseError::InvalidIdentifier));
|
|
||||||
|
|
||||||
let crypto = match as_object.get("crypto") {
|
|
||||||
None => { return Err(KeyFileParseError::NoCryptoSection); }
|
|
||||||
Some(crypto_json) => match KeyFileCrypto::from_json(crypto_json) {
|
|
||||||
Ok(crypto) => crypto,
|
|
||||||
Err(crypto_error) => { return Err(KeyFileParseError::Crypto(crypto_error)); }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(KeyFileContent {
|
|
||||||
version: version,
|
|
||||||
id: id.to_owned(),
|
|
||||||
crypto: crypto
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn to_json(&self) -> Json {
|
|
||||||
let mut map = BTreeMap::new();
|
|
||||||
map.insert("id".to_owned(), Json::String(self.id.to_owned()));
|
|
||||||
map.insert("version".to_owned(), Json::U64(CURRENT_DECLARED_VERSION));
|
|
||||||
map.insert("crypto".to_owned(), self.crypto.to_json());
|
|
||||||
|
|
||||||
Json::Object(map)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{KeyFileContent, KeyFileVersion, KeyFileKdf, KeyFileParseError, CryptoParseError};
|
use super::{KeyFileContent, KeyFileVersion, KeyFileKdf, KeyFileParseError, CryptoParseError, uuid_from_string, uuid_to_string};
|
||||||
use common::*;
|
use common::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn uuid_parses() {
|
||||||
|
let uuid = uuid_from_string("3198bc9c-6672-5ab3-d995-4942343ae5b6").unwrap();
|
||||||
|
assert!(uuid > H128::zero());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn uuid_serializes() {
|
||||||
|
let uuid = uuid_from_string("3198bc9c-6fff-5ab3-d995-4942343ae5b6").unwrap();
|
||||||
|
assert_eq!(uuid_to_string(&uuid), "3198bc9c-6fff-5ab3-d995-4942343ae5b6");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_read_keyfile() {
|
fn can_read_keyfile() {
|
||||||
let json = Json::from_str(
|
let json = Json::from_str(
|
||||||
@ -461,7 +568,7 @@ mod tests {
|
|||||||
match KeyFileContent::from_json(&json) {
|
match KeyFileContent::from_json(&json) {
|
||||||
Ok(key_file) => {
|
Ok(key_file) => {
|
||||||
match key_file.crypto.kdf {
|
match key_file.crypto.kdf {
|
||||||
KeyFileKdf::Scrypt(scrypt_params) => {},
|
KeyFileKdf::Scrypt(_) => {},
|
||||||
_ => { panic!("expected kdf params of crypto to be of scrypt type" ); }
|
_ => { panic!("expected kdf params of crypto to be of scrypt type" ); }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -593,3 +700,19 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod specs {
|
||||||
|
use super::*;
|
||||||
|
use common::*;
|
||||||
|
use tests::helpers::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_initiate_key_directory() {
|
||||||
|
let temp_path = RandomTempPath::create_dir();
|
||||||
|
|
||||||
|
let directory = KeyDirectory::new(&temp_path.as_path());
|
||||||
|
|
||||||
|
assert!(directory.path().len() > 0);
|
||||||
|
}
|
||||||
|
}
|
@ -101,6 +101,7 @@ pub mod spec;
|
|||||||
pub mod transaction;
|
pub mod transaction;
|
||||||
pub mod views;
|
pub mod views;
|
||||||
pub mod receipt;
|
pub mod receipt;
|
||||||
|
pub mod keys_directory;
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
mod basic_types;
|
mod basic_types;
|
||||||
@ -123,7 +124,6 @@ mod substate;
|
|||||||
mod executive;
|
mod executive;
|
||||||
mod externalities;
|
mod externalities;
|
||||||
mod verification;
|
mod verification;
|
||||||
mod secret_store;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
@ -46,6 +46,15 @@ impl RandomTempPath {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_dir() -> RandomTempPath {
|
||||||
|
let mut dir = env::temp_dir();
|
||||||
|
dir.push(H32::random().hex());
|
||||||
|
fs::create_dir_all(dir.as_path()).unwrap();
|
||||||
|
RandomTempPath {
|
||||||
|
path: dir.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn as_path(&self) -> &PathBuf {
|
pub fn as_path(&self) -> &PathBuf {
|
||||||
&self.path
|
&self.path
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user