On-chain ACL checker for secretstore (#5015)
* ECDKG protocol prototype * added test for enc/dec math * get rid of decryption_session * added licenses * fix after merge * get rid of unused serde dependency * doc * decryption session [without commutative enc] * failed_dec_session * fixed tests * added commen * added more decryption session tests * helper to localize an issue * more computations to localize error * decryption_session::SessionParams * added tests for EC math to localize problem * secretstore network transport * encryption_session_works_over_network * network errors processing * connecting to KeyServer * licenses * get rid of debug println-s * fixed secretstore args * encryption results are stored in KS database * decryption protocol works over network * enc/dec Session traits * fixing warnings * fix after merge * on-chain ACL checker proto * fixed compilation * fixed compilation * finally fixed <odd>-of-N-scheme * temporary commented test * 1-of-N works in math * scheme 1-of-N works * updated AclStorage with real contract ABI * remove unnecessary unsafety * fixed grumbles * wakeup on access denied * fix after merge * fix after merge * moved contract to native-contracts lib
This commit is contained in:
parent
ee4f9da385
commit
abec06f50c
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -635,6 +635,8 @@ name = "ethcore-secretstore"
|
||||
version = "1.0.0"
|
||||
dependencies = [
|
||||
"byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethabi 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethcore 1.7.0",
|
||||
"ethcore-devtools 1.7.0",
|
||||
"ethcore-ipc 1.7.0",
|
||||
"ethcore-ipc-codegen 1.7.0",
|
||||
@ -646,6 +648,7 @@ dependencies = [
|
||||
"futures-cpupool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hyper 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"native-contracts 0.1.0",
|
||||
"parking_lot 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
|
@ -23,6 +23,7 @@ use std::io::Write;
|
||||
// TODO: `include!` these from files where they're pretty-printed?
|
||||
const REGISTRY_ABI: &'static str = r#"[{"constant":true,"inputs":[{"name":"_data","type":"address"}],"name":"canReverse","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"},{"name":"_value","type":"bytes32"}],"name":"setData","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"}],"name":"confirmReverse","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"reserve","outputs":[{"name":"success","type":"bool"}],"payable":true,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"}],"name":"drop","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_amount","type":"uint256"}],"name":"setFee","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_to","type":"address"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"}],"name":"getData","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"reserved","outputs":[{"name":"reserved","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"drain","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_who","type":"address"}],"name":"proposeReverse","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"hasReverse","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"fee","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"getOwner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_name","type":"bytes32"}],"name":"getReverse","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_data","type":"address"}],"name":"reverse","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"},{"name":"_value","type":"uint256"}],"name":"setUint","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"string"},{"name":"_who","type":"address"}],"name":"confirmReverseAs","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"removeReverse","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_name","type":"bytes32"},{"name":"_key","type":"string"},{"name":"_value","type":"address"}],"name":"setAddress","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"}]"#;
|
||||
const SERVICE_TRANSACTION_ABI: &'static str = r#"[{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setOwner","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"certify","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getAddress","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_who","type":"address"}],"name":"revoke","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"owner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"delegate","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"getUint","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_new","type":"address"}],"name":"setDelegate","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"}],"name":"certified","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_who","type":"address"},{"name":"_field","type":"string"}],"name":"get","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"}]"#;
|
||||
const SECRETSTORE_ACL_STORAGE_ABI: &'static str = r#"[{"constant":true,"inputs":[{"name":"user","type":"address"},{"name":"document","type":"bytes32"}],"name":"checkPermissions","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"}]"#;
|
||||
|
||||
fn build_file(name: &str, abi: &str, filename: &str) {
|
||||
let code = ::native_contract_generator::generate_module(name, abi).unwrap();
|
||||
@ -37,4 +38,5 @@ fn build_file(name: &str, abi: &str, filename: &str) {
|
||||
fn main() {
|
||||
build_file("Registry", REGISTRY_ABI, "registry.rs");
|
||||
build_file("ServiceTransactionChecker", SERVICE_TRANSACTION_ABI, "service_transaction.rs");
|
||||
build_file("SecretStoreAclStorage", SECRETSTORE_ACL_STORAGE_ABI, "secretstore_acl_storage.rs");
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ extern crate ethcore_util as util;
|
||||
|
||||
mod registry;
|
||||
mod service_transaction;
|
||||
mod secretstore_acl_storage;
|
||||
|
||||
pub use self::registry::Registry;
|
||||
pub use self::service_transaction::ServiceTransactionChecker;
|
||||
pub use self::secretstore_acl_storage::SecretStoreAclStorage;
|
||||
|
22
ethcore/native_contracts/src/secretstore_acl_storage.rs
Normal file
22
ethcore/native_contracts/src/secretstore_acl_storage.rs
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2015-2017 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/>.
|
||||
|
||||
#![allow(unused_mut, unused_variables, unused_imports)]
|
||||
|
||||
//! Secret store ACL storage contract.
|
||||
// TODO: testing.
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/secretstore_acl_storage.rs"));
|
@ -463,7 +463,9 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
|
||||
let signer_server = signer::start(cmd.signer_conf.clone(), signer_deps)?;
|
||||
|
||||
// secret store key server
|
||||
let secretstore_deps = secretstore::Dependencies { };
|
||||
let secretstore_deps = secretstore::Dependencies {
|
||||
client: client.clone(),
|
||||
};
|
||||
let secretstore_key_server = secretstore::start(cmd.secretstore_conf.clone(), secretstore_deps);
|
||||
|
||||
// the ipfs server
|
||||
|
@ -14,7 +14,9 @@
|
||||
// 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::sync::Arc;
|
||||
use dir::default_data_path;
|
||||
use ethcore::client::Client;
|
||||
use helpers::replace_home;
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
@ -30,10 +32,10 @@ pub struct Configuration {
|
||||
pub data_path: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
/// Secret store dependencies
|
||||
pub struct Dependencies {
|
||||
// the only dependency will be BlockChainClient
|
||||
/// Blockchain client.
|
||||
pub client: Arc<Client>,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "secretstore"))]
|
||||
@ -64,7 +66,7 @@ mod server {
|
||||
|
||||
impl KeyServer {
|
||||
/// Create new key server
|
||||
pub fn new(conf: Configuration, _deps: Dependencies) -> Result<Self, String> {
|
||||
pub fn new(conf: Configuration, deps: Dependencies) -> Result<Self, String> {
|
||||
let key_pairs = vec![
|
||||
ethkey::KeyPair::from_secret("6c26a76e9b31048d170873a791401c7e799a11f0cefc0171cc31a49800967509".parse().unwrap()).unwrap(),
|
||||
ethkey::KeyPair::from_secret("7e94018b3731afdb3b4e6f4c3e179475640166da12e1d1b0c7d80729b1a5b452".parse().unwrap()).unwrap(),
|
||||
@ -96,7 +98,7 @@ mod server {
|
||||
}
|
||||
};
|
||||
|
||||
let key_server = ethcore_secretstore::start(conf)
|
||||
let key_server = ethcore_secretstore::start(deps.client, conf)
|
||||
.map_err(Into::<String>::into)?;
|
||||
|
||||
Ok(KeyServer {
|
||||
|
@ -24,12 +24,15 @@ tokio-core = "0.1"
|
||||
tokio-service = "0.1"
|
||||
tokio-proto = "0.1"
|
||||
url = "1.0"
|
||||
ethabi = "1.0.0"
|
||||
ethcore = { path = "../ethcore" }
|
||||
ethcore-devtools = { path = "../devtools" }
|
||||
ethcore-util = { path = "../util" }
|
||||
ethcore-ipc = { path = "../ipc/rpc" }
|
||||
ethcore-ipc-nano = { path = "../ipc/nano" }
|
||||
ethcrypto = { path = "../ethcrypto" }
|
||||
ethkey = { path = "../ethkey" }
|
||||
native-contracts = { path = "../ethcore/native_contracts" }
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
||||
|
@ -14,18 +14,71 @@
|
||||
// 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::collections::{HashMap, HashSet};
|
||||
use parking_lot::RwLock;
|
||||
use std::sync::Arc;
|
||||
use futures::{future, Future};
|
||||
use parking_lot::Mutex;
|
||||
use ethkey::public_to_address;
|
||||
use ethcore::client::{Client, BlockChainClient, BlockId};
|
||||
use native_contracts::SecretStoreAclStorage;
|
||||
use types::all::{Error, DocumentAddress, Public};
|
||||
|
||||
const ACL_CHECKER_CONTRACT_REGISTRY_NAME: &'static str = "secretstore_acl_checker";
|
||||
|
||||
/// ACL storage of Secret Store
|
||||
pub trait AclStorage: Send + Sync {
|
||||
/// Check if requestor with `public` key can access document with hash `document`
|
||||
fn check(&self, public: &Public, document: &DocumentAddress) -> Result<bool, Error>;
|
||||
}
|
||||
|
||||
/// Dummy ACL storage implementation
|
||||
/// On-chain ACL storage implementation.
|
||||
pub struct OnChainAclStorage {
|
||||
/// Blockchain client.
|
||||
client: Arc<Client>,
|
||||
/// On-chain contract.
|
||||
contract: Mutex<Option<SecretStoreAclStorage>>,
|
||||
}
|
||||
|
||||
impl OnChainAclStorage {
|
||||
pub fn new(client: Arc<Client>) -> Self {
|
||||
OnChainAclStorage {
|
||||
client: client,
|
||||
contract: Mutex::new(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AclStorage for OnChainAclStorage {
|
||||
fn check(&self, public: &Public, document: &DocumentAddress) -> Result<bool, Error> {
|
||||
let mut contract = self.contract.lock();
|
||||
if !contract.is_some() {
|
||||
*contract = self.client.registry_address(ACL_CHECKER_CONTRACT_REGISTRY_NAME.to_owned())
|
||||
.and_then(|contract_addr| {
|
||||
trace!(target: "secretstore", "Configuring for ACL checker contract from {}", contract_addr);
|
||||
|
||||
Some(SecretStoreAclStorage::new(contract_addr))
|
||||
})
|
||||
}
|
||||
if let Some(ref contract) = *contract {
|
||||
let address = public_to_address(&public);
|
||||
let do_call = |a, d| future::done(self.client.call_contract(BlockId::Latest, a, d));
|
||||
contract.check_permissions(do_call, address, document.clone())
|
||||
.map_err(|err| Error::Internal(err))
|
||||
.wait()
|
||||
} else {
|
||||
Err(Error::Internal("ACL checker contract is not configured".to_owned()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use parking_lot::RwLock;
|
||||
use types::all::{Error, DocumentAddress, Public};
|
||||
use super::AclStorage;
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
/// Dummy ACL storage implementation
|
||||
pub struct DummyAclStorage {
|
||||
prohibited: RwLock<HashMap<Public, HashSet<DocumentAddress>>>,
|
||||
}
|
||||
@ -49,3 +102,4 @@ impl AclStorage for DummyAclStorage {
|
||||
.unwrap_or(true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ mod tests {
|
||||
use std::sync::Arc;
|
||||
use ethcrypto;
|
||||
use ethkey::{self, Random, Generator};
|
||||
use acl_storage::DummyAclStorage;
|
||||
use acl_storage::tests::DummyAclStorage;
|
||||
use key_storage::tests::DummyKeyStorage;
|
||||
use types::all::{ClusterConfiguration, NodeAddress, EncryptionConfiguration, DocumentEncryptedKey, DocumentKey};
|
||||
use super::super::{RequestSignature, DocumentAddress};
|
||||
|
@ -220,7 +220,7 @@ impl SessionImpl {
|
||||
self.completed.notify_all();
|
||||
},
|
||||
// we can not decrypt data
|
||||
SessionState::Failed => (),
|
||||
SessionState::Failed => self.completed.notify_all(),
|
||||
// cannot reach other states
|
||||
_ => unreachable!("process_initialization_response can change state to WaitingForPartialDecryption or Failed; checked that we are in WaitingForInitializationConfirm state above; qed"),
|
||||
}
|
||||
@ -285,7 +285,10 @@ impl SessionImpl {
|
||||
SessionState::WaitingForPartialDecryption =>
|
||||
SessionImpl::start_waiting_for_partial_decryption(self.node().clone(), self.id.clone(), self.access_key.clone(), &self.cluster, &self.encrypted_data, &mut *data),
|
||||
// we can not have enough nodes for decryption
|
||||
SessionState::Failed => Ok(()),
|
||||
SessionState::Failed => {
|
||||
self.completed.notify_all();
|
||||
Ok(())
|
||||
},
|
||||
// cannot reach other states
|
||||
_ => unreachable!("process_initialization_response can change state to WaitingForPartialDecryption or Failed; checked that we are in WaitingForInitializationConfirm state above; qed"),
|
||||
}
|
||||
@ -480,6 +483,7 @@ fn process_initialization_response(encrypted_data: &DocumentKeyShare, data: &mut
|
||||
|
||||
// check if we still can receive enough confirmations to do a decryption?
|
||||
if encrypted_data.id_numbers.len() - data.rejected_nodes.len() < encrypted_data.threshold + 1 {
|
||||
data.decrypted_secret = Some(Err(Error::AccessDenied));
|
||||
data.state = SessionState::Failed;
|
||||
}
|
||||
},
|
||||
@ -503,7 +507,7 @@ fn do_partial_decryption(node: &NodeId, _requestor_public: &Public, participants
|
||||
mod tests {
|
||||
use std::sync::Arc;
|
||||
use std::collections::BTreeMap;
|
||||
use super::super::super::acl_storage::DummyAclStorage;
|
||||
use super::super::super::acl_storage::tests::DummyAclStorage;
|
||||
use ethkey::{self, Random, Generator, Public, Secret};
|
||||
use key_server_cluster::{NodeId, DocumentKeyShare, SessionId, Error};
|
||||
use key_server_cluster::cluster::tests::DummyCluster;
|
||||
|
@ -21,7 +21,7 @@ use ethcrypto;
|
||||
use super::types::all::DocumentAddress;
|
||||
|
||||
pub use super::types::all::{NodeId, EncryptionConfiguration};
|
||||
pub use super::acl_storage::{AclStorage, DummyAclStorage};
|
||||
pub use super::acl_storage::AclStorage;
|
||||
pub use super::key_storage::{KeyStorage, DocumentKeyShare};
|
||||
pub use super::serialization::{SerializableSignature, SerializableH256, SerializableSecret, SerializablePublic};
|
||||
pub use self::cluster::{ClusterCore, ClusterConfiguration, ClusterClient};
|
||||
@ -30,6 +30,8 @@ pub use self::decryption_session::Session as DecryptionSession;
|
||||
|
||||
#[cfg(test)]
|
||||
pub use super::key_storage::tests::DummyKeyStorage;
|
||||
#[cfg(test)]
|
||||
pub use super::acl_storage::tests::DummyAclStorage;
|
||||
|
||||
pub type SessionId = DocumentAddress;
|
||||
|
||||
@ -72,6 +74,8 @@ pub enum Error {
|
||||
Serde(String),
|
||||
/// Key storage error.
|
||||
KeyStorage(String),
|
||||
/// Acl storage error.
|
||||
AccessDenied,
|
||||
}
|
||||
|
||||
impl From<ethkey::Error> for Error {
|
||||
@ -110,6 +114,7 @@ impl fmt::Display for Error {
|
||||
Error::Io(ref e) => write!(f, "i/o error {}", e),
|
||||
Error::Serde(ref e) => write!(f, "serde error {}", e),
|
||||
Error::KeyStorage(ref e) => write!(f, "key storage error {}", e),
|
||||
Error::AccessDenied => write!(f, "Access denied"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,11 +32,14 @@ extern crate tokio_service;
|
||||
extern crate tokio_proto;
|
||||
extern crate url;
|
||||
|
||||
extern crate ethabi;
|
||||
extern crate ethcore;
|
||||
extern crate ethcore_devtools as devtools;
|
||||
extern crate ethcore_util as util;
|
||||
extern crate ethcore_ipc as ipc;
|
||||
extern crate ethcrypto;
|
||||
extern crate ethkey;
|
||||
extern crate native_contracts;
|
||||
|
||||
mod key_server_cluster;
|
||||
mod types;
|
||||
@ -52,15 +55,18 @@ mod key_server;
|
||||
mod key_storage;
|
||||
mod serialization;
|
||||
|
||||
use std::sync::Arc;
|
||||
use ethcore::client::Client;
|
||||
|
||||
pub use types::all::{DocumentAddress, DocumentKey, DocumentEncryptedKey, RequestSignature, Public,
|
||||
Error, NodeAddress, ServiceConfiguration, ClusterConfiguration, EncryptionConfiguration};
|
||||
pub use traits::{KeyServer};
|
||||
|
||||
/// Start new key server instance
|
||||
pub fn start(config: ServiceConfiguration) -> Result<Box<KeyServer>, Error> {
|
||||
pub fn start(client: Arc<Client>, config: ServiceConfiguration) -> Result<Box<KeyServer>, Error> {
|
||||
use std::sync::Arc;
|
||||
|
||||
let acl_storage = Arc::new(acl_storage::DummyAclStorage::default());
|
||||
let acl_storage = Arc::new(acl_storage::OnChainAclStorage::new(client));
|
||||
let key_storage = Arc::new(key_storage::PersistentKeyStorage::new(&config)?);
|
||||
let key_server = key_server::KeyServerImpl::new(&config.cluster_config, acl_storage, key_storage)?;
|
||||
let listener = http_listener::KeyServerHttpListener::start(config, key_server)?;
|
||||
|
@ -119,7 +119,10 @@ impl From<ethkey::Error> for Error {
|
||||
|
||||
impl From<key_server_cluster::Error> for Error {
|
||||
fn from(err: key_server_cluster::Error) -> Self {
|
||||
Error::Internal(err.into())
|
||||
match err {
|
||||
key_server_cluster::Error::AccessDenied => Error::AccessDenied,
|
||||
_ => Error::Internal(err.into()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user