keyforkd: split into enum based request
This commit is contained in:
parent
48e4d7096c
commit
ada6cf150b
|
@ -1103,6 +1103,7 @@ dependencies = [
|
||||||
"keyfork-frame",
|
"keyfork-frame",
|
||||||
"keyfork-mnemonic-util",
|
"keyfork-mnemonic-util",
|
||||||
"keyfork-slip10-test-data",
|
"keyfork-slip10-test-data",
|
||||||
|
"keyforkd-models",
|
||||||
"serde",
|
"serde",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
@ -1121,11 +1122,21 @@ dependencies = [
|
||||||
"keyfork-frame",
|
"keyfork-frame",
|
||||||
"keyfork-slip10-test-data",
|
"keyfork-slip10-test-data",
|
||||||
"keyforkd",
|
"keyforkd",
|
||||||
|
"keyforkd-models",
|
||||||
"tempdir",
|
"tempdir",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "keyforkd-models"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"keyfork-derive-util",
|
||||||
|
"serde",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lalrpop"
|
name = "lalrpop"
|
||||||
version = "0.20.0"
|
version = "0.20.0"
|
||||||
|
@ -1944,18 +1955,18 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.188"
|
version = "1.0.190"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
|
checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.188"
|
version = "1.0.190"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
|
checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
|
@ -15,5 +15,6 @@ members = [
|
||||||
"keyfork-slip10-test-data",
|
"keyfork-slip10-test-data",
|
||||||
"keyforkd",
|
"keyforkd",
|
||||||
"keyforkd-client",
|
"keyforkd-client",
|
||||||
|
"keyforkd-models",
|
||||||
"smex",
|
"smex",
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{env, process::ExitCode, str::FromStr};
|
use std::{env, process::ExitCode, str::FromStr};
|
||||||
|
|
||||||
use keyfork_derive_util::{
|
use keyfork_derive_util::{
|
||||||
request::{DerivationAlgorithm, DerivationError, DerivationRequest},
|
request::{DerivationAlgorithm, DerivationError, DerivationRequest, DerivationResponse},
|
||||||
DerivationPath,
|
DerivationPath,
|
||||||
};
|
};
|
||||||
use keyforkd_client::Client;
|
use keyforkd_client::Client;
|
||||||
|
@ -38,8 +38,8 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
|
||||||
let mut client = Client::discover_socket()?;
|
let mut client = Client::discover_socket()?;
|
||||||
let request = DerivationRequest::new(algo, &path);
|
let request = DerivationRequest::new(algo, &path);
|
||||||
let response = client.request(&request)?;
|
let response = client.request(&request.into())?;
|
||||||
println!("{}", smex::encode(&response.data));
|
println!("{}", smex::encode(&DerivationResponse::try_from(response)?.data));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{env, process::ExitCode, str::FromStr};
|
use std::{env, process::ExitCode, str::FromStr};
|
||||||
|
|
||||||
use keyfork_derive_util::{
|
use keyfork_derive_util::{
|
||||||
request::{DerivationAlgorithm, DerivationRequest},
|
request::{DerivationAlgorithm, DerivationRequest, DerivationResponse},
|
||||||
DerivationIndex, DerivationPath,
|
DerivationIndex, DerivationPath,
|
||||||
};
|
};
|
||||||
use keyforkd_client::Client;
|
use keyforkd_client::Client;
|
||||||
|
@ -107,7 +107,9 @@ fn run() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
};
|
};
|
||||||
|
|
||||||
let request = DerivationRequest::new(DerivationAlgorithm::Ed25519, &path);
|
let request = DerivationRequest::new(DerivationAlgorithm::Ed25519, &path);
|
||||||
let derived_data = Client::discover_socket()?.request(&request)?;
|
let derived_data: DerivationResponse = Client::discover_socket()?
|
||||||
|
.request(&request.into())?
|
||||||
|
.try_into()?;
|
||||||
let subkeys = subkey_format
|
let subkeys = subkey_format
|
||||||
.iter()
|
.iter()
|
||||||
.map(|kt| kt.inner().clone())
|
.map(|kt| kt.inner().clone())
|
||||||
|
|
|
@ -14,6 +14,7 @@ secp256k1 = ["keyfork-derive-util/secp256k1"]
|
||||||
bincode = "1.3.3"
|
bincode = "1.3.3"
|
||||||
keyfork-derive-util = { version = "0.1.0", path = "../keyfork-derive-util", default-features = false }
|
keyfork-derive-util = { version = "0.1.0", path = "../keyfork-derive-util", default-features = false }
|
||||||
keyfork-frame = { version = "0.1.0", path = "../keyfork-frame" }
|
keyfork-frame = { version = "0.1.0", path = "../keyfork-frame" }
|
||||||
|
keyforkd-models = { version = "0.1.0", path = "../keyforkd-models" }
|
||||||
thiserror = "1.0.49"
|
thiserror = "1.0.49"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{collections::HashMap, os::unix::net::UnixStream, path::PathBuf};
|
use std::{collections::HashMap, os::unix::net::UnixStream, path::PathBuf};
|
||||||
|
|
||||||
use keyfork_derive_util::request::{DerivationRequest, DerivationResponse};
|
|
||||||
use keyfork_frame::{try_decode_from, try_encode_to, DecodeError, EncodeError};
|
use keyfork_frame::{try_decode_from, try_encode_to, DecodeError, EncodeError};
|
||||||
|
use keyforkd_models::{Request, Response /* Error as KeyforkdError */};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
@ -65,7 +65,7 @@ impl Client {
|
||||||
get_socket().map(|socket| Self { socket })
|
get_socket().map(|socket| Self { socket })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn request(&mut self, req: &DerivationRequest) -> Result<DerivationResponse> {
|
pub fn request(&mut self, req: &Request) -> Result<Response> {
|
||||||
try_encode_to(&bincode::serialize(&req)?, &mut self.socket)?;
|
try_encode_to(&bincode::serialize(&req)?, &mut self.socket)?;
|
||||||
let resp = try_decode_from(&mut self.socket)?;
|
let resp = try_decode_from(&mut self.socket)?;
|
||||||
bincode::deserialize(&resp).map_err(From::from)
|
bincode::deserialize(&resp).map_err(From::from)
|
||||||
|
|
|
@ -46,7 +46,8 @@ fn secp256k1() {
|
||||||
DerivationAlgorithm::Secp256k1,
|
DerivationAlgorithm::Secp256k1,
|
||||||
&DerivationPath::from_str(test.chain).unwrap(),
|
&DerivationPath::from_str(test.chain).unwrap(),
|
||||||
);
|
);
|
||||||
let response = client.request(&req).unwrap();
|
let response =
|
||||||
|
DerivationResponse::try_from(client.request(&req.into()).unwrap()).unwrap();
|
||||||
assert_eq!(response.data, test.private_key);
|
assert_eq!(response.data, test.private_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +91,8 @@ fn ed25519() {
|
||||||
DerivationAlgorithm::Ed25519,
|
DerivationAlgorithm::Ed25519,
|
||||||
&DerivationPath::from_str(test.chain).unwrap(),
|
&DerivationPath::from_str(test.chain).unwrap(),
|
||||||
);
|
);
|
||||||
let response = client.request(&req).unwrap();
|
let response =
|
||||||
|
DerivationResponse::try_from(client.request(&req.into()).unwrap()).unwrap();
|
||||||
assert_eq!(response.data, test.private_key);
|
assert_eq!(response.data, test.private_key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
name = "keyforkd-models"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
keyfork-derive-util = { version = "0.1.0", path = "../keyfork-derive-util", default-features = false }
|
||||||
|
serde = { version = "1.0.190", features = ["derive"] }
|
||||||
|
thiserror = "1.0.50"
|
|
@ -0,0 +1,84 @@
|
||||||
|
//! All values that can be sent to and returned from Keyforkd.
|
||||||
|
//!
|
||||||
|
//! All Error values are stored as enum unit values.
|
||||||
|
|
||||||
|
use keyfork_derive_util::request::{DerivationRequest, DerivationResponse};
|
||||||
|
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
/// A request made to Keyforkd.
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
pub enum Request {
|
||||||
|
/// A derivation request.
|
||||||
|
Derivation(DerivationRequest),
|
||||||
|
|
||||||
|
/// A derivation request, with a TTY provided for pinentry if necessary.
|
||||||
|
DerivationWithTTY(DerivationRequest, String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<DerivationRequest> for Request {
|
||||||
|
fn from(value: DerivationRequest) -> Self {
|
||||||
|
Self::Derivation(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(DerivationRequest, String)> for Request {
|
||||||
|
fn from((request, tty): (DerivationRequest, String)) -> Self {
|
||||||
|
Self::DerivationWithTTY(request, tty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub enum DerivationError {
|
||||||
|
#[error("The provided TTY was not valid")]
|
||||||
|
InvalidTTY,
|
||||||
|
|
||||||
|
#[error("A TTY was required by the pinentry program but was not provided")]
|
||||||
|
NoTTY,
|
||||||
|
|
||||||
|
#[error("Invalid derivation length: Expected 2, actual: {0}")]
|
||||||
|
InvalidDerivationLength(usize),
|
||||||
|
|
||||||
|
#[error("Derivation error: {0}")]
|
||||||
|
Derivation(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error(transparent)]
|
||||||
|
Derivation(#[from] DerivationError),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Any response from a Keyforkd request.
|
||||||
|
///
|
||||||
|
/// Responses can be converted to their inner values without matching the Response type by
|
||||||
|
/// using a type annotation and [`TryInto::try_into`].
|
||||||
|
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum Response {
|
||||||
|
/// A derivation response.
|
||||||
|
///
|
||||||
|
/// From:
|
||||||
|
/// * [`Request::Derivation`]
|
||||||
|
/// * [`Request::DerivationWithTTY`]
|
||||||
|
Derivation(DerivationResponse),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(thiserror::Error, Debug)]
|
||||||
|
#[error("Unable to downcast to {0}")]
|
||||||
|
pub struct Downcast(&'static str);
|
||||||
|
|
||||||
|
use std::any::type_name;
|
||||||
|
|
||||||
|
impl TryFrom<Response> for DerivationResponse {
|
||||||
|
type Error = Downcast;
|
||||||
|
|
||||||
|
fn try_from(value: Response) -> Result<Self, Self::Error> {
|
||||||
|
#[allow(irrefutable_let_patterns)]
|
||||||
|
if let Response::Derivation(response) = value {
|
||||||
|
Ok(response)
|
||||||
|
} else {
|
||||||
|
Err(Downcast(type_name::<Self>()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,6 +29,7 @@ tower = { version = "0.4.13", features = ["tokio", "util"] }
|
||||||
thiserror = "1.0.47"
|
thiserror = "1.0.47"
|
||||||
serde = { version = "1.0.186", features = ["derive"] }
|
serde = { version = "1.0.186", features = ["derive"] }
|
||||||
keyfork-derive-path-data = { version = "0.1.0", path = "../keyfork-derive-path-data" }
|
keyfork-derive-path-data = { version = "0.1.0", path = "../keyfork-derive-path-data" }
|
||||||
|
keyforkd-models = { version = "0.1.0", path = "../keyforkd-models" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
hex-literal = "0.4.1"
|
hex-literal = "0.4.1"
|
||||||
|
|
|
@ -1,22 +1,14 @@
|
||||||
use std::{future::Future, pin::Pin, sync::Arc, task::Poll};
|
use std::{future::Future, pin::Pin, sync::Arc, task::Poll};
|
||||||
|
|
||||||
use keyfork_derive_path_data::guess_target;
|
use keyfork_derive_path_data::guess_target;
|
||||||
use keyfork_derive_util::request::{DerivationError, DerivationRequest, DerivationResponse};
|
// use keyfork_derive_util::request::{DerivationError, DerivationRequest, DerivationResponse};
|
||||||
|
use keyforkd_models::{DerivationError, Error, Request, Response};
|
||||||
use tower::Service;
|
use tower::Service;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
// NOTE: All values implemented in Keyforkd must implement Clone with low overhead, either by
|
// NOTE: All values implemented in Keyforkd must implement Clone with low overhead, either by
|
||||||
// using an Arc or by having a small signature. This is because Service<T> takes &mut self.
|
// using an Arc or by having a small signature. This is because Service<T> takes &mut self.
|
||||||
|
//
|
||||||
#[derive(thiserror::Error, Debug)]
|
|
||||||
pub enum KeyforkdRequestError {
|
|
||||||
#[error("Invalid derivation length: Expected: 2, actual: {0}")]
|
|
||||||
InvalidDerivationLength(usize),
|
|
||||||
|
|
||||||
#[error("Derivation error: {0}")]
|
|
||||||
Derivation(#[from] DerivationError),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Keyforkd {
|
pub struct Keyforkd {
|
||||||
seed: Arc<Vec<u8>>,
|
seed: Arc<Vec<u8>>,
|
||||||
|
@ -30,10 +22,11 @@ impl Keyforkd {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Service<DerivationRequest> for Keyforkd {
|
impl Service<Request> for Keyforkd {
|
||||||
type Response = DerivationResponse;
|
type Response = Response;
|
||||||
|
|
||||||
type Error = KeyforkdRequestError;
|
// TODO: indicate serialize in BincodeLayer
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
|
type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
|
||||||
|
|
||||||
|
@ -45,24 +38,28 @@ impl Service<DerivationRequest> for Keyforkd {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
|
#[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))]
|
||||||
fn call(&mut self, req: DerivationRequest) -> Self::Future {
|
fn call(&mut self, req: Request) -> Self::Future {
|
||||||
let seed = self.seed.clone();
|
let seed = self.seed.clone();
|
||||||
Box::pin(async move {
|
match req {
|
||||||
let len = req.path().len();
|
Request::Derivation(req) => Box::pin(async move {
|
||||||
if len < 2 {
|
let len = req.path().len();
|
||||||
return Err(KeyforkdRequestError::InvalidDerivationLength(len));
|
if len < 2 {
|
||||||
}
|
return Err(DerivationError::InvalidDerivationLength(len).into());
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "tracing")]
|
#[cfg(feature = "tracing")]
|
||||||
if let Some(target) = guess_target(req.path()) {
|
if let Some(target) = guess_target(req.path()) {
|
||||||
info!("Deriving path: {target}");
|
info!("Deriving path: {target}");
|
||||||
} else {
|
} else {
|
||||||
info!("Deriving path: {}", req.path());
|
info!("Deriving path: {}", req.path());
|
||||||
}
|
}
|
||||||
|
|
||||||
req.derive_with_master_seed((*seed).clone())
|
req.derive_with_master_seed((*seed).clone())
|
||||||
.map_err(KeyforkdRequestError::from)
|
.map(Response::Derivation)
|
||||||
})
|
.map_err(|e| DerivationError::Derivation(e.to_string()).into())
|
||||||
|
}),
|
||||||
|
Request::DerivationWithTTY(_, _) => todo!(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,7 +89,15 @@ mod tests {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let req = DerivationRequest::new(DerivationAlgorithm::Secp256k1, &chain);
|
let req = DerivationRequest::new(DerivationAlgorithm::Secp256k1, &chain);
|
||||||
let response = keyforkd.ready().await.unwrap().call(req).await.unwrap();
|
let response: DerivationResponse = keyforkd
|
||||||
|
.ready()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.call(Request::Derivation(req))
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
assert_eq!(response.data, test.private_key);
|
assert_eq!(response.data, test.private_key);
|
||||||
assert_eq!(response.chain_code.as_slice(), test.chain_code);
|
assert_eq!(response.chain_code.as_slice(), test.chain_code);
|
||||||
}
|
}
|
||||||
|
@ -114,7 +119,15 @@ mod tests {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let req = DerivationRequest::new(DerivationAlgorithm::Ed25519, &chain);
|
let req = DerivationRequest::new(DerivationAlgorithm::Ed25519, &chain);
|
||||||
let response = keyforkd.ready().await.unwrap().call(req).await.unwrap();
|
let response: DerivationResponse = keyforkd
|
||||||
|
.ready()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.call(Request::Derivation(req))
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
assert_eq!(response.data, test.private_key);
|
assert_eq!(response.data, test.private_key);
|
||||||
assert_eq!(response.chain_code.as_slice(), test.chain_code);
|
assert_eq!(response.chain_code.as_slice(), test.chain_code);
|
||||||
}
|
}
|
||||||
|
@ -134,7 +147,15 @@ mod tests {
|
||||||
for (seed, path, _, private_key, _) in tests {
|
for (seed, path, _, private_key, _) in tests {
|
||||||
let req = DerivationRequest::new(DerivationAlgorithm::Ed25519, &path);
|
let req = DerivationRequest::new(DerivationAlgorithm::Ed25519, &path);
|
||||||
let mut keyforkd = Keyforkd::new(seed.to_vec());
|
let mut keyforkd = Keyforkd::new(seed.to_vec());
|
||||||
let response = keyforkd.ready().await.unwrap().call(req).await.unwrap();
|
let response: DerivationResponse = keyforkd
|
||||||
|
.ready()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.call(Request::Derivation(req))
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
assert_eq!(response.data, private_key)
|
assert_eq!(response.data, private_key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,7 +173,15 @@ mod tests {
|
||||||
for (seed, path, _, private_key, _) in tests {
|
for (seed, path, _, private_key, _) in tests {
|
||||||
let req = DerivationRequest::new(DerivationAlgorithm::Ed25519, &path);
|
let req = DerivationRequest::new(DerivationAlgorithm::Ed25519, &path);
|
||||||
let mut keyforkd = Keyforkd::new(seed.to_vec());
|
let mut keyforkd = Keyforkd::new(seed.to_vec());
|
||||||
let response = keyforkd.ready().await.unwrap().call(req).await.unwrap();
|
let response: DerivationResponse = keyforkd
|
||||||
|
.ready()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.call(Request::Derivation(req))
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.try_into()
|
||||||
|
.unwrap();
|
||||||
assert_eq!(response.data, private_key)
|
assert_eq!(response.data, private_key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue