server: misc cleanups (#407)
This commit is contained in:
parent
3385036c50
commit
d7b6ab7644
|
@ -70,7 +70,7 @@ pub struct Args {
|
|||
|
||||
/// Port to bind to, if using socket comms.
|
||||
/// Port to connect to, if using HTTP mode.
|
||||
#[arg(short, long, default_value_t = 2744)]
|
||||
#[arg(short, long, default_value_t = 443)]
|
||||
pub port: u16,
|
||||
}
|
||||
|
||||
|
|
|
@ -267,7 +267,6 @@ pub struct HTTPComms<C: Ciphersuite> {
|
|||
host_port: String,
|
||||
session_id: Option<Uuid>,
|
||||
access_token: Option<String>,
|
||||
num_signers: u16,
|
||||
args: ProcessedArgs<C>,
|
||||
state: SessionState<C>,
|
||||
pubkeys: HashMap<Vec<u8>, Identifier<C>>,
|
||||
|
@ -286,7 +285,6 @@ impl<C: Ciphersuite> HTTPComms<C> {
|
|||
host_port: format!("https://{}:{}", args.ip, args.port),
|
||||
session_id: None,
|
||||
access_token: None,
|
||||
num_signers: 0,
|
||||
args: args.clone(),
|
||||
state: SessionState::new(args.messages.len(), args.num_signers as usize),
|
||||
pubkeys: Default::default(),
|
||||
|
@ -340,7 +338,7 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
|
|||
_input: &mut dyn BufRead,
|
||||
_output: &mut dyn Write,
|
||||
_pub_key_package: &PublicKeyPackage<C>,
|
||||
num_signers: u16,
|
||||
_num_signers: u16,
|
||||
) -> Result<BTreeMap<Identifier<C>, SigningCommitments<C>>, Box<dyn Error>> {
|
||||
let mut rng = thread_rng();
|
||||
let challenge = self
|
||||
|
@ -368,7 +366,7 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
|
|||
self.client
|
||||
.post(format!("{}/login", self.host_port))
|
||||
.json(&server::KeyLoginArgs {
|
||||
uuid: challenge,
|
||||
challenge,
|
||||
pubkey: self
|
||||
.args
|
||||
.comm_pubkey
|
||||
|
@ -390,7 +388,6 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
|
|||
.bearer_auth(self.access_token.as_ref().expect("was just set"))
|
||||
.json(&server::CreateNewSessionArgs {
|
||||
pubkeys: self.args.signers.iter().cloned().map(PublicKey).collect(),
|
||||
num_signers,
|
||||
message_count: 1,
|
||||
})
|
||||
.send()
|
||||
|
@ -405,7 +402,6 @@ impl<C: Ciphersuite + 'static> Comms<C> for HTTPComms<C> {
|
|||
);
|
||||
}
|
||||
self.session_id = Some(r.session_id);
|
||||
self.num_signers = num_signers;
|
||||
|
||||
let (Some(comm_privkey), Some(comm_participant_pubkey_getter)) = (
|
||||
&self.args.comm_privkey,
|
||||
|
|
|
@ -66,7 +66,7 @@ pub(crate) async fn list(args: &Command) -> Result<(), Box<dyn Error>> {
|
|||
let access_token = client
|
||||
.post(format!("{}/login", host_port))
|
||||
.json(&server::KeyLoginArgs {
|
||||
uuid: challenge,
|
||||
challenge,
|
||||
pubkey: comm_pubkey.clone(),
|
||||
signature: signature.to_vec(),
|
||||
})
|
||||
|
@ -102,7 +102,7 @@ pub(crate) async fn list(args: &Command) -> Result<(), Box<dyn Error>> {
|
|||
let participants: Vec<_> = r
|
||||
.pubkeys
|
||||
.iter()
|
||||
.map(|pubkey| config.contact_by_pubkey(pubkey))
|
||||
.map(|pubkey| config.contact_by_pubkey(&pubkey.0))
|
||||
.collect();
|
||||
eprintln!("Session with ID {}", session_id);
|
||||
eprintln!(
|
||||
|
|
|
@ -37,7 +37,7 @@ pub struct Args {
|
|||
pub ip: String,
|
||||
|
||||
/// Port to connect to, if using online comms
|
||||
#[arg(short, long, default_value_t = 2744)]
|
||||
#[arg(short, long, default_value_t = 443)]
|
||||
pub port: u16,
|
||||
|
||||
/// Optional Session ID
|
||||
|
|
|
@ -203,7 +203,7 @@ where
|
|||
self.client
|
||||
.post(format!("{}/login", self.host_port))
|
||||
.json(&server::KeyLoginArgs {
|
||||
uuid: challenge,
|
||||
challenge,
|
||||
pubkey: self
|
||||
.args
|
||||
.comm_pubkey
|
||||
|
|
|
@ -16,6 +16,7 @@ derivative = "2.2.0"
|
|||
eyre = "0.6.11"
|
||||
frost-core = { version = "2.0.0", features = ["serde"] }
|
||||
frost-rerandomized = { version = "2.0.0-rc.0", features = ["serde"] }
|
||||
hex = "0.4"
|
||||
rand = "0.8"
|
||||
rcgen = "0.13.1"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
@ -32,7 +33,6 @@ xeddsa = "1.0.2"
|
|||
futures-util = "0.3.31"
|
||||
futures = "0.3.31"
|
||||
thiserror = "2.0.3"
|
||||
hex = "0.4.3"
|
||||
|
||||
[dev-dependencies]
|
||||
axum-test = "16.4.0"
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
# FROST Server
|
||||
|
||||
|
||||
This is a HTTP server that allow clients (Coordinator and Participants) to
|
||||
run FROST without needing to directly connect to one another.
|
||||
This is a JSON-HTTPS server that allow FROST clients (Coordinator and
|
||||
Participants) to run FROST without needing to directly connect to one another.
|
||||
|
||||
|
||||
## Status ⚠
|
||||
|
||||
This is a prototype which is NOT SECURE since messages are not encrypted nor
|
||||
authenticated. DO NOT USE this for anything other than testing.
|
||||
This project has not being audited.
|
||||
|
||||
|
||||
## Usage
|
||||
|
@ -17,19 +15,14 @@ NOTE: This is for demo purposes only and should not be used in production.
|
|||
|
||||
You will need to have [Rust and Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html) installed.
|
||||
|
||||
To run:
|
||||
To compile and run:
|
||||
|
||||
1. Clone the repo. Run `git clone https://github.com/ZcashFoundation/frost-zcash-demo.git`
|
||||
2. Run `cargo install`
|
||||
3. Run `cargo run --bin server`
|
||||
2. Run `cargo build --release --bin server`
|
||||
3. Run `./target/release/server -h` to learn about the command line arguments.
|
||||
|
||||
You can specify the IP and port to bind to using `--ip` and `--port`, e.g.
|
||||
`cargo run --bin server -- --ip 127.0.0.1 --port 2744`.
|
||||
You will need to specify a TLS certificate and key with the `--tls-cert`
|
||||
and `--tls-key` arguments.
|
||||
|
||||
## TODO
|
||||
|
||||
- Add specific error codes
|
||||
- Remove frost-specific types (when data is encrypted)
|
||||
- Session timeouts
|
||||
- Encryption/authentication
|
||||
- DoS protections and other production-ready requirements
|
||||
-
|
||||
For more details on using and deploying, refer to the [ZF FROST
|
||||
Book](https://frost.zfnd.org/).
|
||||
|
|
|
@ -10,7 +10,7 @@ use crate::{
|
|||
};
|
||||
|
||||
/// Implement the challenge API.
|
||||
#[tracing::instrument(ret, err(Debug), skip(state, _args))]
|
||||
#[tracing::instrument(level = "debug", err(Debug), skip(state, _args))]
|
||||
pub(crate) async fn challenge(
|
||||
State(state): State<SharedState>,
|
||||
Json(_args): Json<ChallengeArgs>,
|
||||
|
@ -25,7 +25,7 @@ pub(crate) async fn challenge(
|
|||
}
|
||||
|
||||
/// Implement the key_login API.
|
||||
#[tracing::instrument(ret, err(Debug), skip(state, args))]
|
||||
#[tracing::instrument(level = "debug", err(Debug), skip(state, args))]
|
||||
pub(crate) async fn login(
|
||||
State(state): State<SharedState>,
|
||||
Json(args): Json<KeyLoginArgs>,
|
||||
|
@ -41,11 +41,11 @@ pub(crate) async fn login(
|
|||
let signature = TryInto::<[u8; 64]>::try_into(args.signature)
|
||||
.map_err(|_| AppError::InvalidArgument("signature".into()))?;
|
||||
pubkey
|
||||
.verify(args.uuid.as_bytes(), &signature)
|
||||
.verify(args.challenge.as_bytes(), &signature)
|
||||
.map_err(|_| AppError::Unauthorized)?;
|
||||
|
||||
let mut challenges = state.challenges.write().unwrap();
|
||||
if !challenges.remove(&args.uuid) {
|
||||
if !challenges.remove(&args.challenge) {
|
||||
return Err(AppError::Unauthorized);
|
||||
}
|
||||
drop(challenges);
|
||||
|
@ -61,7 +61,7 @@ pub(crate) async fn login(
|
|||
}
|
||||
|
||||
/// Implement the logout API.
|
||||
#[tracing::instrument(ret, err(Debug), skip(state, user))]
|
||||
#[tracing::instrument(level = "debug", ret, err(Debug), skip(state, user))]
|
||||
pub(crate) async fn logout(
|
||||
State(state): State<SharedState>,
|
||||
user: User,
|
||||
|
@ -75,7 +75,7 @@ pub(crate) async fn logout(
|
|||
}
|
||||
|
||||
/// Implement the create_new_session API.
|
||||
#[tracing::instrument(ret, err(Debug), skip(state, user))]
|
||||
#[tracing::instrument(level = "debug", ret, err(Debug), skip(state, user))]
|
||||
pub(crate) async fn create_new_session(
|
||||
State(state): State<SharedState>,
|
||||
user: User,
|
||||
|
@ -94,7 +94,7 @@ pub(crate) async fn create_new_session(
|
|||
// Save session ID in global state
|
||||
for pubkey in &args.pubkeys {
|
||||
sessions_by_pubkey
|
||||
.entry(pubkey.0.clone())
|
||||
.entry(pubkey.clone().0)
|
||||
.or_default()
|
||||
.insert(id);
|
||||
}
|
||||
|
@ -102,7 +102,6 @@ pub(crate) async fn create_new_session(
|
|||
let session = Session {
|
||||
pubkeys: args.pubkeys.into_iter().map(|p| p.0).collect(),
|
||||
coordinator_pubkey: user.pubkey,
|
||||
num_signers: args.num_signers,
|
||||
message_count: args.message_count,
|
||||
queue: Default::default(),
|
||||
};
|
||||
|
@ -114,7 +113,7 @@ pub(crate) async fn create_new_session(
|
|||
}
|
||||
|
||||
/// Implement the create_new_session API.
|
||||
#[tracing::instrument(ret, err(Debug), skip(state, user))]
|
||||
#[tracing::instrument(level = "debug", ret, err(Debug), skip(state, user))]
|
||||
pub(crate) async fn list_sessions(
|
||||
State(state): State<SharedState>,
|
||||
user: User,
|
||||
|
@ -130,7 +129,7 @@ pub(crate) async fn list_sessions(
|
|||
}
|
||||
|
||||
/// Implement the get_session_info API
|
||||
#[tracing::instrument(ret, err(Debug), skip(state, user))]
|
||||
#[tracing::instrument(level = "debug", ret, err(Debug), skip(state, user))]
|
||||
pub(crate) async fn get_session_info(
|
||||
State(state): State<SharedState>,
|
||||
user: User,
|
||||
|
@ -152,7 +151,6 @@ pub(crate) async fn get_session_info(
|
|||
.ok_or(AppError::SessionNotFound)?;
|
||||
|
||||
Ok(Json(GetSessionInfoOutput {
|
||||
num_signers: session.num_signers,
|
||||
message_count: session.message_count,
|
||||
pubkeys: session.pubkeys.iter().cloned().map(PublicKey).collect(),
|
||||
coordinator_pubkey: session.coordinator_pubkey.clone(),
|
||||
|
@ -161,7 +159,7 @@ pub(crate) async fn get_session_info(
|
|||
|
||||
/// Implement the send API
|
||||
// TODO: get identifier from channel rather from arguments
|
||||
#[tracing::instrument(ret, err(Debug), skip(state, user))]
|
||||
#[tracing::instrument(level = "debug", ret, err(Debug), skip(state, user))]
|
||||
pub(crate) async fn send(
|
||||
State(state): State<SharedState>,
|
||||
user: User,
|
||||
|
@ -197,7 +195,7 @@ pub(crate) async fn send(
|
|||
}
|
||||
|
||||
/// Implement the recv API
|
||||
#[tracing::instrument(ret, err(Debug), skip(state, user))]
|
||||
#[tracing::instrument(level = "debug", ret, err(Debug), skip(state, user))]
|
||||
pub(crate) async fn receive(
|
||||
State(state): State<SharedState>,
|
||||
user: User,
|
||||
|
@ -240,7 +238,7 @@ pub(crate) async fn receive(
|
|||
}
|
||||
|
||||
/// Implement the close_session API.
|
||||
#[tracing::instrument(ret, err(Debug), skip(state, user))]
|
||||
#[tracing::instrument(level = "debug", ret, err(Debug), skip(state, user))]
|
||||
pub(crate) async fn close_session(
|
||||
State(state): State<SharedState>,
|
||||
user: User,
|
||||
|
|
|
@ -49,9 +49,10 @@ pub async fn run(args: &Args) -> Result<(), Box<dyn std::error::Error>> {
|
|||
|
||||
if args.no_tls_very_insecure {
|
||||
tracing::warn!(
|
||||
"starting an INSECURE HTTP server. This should be done only for \
|
||||
testing or if you are providing TLS/HTTPS with a separate \
|
||||
mechanism (e.g. reverse proxy such as nginx)"
|
||||
"starting an INSECURE HTTP server at {}. This should be done only \
|
||||
for testing or if you are providing TLS/HTTPS with a separate \
|
||||
mechanism (e.g. reverse proxy such as nginx)",
|
||||
addr,
|
||||
);
|
||||
let listener = tokio::net::TcpListener::bind(addr).await?;
|
||||
Ok(axum::serve(listener, app).await?)
|
||||
|
|
|
@ -1,12 +1,20 @@
|
|||
use clap::Parser;
|
||||
use server::args::Args;
|
||||
use server::run;
|
||||
use tracing::level_filters::LevelFilter;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args = Args::parse();
|
||||
// initialize tracing
|
||||
tracing_subscriber::fmt::init();
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
EnvFilter::builder()
|
||||
.with_default_directive(LevelFilter::INFO.into())
|
||||
.from_env_lossy(),
|
||||
)
|
||||
.init();
|
||||
tracing::event!(tracing::Level::INFO, "server running");
|
||||
run(&args).await
|
||||
}
|
||||
|
|
|
@ -42,8 +42,6 @@ pub struct Session {
|
|||
pub(crate) pubkeys: Vec<Vec<u8>>,
|
||||
/// The public key of the coordinator
|
||||
pub(crate) coordinator_pubkey: Vec<u8>,
|
||||
/// The number of signers in the session.
|
||||
pub(crate) num_signers: u16,
|
||||
/// The number of messages being simultaneously signed.
|
||||
pub(crate) message_count: u8,
|
||||
/// The message queue.
|
||||
|
|
|
@ -32,7 +32,7 @@ pub struct ChallengeOutput {
|
|||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct KeyLoginArgs {
|
||||
pub uuid: Uuid,
|
||||
pub challenge: Uuid,
|
||||
#[serde(
|
||||
serialize_with = "serdect::slice::serialize_hex_lower_or_bin",
|
||||
deserialize_with = "serdect::slice::deserialize_hex_or_bin_vec"
|
||||
|
@ -64,7 +64,6 @@ pub struct LoginArgs {
|
|||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct CreateNewSessionArgs {
|
||||
pub pubkeys: Vec<PublicKey>,
|
||||
pub num_signers: u16,
|
||||
pub message_count: u8,
|
||||
}
|
||||
|
||||
|
@ -85,7 +84,6 @@ pub struct GetSessionInfoArgs {
|
|||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct GetSessionInfoOutput {
|
||||
pub num_signers: u16,
|
||||
pub message_count: u8,
|
||||
pub pubkeys: Vec<PublicKey>,
|
||||
pub coordinator_pubkey: Vec<u8>,
|
||||
|
|
|
@ -89,7 +89,7 @@ async fn test_main_router<
|
|||
let res = server
|
||||
.post("/login")
|
||||
.json(&server::KeyLoginArgs {
|
||||
uuid: alice_challenge,
|
||||
challenge: alice_challenge,
|
||||
pubkey: alice_keypair.public.clone(),
|
||||
signature: alice_signature.to_vec(),
|
||||
})
|
||||
|
@ -104,7 +104,7 @@ async fn test_main_router<
|
|||
let res = server
|
||||
.post("/login")
|
||||
.json(&server::KeyLoginArgs {
|
||||
uuid: bob_challenge,
|
||||
challenge: bob_challenge,
|
||||
pubkey: bob_keypair.public.clone(),
|
||||
signature: bob_signature.to_vec(),
|
||||
})
|
||||
|
@ -124,7 +124,6 @@ async fn test_main_router<
|
|||
server::PublicKey(alice_keypair.public.clone()),
|
||||
server::PublicKey(bob_keypair.public.clone()),
|
||||
],
|
||||
num_signers: 2,
|
||||
message_count: 2,
|
||||
})
|
||||
.await;
|
||||
|
@ -463,7 +462,7 @@ async fn test_http() -> Result<(), Box<dyn std::error::Error>> {
|
|||
let r = client
|
||||
.post("https://127.0.0.1:2744/login")
|
||||
.json(&server::KeyLoginArgs {
|
||||
uuid: alice_challenge,
|
||||
challenge: alice_challenge,
|
||||
pubkey: alice_keypair.public.clone(),
|
||||
signature: alice_signature.to_vec(),
|
||||
})
|
||||
|
@ -485,7 +484,6 @@ async fn test_http() -> Result<(), Box<dyn std::error::Error>> {
|
|||
server::PublicKey(bob_keypair.public.clone()),
|
||||
],
|
||||
message_count: 1,
|
||||
num_signers: 2,
|
||||
})
|
||||
.send()
|
||||
.await?;
|
||||
|
@ -528,7 +526,7 @@ async fn test_http() -> Result<(), Box<dyn std::error::Error>> {
|
|||
let r = client
|
||||
.post("https://127.0.0.1:2744/login")
|
||||
.json(&server::KeyLoginArgs {
|
||||
uuid: bob_challenge,
|
||||
challenge: bob_challenge,
|
||||
pubkey: bob_keypair.public.clone(),
|
||||
signature: bob_signature.to_vec(),
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue