diff --git a/redis-rate-limit/Cargo.toml b/redis-rate-limit/Cargo.toml index 990d8504..a07f481b 100644 --- a/redis-rate-limit/Cargo.toml +++ b/redis-rate-limit/Cargo.toml @@ -5,6 +5,6 @@ authors = ["Bryan Stitt "] edition = "2021" [dependencies] -anyhow = "1.0.61" +anyhow = "1.0.62" bb8-redis = "0.11.0" tracing = "0.1.36" diff --git a/web3_proxy/Cargo.toml b/web3_proxy/Cargo.toml index e0906859..6a744b31 100644 --- a/web3_proxy/Cargo.toml +++ b/web3_proxy/Cargo.toml @@ -16,12 +16,12 @@ entities = { path = "../entities" } migration = { path = "../migration" } redis-rate-limit = { path = "../redis-rate-limit" } -anyhow = { version = "1.0.61", features = ["backtrace"] } +anyhow = { version = "1.0.62", features = ["backtrace"] } arc-swap = "1.5.1" argh = "0.1.8" axum = { version = "0.5.15", features = ["headers", "serde_json", "tokio-tungstenite", "ws"] } axum-client-ip = "0.2.0" -axum-macros = "*" +axum-macros = "0.2.3" counter = "0.5.6" dashmap = "5.3.4" derive_more = "0.99.17" @@ -39,7 +39,7 @@ num = "0.4.0" parking_lot = { version = "0.12.1", features = ["arc_lock"] } petgraph = "0.6.2" proctitle = "0.1.1" -prometheus-client = "0.17.0" +prometheus-client = "0.18.0" rand = "0.8.5" # TODO: regex has several "perf" features that we might want to use regex = "1.6.0" @@ -51,7 +51,7 @@ sea-orm = { version = "0.9.1", features = ["macros"] } serde = { version = "1.0.143", features = [] } serde_json = { version = "1.0.83", default-features = false, features = ["alloc", "raw_value"] } # TODO: make sure this time version matches siwe. PR to put this in their prelude -time = "0.3.11" +time = "0.3.13" tokio = { version = "1.20.1", features = ["full", "tracing"] } # TODO: make sure this uuid version matches sea-orm. PR to put this in their prelude tokio-stream = { version = "0.1.9", features = ["sync"] } diff --git a/web3_proxy/src/frontend/mod.rs b/web3_proxy/src/frontend/mod.rs index a541935f..105fffda 100644 --- a/web3_proxy/src/frontend/mod.rs +++ b/web3_proxy/src/frontend/mod.rs @@ -34,7 +34,9 @@ async fn handle_anyhow_error(err: anyhow::Error) -> (StatusCode, String) { /// http and websocket frontend for customers pub async fn serve(port: u16, proxy_app: Arc) -> anyhow::Result<()> { - // create a tracing span for each request + // create a tracing span for each request with a random request id and the method + // GET: websocket or static pages + // POST: http rpc or login let request_tracing_layer = TraceLayer::new_for_http().make_span_with(|request: &Request| { // We get the request id from the extensions @@ -70,6 +72,7 @@ pub async fn serve(port: u16, proxy_app: Arc) -> anyhow::Result<() .route("/health", get(http::health)) .route("/status", get(http::status)) .route("/login/:user_address", get(users::get_login)) + .route("/login/:user_address/:message_eip", get(users::get_login)) .route("/users", post(users::create_user)) // .route( // "/foo", diff --git a/web3_proxy/src/frontend/users.rs b/web3_proxy/src/frontend/users.rs index 793365dc..7552a64d 100644 --- a/web3_proxy/src/frontend/users.rs +++ b/web3_proxy/src/frontend/users.rs @@ -21,6 +21,7 @@ use axum_client_ip::ClientIp; use axum_macros::debug_handler; use entities::{user, user_keys}; use ethers::{prelude::Address, types::Bytes}; +use hashbrown::HashMap; use redis_rate_limit::redis::AsyncCommands; use reqwest::StatusCode; use sea_orm::ActiveModelTrait; @@ -38,7 +39,7 @@ pub async fn get_login( ClientIp(ip): ClientIp, // TODO: what does axum's error handling look like if the path fails to parse? // TODO: allow ENS names here? - Path(user_address): Path
, + Path(mut params): Path>, ) -> FrontendResult { // TODO: refactor this to use the try operator let _ip = match app.rate_limit_by_ip(ip).await { @@ -65,7 +66,8 @@ pub async fn get_login( let expiration_time = issued_at.add(Duration::new(expire_seconds as i64, 0)); - // TODO: get request_id out of the trace? do we need that when we have a none? + // TODO: proper errors. the first unwrap should be impossible, but the second will happen with bad input + let user_address: Address = params.remove("user_address").unwrap().parse().unwrap(); // TODO: get most of these from the app config let message = Message { @@ -98,7 +100,20 @@ pub async fn get_login( .set_ex(session_key, message.to_string(), expire_seconds) .await?; - Ok(message.to_string().into_response()) + // there are multiple ways to sign messages and not all wallets support them + let message_eip = params + .remove("message_eip") + .unwrap_or_else(|| "eip4361".to_string()); + + let message: String = match message_eip.as_str() { + "eip4361" => message.to_string(), + // https://github.com/spruceid/siwe/issues/98 + "eip191_string" => Bytes::from(message.eip191_string().unwrap()).to_string(), + "eip191_hash" => Bytes::from(&message.eip191_hash().unwrap()).to_string(), + _ => todo!("return a proper error"), + }; + + Ok(message.into_response()) } #[debug_handler]