dry redis connections and use bearer tokens
This commit is contained in:
parent
94bc6fef8c
commit
2989b7e91c
21
Cargo.lock
generated
21
Cargo.lock
generated
@ -278,9 +278,9 @@ checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.53"
|
version = "0.1.57"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed6aa3524a2dfcf9fe180c51eae2b58738348d819517ceadf95789c51fff7600"
|
checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -386,6 +386,18 @@ dependencies = [
|
|||||||
"tower-service",
|
"tower-service",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "axum-auth"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f9770f9a9147b2324066609acb5495538cb25f973129663fba2658ba7ed69407"
|
||||||
|
dependencies = [
|
||||||
|
"async-trait",
|
||||||
|
"axum-core",
|
||||||
|
"base64 0.13.0",
|
||||||
|
"http",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "axum-client-ip"
|
name = "axum-client-ip"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@ -4344,9 +4356,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.83"
|
version = "1.0.85"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "38dd04e3c8279e75b31ef29dbdceebfe5ad89f4d0937213c53f7d49d01b3d5a7"
|
checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa 1.0.2",
|
"itoa 1.0.2",
|
||||||
"ryu",
|
"ryu",
|
||||||
@ -5521,6 +5533,7 @@ dependencies = [
|
|||||||
"arc-swap",
|
"arc-swap",
|
||||||
"argh",
|
"argh",
|
||||||
"axum",
|
"axum",
|
||||||
|
"axum-auth",
|
||||||
"axum-client-ip",
|
"axum-client-ip",
|
||||||
"axum-macros",
|
"axum-macros",
|
||||||
"counter",
|
"counter",
|
||||||
|
@ -20,6 +20,7 @@ anyhow = { version = "1.0.62", features = ["backtrace"] }
|
|||||||
arc-swap = "1.5.1"
|
arc-swap = "1.5.1"
|
||||||
argh = "0.1.8"
|
argh = "0.1.8"
|
||||||
axum = { version = "0.5.15", features = ["headers", "serde_json", "tokio-tungstenite", "ws"] }
|
axum = { version = "0.5.15", features = ["headers", "serde_json", "tokio-tungstenite", "ws"] }
|
||||||
|
axum-auth = "0.3.0"
|
||||||
axum-client-ip = "0.2.0"
|
axum-client-ip = "0.2.0"
|
||||||
axum-macros = "0.2.3"
|
axum-macros = "0.2.3"
|
||||||
counter = "0.5.6"
|
counter = "0.5.6"
|
||||||
@ -49,7 +50,7 @@ rustc-hash = "1.1.0"
|
|||||||
siwe = "0.4.1"
|
siwe = "0.4.1"
|
||||||
sea-orm = { version = "0.9.2", features = ["macros"] }
|
sea-orm = { version = "0.9.2", features = ["macros"] }
|
||||||
serde = { version = "1.0.144", features = [] }
|
serde = { version = "1.0.144", features = [] }
|
||||||
serde_json = { version = "1.0.83", default-features = false, features = ["alloc", "raw_value"] }
|
serde_json = { version = "1.0.85", default-features = false, features = ["alloc", "raw_value"] }
|
||||||
# TODO: make sure this time version matches siwe. PR to put this in their prelude
|
# TODO: make sure this time version matches siwe. PR to put this in their prelude
|
||||||
time = "0.3.13"
|
time = "0.3.13"
|
||||||
tokio = { version = "1.20.1", features = ["full", "tracing"] }
|
tokio = { version = "1.20.1", features = ["full", "tracing"] }
|
||||||
|
@ -15,6 +15,7 @@ use futures::stream::StreamExt;
|
|||||||
use futures::Future;
|
use futures::Future;
|
||||||
use migration::{Migrator, MigratorTrait};
|
use migration::{Migrator, MigratorTrait};
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
|
use redis_rate_limit::bb8::PooledConnection;
|
||||||
use redis_rate_limit::{
|
use redis_rate_limit::{
|
||||||
bb8::{self, ErrorSink},
|
bb8::{self, ErrorSink},
|
||||||
RedisConnectionManager, RedisErrorSink, RedisPool, RedisRateLimit,
|
RedisConnectionManager, RedisErrorSink, RedisPool, RedisRateLimit,
|
||||||
@ -158,6 +159,17 @@ impl fmt::Debug for Web3ProxyApp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Web3ProxyApp {
|
impl Web3ProxyApp {
|
||||||
|
pub async fn redis_conn(&self) -> anyhow::Result<PooledConnection<RedisConnectionManager>> {
|
||||||
|
match self.redis_pool.as_ref() {
|
||||||
|
None => Err(anyhow::anyhow!("no redis server configured")),
|
||||||
|
Some(redis_pool) => {
|
||||||
|
let redis_conn = redis_pool.get().await?;
|
||||||
|
|
||||||
|
Ok(redis_conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: should we just take the rpc config as the only arg instead?
|
// TODO: should we just take the rpc config as the only arg instead?
|
||||||
pub async fn spawn(
|
pub async fn spawn(
|
||||||
app_stats: AppStats,
|
app_stats: AppStats,
|
||||||
|
@ -15,6 +15,7 @@ use axum::{
|
|||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
Extension, Json,
|
Extension, Json,
|
||||||
};
|
};
|
||||||
|
use axum_auth::AuthBearer;
|
||||||
use axum_client_ip::ClientIp;
|
use axum_client_ip::ClientIp;
|
||||||
use axum_macros::debug_handler;
|
use axum_macros::debug_handler;
|
||||||
use entities::{user, user_keys};
|
use entities::{user, user_keys};
|
||||||
@ -48,7 +49,8 @@ pub async fn get_login(
|
|||||||
// create a message and save it in redis
|
// create a message and save it in redis
|
||||||
|
|
||||||
// TODO: how many seconds? get from config?
|
// TODO: how many seconds? get from config?
|
||||||
let expire_seconds: usize = 300;
|
// TODO: while developing, we put a giant number here
|
||||||
|
let expire_seconds: usize = 28800;
|
||||||
|
|
||||||
let nonce = Ulid::new();
|
let nonce = Ulid::new();
|
||||||
|
|
||||||
@ -78,21 +80,14 @@ pub async fn get_login(
|
|||||||
let session_key = format!("pending:{}", nonce);
|
let session_key = format!("pending:{}", nonce);
|
||||||
|
|
||||||
// TODO: if no redis server, store in local cache?
|
// TODO: if no redis server, store in local cache?
|
||||||
let mut redis_conn = app
|
|
||||||
.redis_pool
|
|
||||||
.as_ref()
|
|
||||||
.expect("login requires a redis server")
|
|
||||||
.get()
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
// the address isn't enough. we need to save the actual message so we can read the nonce
|
// the address isn't enough. we need to save the actual message so we can read the nonce
|
||||||
// TODO: what message format is the most efficient to store in redis? probably eip191_string
|
// TODO: what message format is the most efficient to store in redis? probably eip191_string
|
||||||
redis_conn
|
// we add 1 to expire_seconds just to be sure redis has the key for the full expiration_time
|
||||||
.set_ex(session_key, message.to_string(), expire_seconds)
|
app.redis_conn()
|
||||||
|
.await?
|
||||||
|
.set_ex(session_key, message.to_string(), expire_seconds + 1)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
drop(redis_conn);
|
|
||||||
|
|
||||||
// there are multiple ways to sign messages and not all wallets support them
|
// there are multiple ways to sign messages and not all wallets support them
|
||||||
let message_eip = params
|
let message_eip = params
|
||||||
.remove("message_eip")
|
.remove("message_eip")
|
||||||
@ -152,16 +147,8 @@ pub async fn post_login(
|
|||||||
let their_sig: [u8; 65] = payload.sig.as_ref().try_into().unwrap();
|
let their_sig: [u8; 65] = payload.sig.as_ref().try_into().unwrap();
|
||||||
|
|
||||||
// fetch the message we gave them from our redis
|
// fetch the message we gave them from our redis
|
||||||
let redis_pool = app
|
|
||||||
.redis_pool
|
|
||||||
.as_ref()
|
|
||||||
.expect("login requires a redis server");
|
|
||||||
|
|
||||||
let mut redis_conn = redis_pool.get().await.unwrap();
|
|
||||||
|
|
||||||
// TODO: use getdel
|
// TODO: use getdel
|
||||||
// TODO: do not unwrap. make this function return a FrontendResult
|
let our_msg: String = app.redis_conn().await?.get(&their_msg.nonce).await?;
|
||||||
let our_msg: String = redis_conn.get(&their_msg.nonce).await.unwrap();
|
|
||||||
|
|
||||||
let our_msg: siwe::Message = our_msg.parse().unwrap();
|
let our_msg: siwe::Message = our_msg.parse().unwrap();
|
||||||
|
|
||||||
@ -203,6 +190,7 @@ pub async fn post_login(
|
|||||||
// TODO: set a cookie?
|
// TODO: set a cookie?
|
||||||
|
|
||||||
// TODO: do not expose user ids
|
// TODO: do not expose user ids
|
||||||
|
// TODO: return an api key and a bearer token
|
||||||
(StatusCode::CREATED, Json(user)).into_response()
|
(StatusCode::CREATED, Json(user)).into_response()
|
||||||
*/
|
*/
|
||||||
} else {
|
} else {
|
||||||
@ -224,10 +212,12 @@ pub struct PostUser {
|
|||||||
pub async fn post_user(
|
pub async fn post_user(
|
||||||
Json(payload): Json<PostUser>,
|
Json(payload): Json<PostUser>,
|
||||||
Extension(app): Extension<Arc<Web3ProxyApp>>,
|
Extension(app): Extension<Arc<Web3ProxyApp>>,
|
||||||
ClientIp(ip): ClientIp,
|
AuthBearer(auth_token): AuthBearer,
|
||||||
) -> FrontendResult {
|
) -> FrontendResult {
|
||||||
todo!("finish post_user");
|
todo!("finish post_user");
|
||||||
|
|
||||||
|
// TODO: check the auth_token is valid for the user in PostUser
|
||||||
|
|
||||||
// let user = user::ActiveModel {
|
// let user = user::ActiveModel {
|
||||||
// address: sea_orm::Set(payload.address.to_fixed_bytes().into()),
|
// address: sea_orm::Set(payload.address.to_fixed_bytes().into()),
|
||||||
// email: sea_orm::Set(payload.email),
|
// email: sea_orm::Set(payload.email),
|
||||||
|
Loading…
Reference in New Issue
Block a user