less verbose db_conn and db_replica helpers
This commit is contained in:
parent
9115419ec0
commit
fef03f089f
|
@ -6,7 +6,7 @@ use tokio::time::{Duration, Instant};
|
||||||
pub use deadpool_redis::redis;
|
pub use deadpool_redis::redis;
|
||||||
pub use deadpool_redis::{
|
pub use deadpool_redis::{
|
||||||
Config as RedisConfig, Connection as RedisConnection, Manager as RedisManager,
|
Config as RedisConfig, Connection as RedisConnection, Manager as RedisManager,
|
||||||
Pool as RedisPool, Runtime as DeadpoolRuntime,
|
Pool as RedisPool, PoolError as RedisPoolError, Runtime as DeadpoolRuntime,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use crate::app::Web3ProxyApp;
|
use crate::app::Web3ProxyApp;
|
||||||
use crate::errors::{Web3ProxyError, Web3ProxyResponse};
|
use crate::errors::{Web3ProxyError, Web3ProxyResponse};
|
||||||
use crate::http_params::get_user_id_from_params;
|
use crate::http_params::get_user_id_from_params;
|
||||||
use anyhow::Context;
|
|
||||||
use axum::response::IntoResponse;
|
use axum::response::IntoResponse;
|
||||||
use axum::{
|
use axum::{
|
||||||
headers::{authorization::Bearer, Authorization},
|
headers::{authorization::Bearer, Authorization},
|
||||||
|
@ -43,17 +42,9 @@ pub async fn query_admin_modify_usertier<'a>(
|
||||||
let mut response_body = HashMap::new();
|
let mut response_body = HashMap::new();
|
||||||
|
|
||||||
// Establish connections
|
// Establish connections
|
||||||
let db_conn = app
|
let db_conn = app.db_conn()?;
|
||||||
.db_conn()
|
let db_replica = app.db_replica()?;
|
||||||
.context("query_admin_modify_user needs a db")?;
|
let mut redis_conn = app.redis_conn().await?;
|
||||||
let db_replica = app
|
|
||||||
.db_replica()
|
|
||||||
.context("query_user_stats needs a db replica")?;
|
|
||||||
let mut redis_conn = app
|
|
||||||
.redis_conn()
|
|
||||||
.await
|
|
||||||
.context("query_admin_modify_user had a redis connection error")?
|
|
||||||
.context("query_admin_modify_user needs a redis")?;
|
|
||||||
|
|
||||||
// Will modify logic here
|
// Will modify logic here
|
||||||
|
|
||||||
|
@ -61,14 +52,14 @@ pub async fn query_admin_modify_usertier<'a>(
|
||||||
// TODO: Make a single query, where you retrieve the user, and directly from it the secondary user (otherwise we do two jumpy, which is unnecessary)
|
// TODO: Make a single query, where you retrieve the user, and directly from it the secondary user (otherwise we do two jumpy, which is unnecessary)
|
||||||
// get the user id first. if it is 0, we should use a cache on the app
|
// get the user id first. if it is 0, we should use a cache on the app
|
||||||
let caller_id =
|
let caller_id =
|
||||||
get_user_id_from_params(&mut redis_conn, &db_conn, &db_replica, bearer, params).await?;
|
get_user_id_from_params(&mut redis_conn, db_conn, db_replica, bearer, params).await?;
|
||||||
|
|
||||||
trace!("Caller id is: {:?}", caller_id);
|
trace!("Caller id is: {:?}", caller_id);
|
||||||
|
|
||||||
// Check if the caller is an admin (i.e. if he is in an admin table)
|
// Check if the caller is an admin (i.e. if he is in an admin table)
|
||||||
let _admin: admin::Model = admin::Entity::find()
|
let _admin: admin::Model = admin::Entity::find()
|
||||||
.filter(admin::Column::UserId.eq(caller_id))
|
.filter(admin::Column::UserId.eq(caller_id))
|
||||||
.one(&db_conn)
|
.one(db_conn)
|
||||||
.await?
|
.await?
|
||||||
.ok_or(Web3ProxyError::AccessDenied)?;
|
.ok_or(Web3ProxyError::AccessDenied)?;
|
||||||
|
|
||||||
|
@ -77,7 +68,7 @@ pub async fn query_admin_modify_usertier<'a>(
|
||||||
// Fetch the admin, and the user
|
// Fetch the admin, and the user
|
||||||
let user: user::Model = user::Entity::find()
|
let user: user::Model = user::Entity::find()
|
||||||
.filter(user::Column::Address.eq(user_address.as_bytes()))
|
.filter(user::Column::Address.eq(user_address.as_bytes()))
|
||||||
.one(&db_conn)
|
.one(db_conn)
|
||||||
.await?
|
.await?
|
||||||
.ok_or(Web3ProxyError::BadRequest(
|
.ok_or(Web3ProxyError::BadRequest(
|
||||||
"No user with this id found".into(),
|
"No user with this id found".into(),
|
||||||
|
@ -91,7 +82,7 @@ pub async fn query_admin_modify_usertier<'a>(
|
||||||
// Now we can modify the user's tier
|
// Now we can modify the user's tier
|
||||||
let new_user_tier: user_tier::Model = user_tier::Entity::find()
|
let new_user_tier: user_tier::Model = user_tier::Entity::find()
|
||||||
.filter(user_tier::Column::Title.eq(user_tier_title.clone()))
|
.filter(user_tier::Column::Title.eq(user_tier_title.clone()))
|
||||||
.one(&db_conn)
|
.one(db_conn)
|
||||||
.await?
|
.await?
|
||||||
.ok_or(Web3ProxyError::BadRequest(
|
.ok_or(Web3ProxyError::BadRequest(
|
||||||
"User Tier name was not found".into(),
|
"User Tier name was not found".into(),
|
||||||
|
@ -104,7 +95,7 @@ pub async fn query_admin_modify_usertier<'a>(
|
||||||
|
|
||||||
user.user_tier_id = sea_orm::Set(new_user_tier.id);
|
user.user_tier_id = sea_orm::Set(new_user_tier.id);
|
||||||
|
|
||||||
user.save(&db_conn).await?;
|
user.save(db_conn).await?;
|
||||||
|
|
||||||
info!("user's tier changed");
|
info!("user's tier changed");
|
||||||
}
|
}
|
||||||
|
@ -112,7 +103,7 @@ pub async fn query_admin_modify_usertier<'a>(
|
||||||
// Now delete all bearer tokens of this user
|
// Now delete all bearer tokens of this user
|
||||||
login::Entity::delete_many()
|
login::Entity::delete_many()
|
||||||
.filter(login::Column::UserId.eq(user.id))
|
.filter(login::Column::UserId.eq(user.id))
|
||||||
.exec(&db_conn)
|
.exec(db_conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
Ok(Json(&response_body).into_response())
|
Ok(Json(&response_body).into_response())
|
||||||
|
|
|
@ -515,7 +515,7 @@ impl Web3ProxyApp {
|
||||||
Some(watch_consensus_head_sender),
|
Some(watch_consensus_head_sender),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.context("spawning balanced rpcs")?;
|
.web3_context("spawning balanced rpcs")?;
|
||||||
|
|
||||||
app_handles.push(balanced_handle);
|
app_handles.push(balanced_handle);
|
||||||
|
|
||||||
|
@ -546,7 +546,7 @@ impl Web3ProxyApp {
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.context("spawning private_rpcs")?;
|
.web3_context("spawning private_rpcs")?;
|
||||||
|
|
||||||
app_handles.push(private_handle);
|
app_handles.push(private_handle);
|
||||||
|
|
||||||
|
@ -573,7 +573,7 @@ impl Web3ProxyApp {
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.context("spawning bundler_4337_rpcs")?;
|
.web3_context("spawning bundler_4337_rpcs")?;
|
||||||
|
|
||||||
app_handles.push(bundler_4337_rpcs_handle);
|
app_handles.push(bundler_4337_rpcs_handle);
|
||||||
|
|
||||||
|
@ -646,7 +646,7 @@ impl Web3ProxyApp {
|
||||||
new_top_config_receiver
|
new_top_config_receiver
|
||||||
.changed()
|
.changed()
|
||||||
.await
|
.await
|
||||||
.context("failed awaiting top_config change")?;
|
.web3_context("failed awaiting top_config change")?;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -682,14 +682,14 @@ impl Web3ProxyApp {
|
||||||
self.balanced_rpcs
|
self.balanced_rpcs
|
||||||
.apply_server_configs(self, new_top_config.balanced_rpcs)
|
.apply_server_configs(self, new_top_config.balanced_rpcs)
|
||||||
.await
|
.await
|
||||||
.context("updating balanced rpcs")?;
|
.web3_context("updating balanced rpcs")?;
|
||||||
|
|
||||||
if let Some(private_rpc_configs) = new_top_config.private_rpcs {
|
if let Some(private_rpc_configs) = new_top_config.private_rpcs {
|
||||||
if let Some(ref private_rpcs) = self.private_rpcs {
|
if let Some(ref private_rpcs) = self.private_rpcs {
|
||||||
private_rpcs
|
private_rpcs
|
||||||
.apply_server_configs(self, private_rpc_configs)
|
.apply_server_configs(self, private_rpc_configs)
|
||||||
.await
|
.await
|
||||||
.context("updating private_rpcs")?;
|
.web3_context("updating private_rpcs")?;
|
||||||
} else {
|
} else {
|
||||||
// TODO: maybe we should have private_rpcs just be empty instead of being None
|
// TODO: maybe we should have private_rpcs just be empty instead of being None
|
||||||
todo!("handle toggling private_rpcs")
|
todo!("handle toggling private_rpcs")
|
||||||
|
@ -701,7 +701,7 @@ impl Web3ProxyApp {
|
||||||
bundler_4337_rpcs
|
bundler_4337_rpcs
|
||||||
.apply_server_configs(self, bundler_4337_rpc_configs)
|
.apply_server_configs(self, bundler_4337_rpc_configs)
|
||||||
.await
|
.await
|
||||||
.context("updating bundler_4337_rpcs")?;
|
.web3_context("updating bundler_4337_rpcs")?;
|
||||||
} else {
|
} else {
|
||||||
// TODO: maybe we should have bundler_4337_rpcs just be empty instead of being None
|
// TODO: maybe we should have bundler_4337_rpcs just be empty instead of being None
|
||||||
todo!("handle toggling bundler_4337_rpcs")
|
todo!("handle toggling bundler_4337_rpcs")
|
||||||
|
@ -731,8 +731,8 @@ impl Web3ProxyApp {
|
||||||
#[derive(Default, Serialize)]
|
#[derive(Default, Serialize)]
|
||||||
struct UserCount(i64);
|
struct UserCount(i64);
|
||||||
|
|
||||||
let user_count: UserCount = if let Some(db) = self.db_conn() {
|
let user_count: UserCount = if let Ok(db) = self.db_conn() {
|
||||||
match user::Entity::find().count(&db).await {
|
match user::Entity::find().count(db).await {
|
||||||
Ok(user_count) => UserCount(user_count as i64),
|
Ok(user_count) => UserCount(user_count as i64),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!("unable to count users: {:?}", err);
|
warn!("unable to count users: {:?}", err);
|
||||||
|
@ -767,7 +767,7 @@ impl Web3ProxyApp {
|
||||||
RecentCounts,
|
RecentCounts,
|
||||||
RecentCounts,
|
RecentCounts,
|
||||||
) = match self.redis_conn().await {
|
) = match self.redis_conn().await {
|
||||||
Ok(Some(mut redis_conn)) => {
|
Ok(mut redis_conn) => {
|
||||||
// TODO: delete any hash entries where
|
// TODO: delete any hash entries where
|
||||||
const ONE_MINUTE: i64 = 60;
|
const ONE_MINUTE: i64 = 60;
|
||||||
const ONE_HOUR: i64 = ONE_MINUTE * 60;
|
const ONE_HOUR: i64 = ONE_MINUTE * 60;
|
||||||
|
@ -857,11 +857,6 @@ impl Web3ProxyApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(None) => (
|
|
||||||
RecentCounts::default(),
|
|
||||||
RecentCounts::default(),
|
|
||||||
RecentCounts::default(),
|
|
||||||
),
|
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!("unable to connect to redis while counting users: {:?}", err);
|
warn!("unable to connect to redis while counting users: {:?}", err);
|
||||||
(
|
(
|
||||||
|
@ -898,7 +893,7 @@ impl Web3ProxyApp {
|
||||||
method: &str,
|
method: &str,
|
||||||
params: P,
|
params: P,
|
||||||
) -> Web3ProxyResult<R> {
|
) -> Web3ProxyResult<R> {
|
||||||
let db_conn = self.db_conn();
|
let db_conn = self.db_conn().ok().cloned();
|
||||||
|
|
||||||
let authorization = Arc::new(Authorization::internal(db_conn)?);
|
let authorization = Arc::new(Authorization::internal(db_conn)?);
|
||||||
|
|
||||||
|
@ -1021,10 +1016,9 @@ impl Web3ProxyApp {
|
||||||
Ok((collected, collected_rpcs))
|
Ok((collected, collected_rpcs))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO: i don't think we want or need this. just use app.db_conn, or maybe app.db_conn.clone() or app.db_conn.as_ref()
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn db_conn(&self) -> Option<DatabaseConnection> {
|
pub fn db_conn(&self) -> Web3ProxyResult<&DatabaseConnection> {
|
||||||
self.db_conn.clone()
|
self.db_conn.as_ref().ok_or(Web3ProxyError::NoDatabase)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -1038,18 +1032,18 @@ impl Web3ProxyApp {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn db_replica(&self) -> Option<DatabaseReplica> {
|
pub fn db_replica(&self) -> Web3ProxyResult<&DatabaseReplica> {
|
||||||
self.db_replica.clone()
|
self.db_replica.as_ref().ok_or(Web3ProxyError::NoDatabase)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn redis_conn(&self) -> anyhow::Result<Option<redis_rate_limiter::RedisConnection>> {
|
pub async fn redis_conn(&self) -> Web3ProxyResult<redis_rate_limiter::RedisConnection> {
|
||||||
match self.vredis_pool.as_ref() {
|
match self.vredis_pool.as_ref() {
|
||||||
// TODO: don't do an error. return None
|
None => Err(Web3ProxyError::NoDatabase),
|
||||||
None => Ok(None),
|
|
||||||
Some(redis_pool) => {
|
Some(redis_pool) => {
|
||||||
let redis_conn = redis_pool.get().await?;
|
// TODO: add a From for this
|
||||||
|
let redis_conn = redis_pool.get().await.context("redis pool error")?;
|
||||||
|
|
||||||
Ok(Some(redis_conn))
|
Ok(redis_conn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1458,7 +1452,7 @@ impl Web3ProxyApp {
|
||||||
|
|
||||||
let f = async move {
|
let f = async move {
|
||||||
match app.redis_conn().await {
|
match app.redis_conn().await {
|
||||||
Ok(Some(mut redis_conn)) => {
|
Ok(mut redis_conn) => {
|
||||||
let hashed_tx_hash =
|
let hashed_tx_hash =
|
||||||
Bytes::from(keccak256(salted_tx_hash.as_bytes()));
|
Bytes::from(keccak256(salted_tx_hash.as_bytes()));
|
||||||
|
|
||||||
|
@ -1469,7 +1463,7 @@ impl Web3ProxyApp {
|
||||||
.zadd(recent_tx_hash_key, hashed_tx_hash.to_string(), now)
|
.zadd(recent_tx_hash_key, hashed_tx_hash.to_string(), now)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
Ok(None) => {}
|
Err(Web3ProxyError::NoDatabase) => {},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!(
|
warn!(
|
||||||
"unable to save stats for eth_sendRawTransaction: {:?}",
|
"unable to save stats for eth_sendRawTransaction: {:?}",
|
||||||
|
|
|
@ -125,7 +125,7 @@ impl UserImportSubCommand {
|
||||||
for import_u in us.into_iter() {
|
for import_u in us.into_iter() {
|
||||||
// first, check if a user already exists with this address
|
// first, check if a user already exists with this address
|
||||||
if let Some(existing_u) = user::Entity::find()
|
if let Some(existing_u) = user::Entity::find()
|
||||||
.filter(user::Column::Address.eq(import_u.address))
|
.filter(user::Column::Address.eq(import_u.address.clone()))
|
||||||
.one(db_conn)
|
.one(db_conn)
|
||||||
.await?
|
.await?
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,9 +14,11 @@ use axum::{
|
||||||
use derive_more::{Display, Error, From};
|
use derive_more::{Display, Error, From};
|
||||||
use ethers::prelude::ContractError;
|
use ethers::prelude::ContractError;
|
||||||
use http::header::InvalidHeaderValue;
|
use http::header::InvalidHeaderValue;
|
||||||
|
use http::uri::InvalidUri;
|
||||||
use ipnet::AddrParseError;
|
use ipnet::AddrParseError;
|
||||||
use migration::sea_orm::DbErr;
|
use migration::sea_orm::DbErr;
|
||||||
use redis_rate_limiter::redis::RedisError;
|
use redis_rate_limiter::redis::RedisError;
|
||||||
|
use redis_rate_limiter::RedisPoolError;
|
||||||
use reqwest::header::ToStrError;
|
use reqwest::header::ToStrError;
|
||||||
use rust_decimal::Error as DecimalError;
|
use rust_decimal::Error as DecimalError;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
@ -63,6 +65,7 @@ pub enum Web3ProxyError {
|
||||||
HdrRecord(hdrhistogram::errors::RecordError),
|
HdrRecord(hdrhistogram::errors::RecordError),
|
||||||
Headers(headers::Error),
|
Headers(headers::Error),
|
||||||
HeaderToString(ToStrError),
|
HeaderToString(ToStrError),
|
||||||
|
HttpUri(InvalidUri),
|
||||||
Hyper(hyper::Error),
|
Hyper(hyper::Error),
|
||||||
InfluxDb2Request(influxdb2::RequestError),
|
InfluxDb2Request(influxdb2::RequestError),
|
||||||
#[display(fmt = "{} > {}", min, max)]
|
#[display(fmt = "{} > {}", min, max)]
|
||||||
|
@ -112,6 +115,7 @@ pub enum Web3ProxyError {
|
||||||
},
|
},
|
||||||
NotFound,
|
NotFound,
|
||||||
NotImplemented,
|
NotImplemented,
|
||||||
|
NoVolatileRedisDatabase,
|
||||||
OriginRequired,
|
OriginRequired,
|
||||||
#[error(ignore)]
|
#[error(ignore)]
|
||||||
#[from(ignore)]
|
#[from(ignore)]
|
||||||
|
@ -124,6 +128,7 @@ pub enum Web3ProxyError {
|
||||||
#[display(fmt = "{:?}, {:?}", _0, _1)]
|
#[display(fmt = "{:?}, {:?}", _0, _1)]
|
||||||
RateLimited(Authorization, Option<Instant>),
|
RateLimited(Authorization, Option<Instant>),
|
||||||
Redis(RedisError),
|
Redis(RedisError),
|
||||||
|
RedisDeadpool(RedisPoolError),
|
||||||
RefererRequired,
|
RefererRequired,
|
||||||
#[display(fmt = "{:?}", _0)]
|
#[display(fmt = "{:?}", _0)]
|
||||||
#[error(ignore)]
|
#[error(ignore)]
|
||||||
|
@ -355,6 +360,17 @@ impl Web3ProxyError {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Self::HttpUri(err) => {
|
||||||
|
trace!("HttpUri {:#?}", err);
|
||||||
|
(
|
||||||
|
StatusCode::BAD_REQUEST,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: err.to_string().into(),
|
||||||
|
code: StatusCode::BAD_REQUEST.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
Self::Hyper(err) => {
|
Self::Hyper(err) => {
|
||||||
warn!("hyper err={:#?}", err);
|
warn!("hyper err={:#?}", err);
|
||||||
(
|
(
|
||||||
|
@ -461,6 +477,18 @@ impl Web3ProxyError {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Self::RedisDeadpool(err) => {
|
||||||
|
error!("redis deadpool err={:#?}", err);
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
// TODO: is it safe to expose our io error strings?
|
||||||
|
message: err.to_string().into(),
|
||||||
|
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
Self::UnknownReferralCode => {
|
Self::UnknownReferralCode => {
|
||||||
trace!("UnknownReferralCode");
|
trace!("UnknownReferralCode");
|
||||||
(
|
(
|
||||||
|
@ -616,6 +644,17 @@ impl Web3ProxyError {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Self::NoVolatileRedisDatabase => {
|
||||||
|
error!("no volatile redis database configured");
|
||||||
|
(
|
||||||
|
StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
JsonRpcErrorData {
|
||||||
|
message: "no volatile redis database configured!".into(),
|
||||||
|
code: StatusCode::INTERNAL_SERVER_ERROR.as_u16().into(),
|
||||||
|
data: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
Self::NoServersSynced => {
|
Self::NoServersSynced => {
|
||||||
warn!("NoServersSynced");
|
warn!("NoServersSynced");
|
||||||
(
|
(
|
||||||
|
|
|
@ -175,17 +175,7 @@ pub async fn admin_login_get(
|
||||||
let issued_at = OffsetDateTime::now_utc();
|
let issued_at = OffsetDateTime::now_utc();
|
||||||
let expiration_time = issued_at.add(Duration::new(expire_seconds as i64, 0));
|
let expiration_time = issued_at.add(Duration::new(expire_seconds as i64, 0));
|
||||||
|
|
||||||
// The admin user is the one that basically logs in, on behalf of the user
|
// get the admin's address
|
||||||
// This will generate a login id for the admin, which we will be caching ...
|
|
||||||
// I suppose with this, the admin can be logged in to one session at a time
|
|
||||||
// let (caller, _semaphore) = app.bearer_is_authorized(bearer_token).await?;
|
|
||||||
|
|
||||||
// Finally, check if the user is an admin. If he is, return "true" as the third triplet.
|
|
||||||
// TODO: consider wrapping the output in a struct, instead of a triplet
|
|
||||||
// TODO: Could try to merge this into the above query ...
|
|
||||||
// This query will fail if it's not the admin...
|
|
||||||
|
|
||||||
// get the admin field ...
|
|
||||||
let admin_address: Address = params
|
let admin_address: Address = params
|
||||||
.get("admin_address")
|
.get("admin_address")
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
|
@ -196,7 +186,7 @@ pub async fn admin_login_get(
|
||||||
Web3ProxyError::BadRequest("Unable to parse admin_address as an Address".into())
|
Web3ProxyError::BadRequest("Unable to parse admin_address as an Address".into())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Fetch the user_address parameter from the login string ... (as who we want to be logging in ...)
|
// get the address who we want to be logging in as
|
||||||
let user_address: Address = params
|
let user_address: Address = params
|
||||||
.get("user_address")
|
.get("user_address")
|
||||||
.ok_or_else(|| {
|
.ok_or_else(|| {
|
||||||
|
@ -208,29 +198,26 @@ pub async fn admin_login_get(
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// We want to login to llamanodes.com
|
// We want to login to llamanodes.com
|
||||||
let login_domain = app
|
let domain = app
|
||||||
.config
|
.config
|
||||||
.login_domain
|
.login_domain
|
||||||
.as_deref()
|
.as_deref()
|
||||||
.unwrap_or("llamanodes.com");
|
.unwrap_or("llamanodes.com");
|
||||||
|
|
||||||
// Also there must basically be a token, that says that one admin logins _as a user_.
|
let message_domain = domain.parse()?;
|
||||||
// I'm not yet fully sure how to handle with that logic specifically ...
|
// TODO: don't unwrap
|
||||||
|
let message_uri = format!("https://{}/", domain).parse().unwrap();
|
||||||
|
|
||||||
// TODO: get most of these from the app config
|
// TODO: get most of these from the app config
|
||||||
// TODO: Let's check again who the message needs to be signed by;
|
|
||||||
// if the message does not have to be signed by the user, include the user ...
|
|
||||||
let message = Message {
|
let message = Message {
|
||||||
// TODO: don't unwrap
|
domain: message_domain,
|
||||||
// TODO: accept a login_domain from the request?
|
|
||||||
domain: login_domain.parse().unwrap(),
|
|
||||||
// the admin needs to sign the message, not the imitated user
|
// the admin needs to sign the message, not the imitated user
|
||||||
address: admin_address.to_fixed_bytes(),
|
address: admin_address.to_fixed_bytes(),
|
||||||
// TODO: config for statement
|
// TODO: config for statement
|
||||||
statement: Some("🦙🦙🦙🦙🦙".to_string()),
|
statement: Some("👑👑👑👑👑".to_string()),
|
||||||
// TODO: don't unwrap
|
uri: message_uri,
|
||||||
uri: format!("https://{}/", login_domain).parse().unwrap(),
|
|
||||||
version: siwe::Version::V1,
|
version: siwe::Version::V1,
|
||||||
chain_id: 1,
|
chain_id: app.config.chain_id,
|
||||||
expiration_time: Some(expiration_time.into()),
|
expiration_time: Some(expiration_time.into()),
|
||||||
issued_at: issued_at.into(),
|
issued_at: issued_at.into(),
|
||||||
nonce: nonce.to_string(),
|
nonce: nonce.to_string(),
|
||||||
|
@ -239,16 +226,14 @@ pub async fn admin_login_get(
|
||||||
resources: vec![],
|
resources: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
let db_conn = app.db_conn().web3_context("login requires a database")?;
|
let db_conn = app.db_conn()?;
|
||||||
let db_replica = app
|
let db_replica = app.db_replica()?;
|
||||||
.db_replica()
|
|
||||||
.web3_context("login requires a replica database")?;
|
|
||||||
|
|
||||||
// delete ALL expired rows.
|
// delete ALL expired rows.
|
||||||
let now = Utc::now();
|
let now = Utc::now();
|
||||||
let delete_result = pending_login::Entity::delete_many()
|
let delete_result = pending_login::Entity::delete_many()
|
||||||
.filter(pending_login::Column::ExpiresAt.lte(now))
|
.filter(pending_login::Column::ExpiresAt.lte(now))
|
||||||
.exec(&db_conn)
|
.exec(db_conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// TODO: emit a stat? if this is high something weird might be happening
|
// TODO: emit a stat? if this is high something weird might be happening
|
||||||
|
@ -283,7 +268,7 @@ pub async fn admin_login_get(
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
trail
|
trail
|
||||||
.save(&db_conn)
|
.save(db_conn)
|
||||||
.await
|
.await
|
||||||
.web3_context("saving user's pending_login")?;
|
.web3_context("saving user's pending_login")?;
|
||||||
|
|
||||||
|
@ -308,7 +293,7 @@ pub async fn admin_login_get(
|
||||||
};
|
};
|
||||||
|
|
||||||
user_pending_login
|
user_pending_login
|
||||||
.save(&db_conn)
|
.save(db_conn)
|
||||||
.await
|
.await
|
||||||
.web3_context("saving an admin trail pre login")?;
|
.web3_context("saving an admin trail pre login")?;
|
||||||
|
|
||||||
|
@ -385,9 +370,7 @@ pub async fn admin_login_post(
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
// fetch the message we gave them from our database
|
// fetch the message we gave them from our database
|
||||||
let db_replica = app
|
let db_replica = app.db_replica()?;
|
||||||
.db_replica()
|
|
||||||
.web3_context("Getting database connection")?;
|
|
||||||
|
|
||||||
// massage type for the db
|
// massage type for the db
|
||||||
let login_nonce_uuid: Uuid = login_nonce.clone().into();
|
let login_nonce_uuid: Uuid = login_nonce.clone().into();
|
||||||
|
@ -434,9 +417,7 @@ pub async fn admin_login_post(
|
||||||
.await?
|
.await?
|
||||||
.web3_context("admin address was not found!")?;
|
.web3_context("admin address was not found!")?;
|
||||||
|
|
||||||
let db_conn = app
|
let db_conn = app.db_conn()?;
|
||||||
.db_conn()
|
|
||||||
.web3_context("deleting expired pending logins requires a db")?;
|
|
||||||
|
|
||||||
// Add a message that the admin has logged in
|
// Add a message that the admin has logged in
|
||||||
// Note that the admin is trying to log in as this user
|
// Note that the admin is trying to log in as this user
|
||||||
|
@ -448,7 +429,7 @@ pub async fn admin_login_post(
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
trail
|
trail
|
||||||
.save(&db_conn)
|
.save(db_conn)
|
||||||
.await
|
.await
|
||||||
.web3_context("saving an admin trail post login")?;
|
.web3_context("saving an admin trail post login")?;
|
||||||
|
|
||||||
|
@ -497,15 +478,11 @@ pub async fn admin_login_post(
|
||||||
};
|
};
|
||||||
|
|
||||||
user_login
|
user_login
|
||||||
.save(&db_conn)
|
.save(db_conn)
|
||||||
.await
|
.await
|
||||||
.web3_context("saving user login")?;
|
.web3_context("saving user login")?;
|
||||||
|
|
||||||
if let Err(err) = user_pending_login
|
if let Err(err) = user_pending_login.into_active_model().delete(db_conn).await {
|
||||||
.into_active_model()
|
|
||||||
.delete(&db_conn)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
warn!("Failed to delete nonce:{}: {}", login_nonce.0, err);
|
warn!("Failed to delete nonce:{}: {}", login_nonce.0, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,13 +498,11 @@ pub async fn admin_logout_post(
|
||||||
) -> Web3ProxyResponse {
|
) -> Web3ProxyResponse {
|
||||||
let user_bearer = UserBearerToken::try_from(bearer)?;
|
let user_bearer = UserBearerToken::try_from(bearer)?;
|
||||||
|
|
||||||
let db_conn = app
|
let db_conn = app.db_conn()?;
|
||||||
.db_conn()
|
|
||||||
.web3_context("database needed for user logout")?;
|
|
||||||
|
|
||||||
if let Err(err) = login::Entity::delete_many()
|
if let Err(err) = login::Entity::delete_many()
|
||||||
.filter(login::Column::BearerToken.eq(user_bearer.uuid()))
|
.filter(login::Column::BearerToken.eq(user_bearer.uuid()))
|
||||||
.exec(&db_conn)
|
.exec(db_conn)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
debug!("Failed to delete {}: {}", user_bearer.redis_key(), err);
|
debug!("Failed to delete {}: {}", user_bearer.redis_key(), err);
|
||||||
|
@ -538,7 +513,7 @@ pub async fn admin_logout_post(
|
||||||
// also delete any expired logins
|
// also delete any expired logins
|
||||||
let delete_result = login::Entity::delete_many()
|
let delete_result = login::Entity::delete_many()
|
||||||
.filter(login::Column::ExpiresAt.lte(now))
|
.filter(login::Column::ExpiresAt.lte(now))
|
||||||
.exec(&db_conn)
|
.exec(db_conn)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
debug!("Deleted expired logins: {:?}", delete_result);
|
debug!("Deleted expired logins: {:?}", delete_result);
|
||||||
|
@ -546,7 +521,7 @@ pub async fn admin_logout_post(
|
||||||
// also delete any expired pending logins
|
// also delete any expired pending logins
|
||||||
let delete_result = login::Entity::delete_many()
|
let delete_result = login::Entity::delete_many()
|
||||||
.filter(login::Column::ExpiresAt.lte(now))
|
.filter(login::Column::ExpiresAt.lte(now))
|
||||||
.exec(&db_conn)
|
.exec(db_conn)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
debug!("Deleted expired pending logins: {:?}", delete_result);
|
debug!("Deleted expired pending logins: {:?}", delete_result);
|
||||||
|
|
|
@ -859,7 +859,7 @@ pub async fn ip_is_authorized(
|
||||||
let f = async move {
|
let f = async move {
|
||||||
let now = Utc::now().timestamp();
|
let now = Utc::now().timestamp();
|
||||||
|
|
||||||
if let Some(mut redis_conn) = app.redis_conn().await? {
|
if let Ok(mut redis_conn) = app.redis_conn().await {
|
||||||
let salt = app
|
let salt = app
|
||||||
.config
|
.config
|
||||||
.public_recent_ips_salt
|
.public_recent_ips_salt
|
||||||
|
@ -923,7 +923,7 @@ pub async fn key_is_authorized(
|
||||||
let f = async move {
|
let f = async move {
|
||||||
let now = Utc::now().timestamp();
|
let now = Utc::now().timestamp();
|
||||||
|
|
||||||
if let Some(mut redis_conn) = app.redis_conn().await? {
|
if let Ok(mut redis_conn) = app.redis_conn().await {
|
||||||
let salt = app
|
let salt = app
|
||||||
.config
|
.config
|
||||||
.public_recent_ips_salt
|
.public_recent_ips_salt
|
||||||
|
@ -1027,9 +1027,7 @@ impl Web3ProxyApp {
|
||||||
let semaphore_permit = semaphore.acquire_owned().await?;
|
let semaphore_permit = semaphore.acquire_owned().await?;
|
||||||
|
|
||||||
// get the attached address from the database for the given auth_token.
|
// get the attached address from the database for the given auth_token.
|
||||||
let db_replica = self
|
let db_replica = self.db_replica()?;
|
||||||
.db_replica()
|
|
||||||
.web3_context("checking if bearer token is authorized")?;
|
|
||||||
|
|
||||||
let user_bearer_uuid: Uuid = user_bearer_token.into();
|
let user_bearer_uuid: Uuid = user_bearer_token.into();
|
||||||
|
|
||||||
|
@ -1054,7 +1052,7 @@ impl Web3ProxyApp {
|
||||||
// we don't care about user agent or origin or referer
|
// we don't care about user agent or origin or referer
|
||||||
let authorization = Authorization::external(
|
let authorization = Authorization::external(
|
||||||
&self.config.allowed_origin_requests_per_period,
|
&self.config.allowed_origin_requests_per_period,
|
||||||
self.db_conn(),
|
self.db_conn().ok().cloned(),
|
||||||
&ip,
|
&ip,
|
||||||
None,
|
None,
|
||||||
proxy_mode,
|
proxy_mode,
|
||||||
|
@ -1110,7 +1108,7 @@ impl Web3ProxyApp {
|
||||||
) -> Web3ProxyResult<RateLimitResult> {
|
) -> Web3ProxyResult<RateLimitResult> {
|
||||||
if ip.is_loopback() {
|
if ip.is_loopback() {
|
||||||
// TODO: localhost being unlimited should be optional
|
// TODO: localhost being unlimited should be optional
|
||||||
let authorization = Authorization::internal(self.db_conn())?;
|
let authorization = Authorization::internal(self.db_conn().ok().cloned())?;
|
||||||
|
|
||||||
return Ok(RateLimitResult::Allowed(authorization, None));
|
return Ok(RateLimitResult::Allowed(authorization, None));
|
||||||
}
|
}
|
||||||
|
@ -1119,7 +1117,7 @@ impl Web3ProxyApp {
|
||||||
// they do check origin because we can override rate limits for some origins
|
// they do check origin because we can override rate limits for some origins
|
||||||
let authorization = Authorization::external(
|
let authorization = Authorization::external(
|
||||||
allowed_origin_requests_per_period,
|
allowed_origin_requests_per_period,
|
||||||
self.db_conn(),
|
self.db_conn().ok().cloned(),
|
||||||
ip,
|
ip,
|
||||||
origin,
|
origin,
|
||||||
proxy_mode,
|
proxy_mode,
|
||||||
|
@ -1181,9 +1179,7 @@ impl Web3ProxyApp {
|
||||||
Ok(x) => self
|
Ok(x) => self
|
||||||
.user_balance_cache
|
.user_balance_cache
|
||||||
.try_get_with(x, async move {
|
.try_get_with(x, async move {
|
||||||
let db_replica = self
|
let db_replica = self.db_replica()?;
|
||||||
.db_replica()
|
|
||||||
.web3_context("Getting database replica connection")?;
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match balance::Entity::find()
|
match balance::Entity::find()
|
||||||
|
@ -1201,8 +1197,7 @@ impl Web3ProxyApp {
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
// no balance row. make one now
|
// no balance row. make one now
|
||||||
let db_conn =
|
let db_conn = self.db_conn()?;
|
||||||
self.db_conn().web3_context("Getting database connection")?;
|
|
||||||
|
|
||||||
let balance_entry = balance::ActiveModel {
|
let balance_entry = balance::ActiveModel {
|
||||||
id: sea_orm::NotSet,
|
id: sea_orm::NotSet,
|
||||||
|
@ -1219,7 +1214,7 @@ impl Web3ProxyApp {
|
||||||
)])
|
)])
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
)
|
)
|
||||||
.exec(&db_conn)
|
.exec(db_conn)
|
||||||
.await
|
.await
|
||||||
.web3_context("creating empty balance row for existing user")?;
|
.web3_context("creating empty balance row for existing user")?;
|
||||||
|
|
||||||
|
@ -1243,9 +1238,7 @@ impl Web3ProxyApp {
|
||||||
.try_get_with_by_ref(rpc_secret_key, async move {
|
.try_get_with_by_ref(rpc_secret_key, async move {
|
||||||
// trace!(?rpc_secret_key, "user cache miss");
|
// trace!(?rpc_secret_key, "user cache miss");
|
||||||
|
|
||||||
let db_replica = self
|
let db_replica = self.db_replica()?;
|
||||||
.db_replica()
|
|
||||||
.web3_context("Getting database connection")?;
|
|
||||||
|
|
||||||
// TODO: join the user table to this to return the User? we don't always need it
|
// TODO: join the user table to this to return the User? we don't always need it
|
||||||
// TODO: join on secondary users
|
// TODO: join on secondary users
|
||||||
|
@ -1322,7 +1315,7 @@ impl Web3ProxyApp {
|
||||||
let user_model = user::Entity::find_by_id(rpc_key_model.user_id)
|
let user_model = user::Entity::find_by_id(rpc_key_model.user_id)
|
||||||
.one(db_replica.as_ref())
|
.one(db_replica.as_ref())
|
||||||
.await?
|
.await?
|
||||||
.context(
|
.web3_context(
|
||||||
"user model was not found, but every rpc_key should have a user",
|
"user model was not found, but every rpc_key should have a user",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -1331,7 +1324,7 @@ impl Web3ProxyApp {
|
||||||
)
|
)
|
||||||
.one(db_replica.as_ref())
|
.one(db_replica.as_ref())
|
||||||
.await?
|
.await?
|
||||||
.context(
|
.web3_context(
|
||||||
"related user tier not found, but every user should have a tier",
|
"related user tier not found, but every user should have a tier",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
@ -1351,7 +1344,7 @@ impl Web3ProxyApp {
|
||||||
user_tier::Entity::find_by_id(downgrade_user_tier)
|
user_tier::Entity::find_by_id(downgrade_user_tier)
|
||||||
.one(db_replica.as_ref())
|
.one(db_replica.as_ref())
|
||||||
.await?
|
.await?
|
||||||
.context(format!(
|
.web3_context(format!(
|
||||||
"downgrade user tier ({}) is missing!",
|
"downgrade user tier ({}) is missing!",
|
||||||
downgrade_user_tier
|
downgrade_user_tier
|
||||||
))?;
|
))?;
|
||||||
|
@ -1411,7 +1404,7 @@ impl Web3ProxyApp {
|
||||||
|
|
||||||
let authorization = Authorization::try_new(
|
let authorization = Authorization::try_new(
|
||||||
authorization_checks,
|
authorization_checks,
|
||||||
self.db_conn(),
|
self.db_conn().ok().cloned(),
|
||||||
ip,
|
ip,
|
||||||
origin,
|
origin,
|
||||||
referer,
|
referer,
|
||||||
|
|
|
@ -74,24 +74,24 @@ pub async fn user_login_get(
|
||||||
.parse()
|
.parse()
|
||||||
.or(Err(Web3ProxyError::ParseAddressError))?;
|
.or(Err(Web3ProxyError::ParseAddressError))?;
|
||||||
|
|
||||||
let login_domain = app
|
let domain = app
|
||||||
.config
|
.config
|
||||||
.login_domain
|
.login_domain
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_else(|| "llamanodes.com".to_string());
|
.unwrap_or_else(|| "llamanodes.com".to_string());
|
||||||
|
|
||||||
|
let message_domain = domain.parse().unwrap();
|
||||||
|
let message_uri = format!("https://{}/", domain).parse().unwrap();
|
||||||
|
|
||||||
// TODO: get most of these from the app config
|
// TODO: get most of these from the app config
|
||||||
let message = Message {
|
let message = Message {
|
||||||
// TODO: don't unwrap
|
domain: message_domain,
|
||||||
// TODO: accept a login_domain from the request?
|
|
||||||
domain: login_domain.parse().unwrap(),
|
|
||||||
address: user_address.to_fixed_bytes(),
|
address: user_address.to_fixed_bytes(),
|
||||||
// TODO: config for statement
|
// TODO: config for statement
|
||||||
statement: Some("🦙🦙🦙🦙🦙".to_string()),
|
statement: Some("🦙🦙🦙🦙🦙".to_string()),
|
||||||
// TODO: don't unwrap
|
uri: message_uri,
|
||||||
uri: format!("https://{}/", login_domain).parse().unwrap(),
|
|
||||||
version: siwe::Version::V1,
|
version: siwe::Version::V1,
|
||||||
chain_id: 1,
|
chain_id: app.config.chain_id,
|
||||||
expiration_time: Some(expiration_time.into()),
|
expiration_time: Some(expiration_time.into()),
|
||||||
issued_at: issued_at.into(),
|
issued_at: issued_at.into(),
|
||||||
nonce: nonce.to_string(),
|
nonce: nonce.to_string(),
|
||||||
|
@ -100,13 +100,13 @@ pub async fn user_login_get(
|
||||||
resources: vec![],
|
resources: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
let db_conn = app.db_conn().web3_context("login requires a database")?;
|
let db_conn = app.db_conn()?;
|
||||||
|
|
||||||
// delete ALL expired rows.
|
// delete ALL expired rows.
|
||||||
let now = Utc::now();
|
let now = Utc::now();
|
||||||
let _ = pending_login::Entity::delete_many()
|
let _ = pending_login::Entity::delete_many()
|
||||||
.filter(pending_login::Column::ExpiresAt.lte(now))
|
.filter(pending_login::Column::ExpiresAt.lte(now))
|
||||||
.exec(&db_conn)
|
.exec(db_conn)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
// massage types to fit in the database. sea-orm does not make this very elegant
|
// massage types to fit in the database. sea-orm does not make this very elegant
|
||||||
|
@ -127,7 +127,7 @@ pub async fn user_login_get(
|
||||||
};
|
};
|
||||||
|
|
||||||
user_pending_login
|
user_pending_login
|
||||||
.save(&db_conn)
|
.save(db_conn)
|
||||||
.await
|
.await
|
||||||
.web3_context("saving user's pending_login")?;
|
.web3_context("saving user's pending_login")?;
|
||||||
|
|
||||||
|
@ -236,9 +236,7 @@ pub async fn user_login_post(
|
||||||
let login_nonce = UserBearerToken::from_str(&their_msg.nonce)?;
|
let login_nonce = UserBearerToken::from_str(&their_msg.nonce)?;
|
||||||
|
|
||||||
// fetch the message we gave them from our database
|
// fetch the message we gave them from our database
|
||||||
let db_replica = app
|
let db_replica = app.db_replica()?;
|
||||||
.db_replica()
|
|
||||||
.web3_context("Getting database connection")?;
|
|
||||||
|
|
||||||
let user_pending_login = pending_login::Entity::find()
|
let user_pending_login = pending_login::Entity::find()
|
||||||
.filter(pending_login::Column::Nonce.eq(Uuid::from(login_nonce.clone())))
|
.filter(pending_login::Column::Nonce.eq(Uuid::from(login_nonce.clone())))
|
||||||
|
@ -270,7 +268,7 @@ pub async fn user_login_post(
|
||||||
.one(db_replica.as_ref())
|
.one(db_replica.as_ref())
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let db_conn = app.db_conn().web3_context("login requires a db")?;
|
let db_conn = app.db_conn()?;
|
||||||
|
|
||||||
let (caller, user_rpc_keys, status_code) = match caller {
|
let (caller, user_rpc_keys, status_code) = match caller {
|
||||||
None => {
|
None => {
|
||||||
|
@ -357,7 +355,7 @@ pub async fn user_login_post(
|
||||||
// the user is already registered
|
// the user is already registered
|
||||||
let user_rpc_keys = rpc_key::Entity::find()
|
let user_rpc_keys = rpc_key::Entity::find()
|
||||||
.filter(rpc_key::Column::UserId.eq(caller.id))
|
.filter(rpc_key::Column::UserId.eq(caller.id))
|
||||||
.all(&db_conn)
|
.all(db_conn)
|
||||||
.await
|
.await
|
||||||
.web3_context("failed loading user's key")?;
|
.web3_context("failed loading user's key")?;
|
||||||
|
|
||||||
|
@ -397,15 +395,11 @@ pub async fn user_login_post(
|
||||||
};
|
};
|
||||||
|
|
||||||
user_login
|
user_login
|
||||||
.save(&db_conn)
|
.save(db_conn)
|
||||||
.await
|
.await
|
||||||
.web3_context("saving user login")?;
|
.web3_context("saving user login")?;
|
||||||
|
|
||||||
if let Err(err) = user_pending_login
|
if let Err(err) = user_pending_login.into_active_model().delete(db_conn).await {
|
||||||
.into_active_model()
|
|
||||||
.delete(&db_conn)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
error!("Failed to delete nonce:{}: {}", login_nonce, err);
|
error!("Failed to delete nonce:{}: {}", login_nonce, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,13 +414,11 @@ pub async fn user_logout_post(
|
||||||
) -> Web3ProxyResponse {
|
) -> Web3ProxyResponse {
|
||||||
let user_bearer = UserBearerToken::try_from(bearer)?;
|
let user_bearer = UserBearerToken::try_from(bearer)?;
|
||||||
|
|
||||||
let db_conn = app
|
let db_conn = app.db_conn()?;
|
||||||
.db_conn()
|
|
||||||
.web3_context("database needed for user logout")?;
|
|
||||||
|
|
||||||
if let Err(err) = login::Entity::delete_many()
|
if let Err(err) = login::Entity::delete_many()
|
||||||
.filter(login::Column::BearerToken.eq(user_bearer.uuid()))
|
.filter(login::Column::BearerToken.eq(user_bearer.uuid()))
|
||||||
.exec(&db_conn)
|
.exec(db_conn)
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
warn!("Failed to delete {}: {}", user_bearer.redis_key(), err);
|
warn!("Failed to delete {}: {}", user_bearer.redis_key(), err);
|
||||||
|
@ -437,7 +429,7 @@ pub async fn user_logout_post(
|
||||||
// also delete any expired logins
|
// also delete any expired logins
|
||||||
let delete_result = login::Entity::delete_many()
|
let delete_result = login::Entity::delete_many()
|
||||||
.filter(login::Column::ExpiresAt.lte(now))
|
.filter(login::Column::ExpiresAt.lte(now))
|
||||||
.exec(&db_conn)
|
.exec(db_conn)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
trace!("Deleted expired logins: {:?}", delete_result);
|
trace!("Deleted expired logins: {:?}", delete_result);
|
||||||
|
@ -445,7 +437,7 @@ pub async fn user_logout_post(
|
||||||
// also delete any expired pending logins
|
// also delete any expired pending logins
|
||||||
let delete_result = login::Entity::delete_many()
|
let delete_result = login::Entity::delete_many()
|
||||||
.filter(login::Column::ExpiresAt.lte(now))
|
.filter(login::Column::ExpiresAt.lte(now))
|
||||||
.exec(&db_conn)
|
.exec(db_conn)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
trace!("Deleted expired pending logins: {:?}", delete_result);
|
trace!("Deleted expired pending logins: {:?}", delete_result);
|
||||||
|
|
|
@ -45,7 +45,7 @@ pub async fn user_balance_get(
|
||||||
) -> Web3ProxyResponse {
|
) -> Web3ProxyResponse {
|
||||||
let (_user, _semaphore) = app.bearer_is_authorized(bearer).await?;
|
let (_user, _semaphore) = app.bearer_is_authorized(bearer).await?;
|
||||||
|
|
||||||
let db_replica = app.db_replica().context("Getting database connection")?;
|
let db_replica = app.db_replica()?;
|
||||||
|
|
||||||
// Just return the balance for the user
|
// Just return the balance for the user
|
||||||
let user_balance = balance::Entity::find()
|
let user_balance = balance::Entity::find()
|
||||||
|
@ -73,7 +73,7 @@ pub async fn user_deposits_get(
|
||||||
) -> Web3ProxyResponse {
|
) -> Web3ProxyResponse {
|
||||||
let (user, _semaphore) = app.bearer_is_authorized(bearer).await?;
|
let (user, _semaphore) = app.bearer_is_authorized(bearer).await?;
|
||||||
|
|
||||||
let db_replica = app.db_replica().context("Getting database connection")?;
|
let db_replica = app.db_replica()?;
|
||||||
|
|
||||||
// Filter by user ...
|
// Filter by user ...
|
||||||
let receipts = increase_on_chain_balance_receipt::Entity::find()
|
let receipts = increase_on_chain_balance_receipt::Entity::find()
|
||||||
|
@ -114,7 +114,7 @@ pub async fn user_balance_post(
|
||||||
let (_, semaphore) = app.bearer_is_authorized(bearer).await?;
|
let (_, semaphore) = app.bearer_is_authorized(bearer).await?;
|
||||||
|
|
||||||
// TODO: is handling this as internal fine?
|
// TODO: is handling this as internal fine?
|
||||||
let authorization = Web3ProxyAuthorization::internal(app.db_conn())?;
|
let authorization = Web3ProxyAuthorization::internal(app.db_conn().ok().cloned())?;
|
||||||
|
|
||||||
(authorization, Some(semaphore))
|
(authorization, Some(semaphore))
|
||||||
} else if let Some(InsecureClientIp(ip)) = ip {
|
} else if let Some(InsecureClientIp(ip)) = ip {
|
||||||
|
@ -136,7 +136,7 @@ pub async fn user_balance_post(
|
||||||
Web3ProxyError::BadRequest(format!("unable to parse tx_hash: {}", err).into())
|
Web3ProxyError::BadRequest(format!("unable to parse tx_hash: {}", err).into())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let db_conn = app.db_conn().context("query_user_stats needs a db")?;
|
let db_conn = app.db_conn()?;
|
||||||
|
|
||||||
let authorization = Arc::new(authorization);
|
let authorization = Arc::new(authorization);
|
||||||
|
|
||||||
|
@ -172,7 +172,7 @@ pub async fn user_balance_post(
|
||||||
true
|
true
|
||||||
};
|
};
|
||||||
|
|
||||||
let uncle_hashes = find_uncles.all(&db_conn).await?;
|
let uncle_hashes = find_uncles.all(db_conn).await?;
|
||||||
|
|
||||||
let uncle_hashes: HashSet<_> = uncle_hashes
|
let uncle_hashes: HashSet<_> = uncle_hashes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
|
@ -35,9 +35,7 @@ pub async fn user_referral_link_get(
|
||||||
// First get the bearer token and check if the user is logged in
|
// First get the bearer token and check if the user is logged in
|
||||||
let (user, _semaphore) = app.bearer_is_authorized(bearer).await?;
|
let (user, _semaphore) = app.bearer_is_authorized(bearer).await?;
|
||||||
|
|
||||||
let db_replica = app
|
let db_replica = app.db_replica()?;
|
||||||
.db_replica()
|
|
||||||
.context("getting replica db for user's revert logs")?;
|
|
||||||
|
|
||||||
// Then get the referral token. If one doesn't exist, create one
|
// Then get the referral token. If one doesn't exist, create one
|
||||||
let user_referrer = referrer::Entity::find()
|
let user_referrer = referrer::Entity::find()
|
||||||
|
@ -49,7 +47,7 @@ pub async fn user_referral_link_get(
|
||||||
Some(x) => (x.referral_code, StatusCode::OK),
|
Some(x) => (x.referral_code, StatusCode::OK),
|
||||||
None => {
|
None => {
|
||||||
// Connect to the database for writes
|
// Connect to the database for writes
|
||||||
let db_conn = app.db_conn().context("getting db_conn")?;
|
let db_conn = app.db_conn()?;
|
||||||
|
|
||||||
let referral_code = ReferralCode::default().to_string();
|
let referral_code = ReferralCode::default().to_string();
|
||||||
|
|
||||||
|
@ -58,7 +56,7 @@ pub async fn user_referral_link_get(
|
||||||
referral_code: sea_orm::ActiveValue::Set(referral_code.clone()),
|
referral_code: sea_orm::ActiveValue::Set(referral_code.clone()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
referrer_entry.save(&db_conn).await?;
|
referrer_entry.save(db_conn).await?;
|
||||||
|
|
||||||
(referral_code, StatusCode::CREATED)
|
(referral_code, StatusCode::CREATED)
|
||||||
}
|
}
|
||||||
|
@ -82,9 +80,7 @@ pub async fn user_used_referral_stats(
|
||||||
// First get the bearer token and check if the user is logged in
|
// First get the bearer token and check if the user is logged in
|
||||||
let (user, _semaphore) = app.bearer_is_authorized(bearer).await?;
|
let (user, _semaphore) = app.bearer_is_authorized(bearer).await?;
|
||||||
|
|
||||||
let db_replica = app
|
let db_replica = app.db_replica()?;
|
||||||
.db_replica()
|
|
||||||
.context("getting replica db for user's revert logs")?;
|
|
||||||
|
|
||||||
// Get all referral records associated with this user
|
// Get all referral records associated with this user
|
||||||
let referrals = referee::Entity::find()
|
let referrals = referee::Entity::find()
|
||||||
|
@ -142,9 +138,7 @@ pub async fn user_shared_referral_stats(
|
||||||
// First get the bearer token and check if the user is logged in
|
// First get the bearer token and check if the user is logged in
|
||||||
let (user, _semaphore) = app.bearer_is_authorized(bearer).await?;
|
let (user, _semaphore) = app.bearer_is_authorized(bearer).await?;
|
||||||
|
|
||||||
let db_replica = app
|
let db_replica = app.db_replica()?;
|
||||||
.db_replica()
|
|
||||||
.context("getting replica db for user's revert logs")?;
|
|
||||||
|
|
||||||
// Get all referral records associated with this user
|
// Get all referral records associated with this user
|
||||||
let query_result = referrer::Entity::find()
|
let query_result = referrer::Entity::find()
|
||||||
|
|
|
@ -31,9 +31,7 @@ pub async fn rpc_keys_get(
|
||||||
) -> Web3ProxyResponse {
|
) -> Web3ProxyResponse {
|
||||||
let (user, _semaphore) = app.bearer_is_authorized(bearer).await?;
|
let (user, _semaphore) = app.bearer_is_authorized(bearer).await?;
|
||||||
|
|
||||||
let db_replica = app
|
let db_replica = app.db_replica()?;
|
||||||
.db_replica()
|
|
||||||
.web3_context("db_replica is required to fetch a user's keys")?;
|
|
||||||
|
|
||||||
// This is basically completely copied from sea-orm. Not optimal, but it keeps the format identical to before (while adding the final key)
|
// This is basically completely copied from sea-orm. Not optimal, but it keeps the format identical to before (while adding the final key)
|
||||||
// We could also pack the below stuff into it's subfield, but then we would destroy the format. Both options are fine for now though
|
// We could also pack the below stuff into it's subfield, but then we would destroy the format. Both options are fine for now though
|
||||||
|
@ -162,9 +160,7 @@ pub async fn rpc_keys_management(
|
||||||
|
|
||||||
let (user, _semaphore) = app.bearer_is_authorized(bearer).await?;
|
let (user, _semaphore) = app.bearer_is_authorized(bearer).await?;
|
||||||
|
|
||||||
let db_replica = app
|
let db_replica = app.db_replica()?;
|
||||||
.db_replica()
|
|
||||||
.web3_context("getting db for user's keys")?;
|
|
||||||
|
|
||||||
let mut uk = match payload.key_id {
|
let mut uk = match payload.key_id {
|
||||||
Some(existing_key_id) => {
|
Some(existing_key_id) => {
|
||||||
|
@ -342,9 +338,9 @@ pub async fn rpc_keys_management(
|
||||||
}
|
}
|
||||||
|
|
||||||
let uk = if uk.is_changed() {
|
let uk = if uk.is_changed() {
|
||||||
let db_conn = app.db_conn().web3_context("login requires a db")?;
|
let db_conn = app.db_conn()?;
|
||||||
|
|
||||||
uk.save(&db_conn)
|
uk.save(db_conn)
|
||||||
.await
|
.await
|
||||||
.web3_context("Failed saving user key")?
|
.web3_context("Failed saving user key")?
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -46,9 +46,7 @@ pub async fn user_revert_logs_get(
|
||||||
response.insert("chain_id", json!(chain_id));
|
response.insert("chain_id", json!(chain_id));
|
||||||
response.insert("query_start", json!(query_start.timestamp() as u64));
|
response.insert("query_start", json!(query_start.timestamp() as u64));
|
||||||
|
|
||||||
let db_replica = app
|
let db_replica = app.db_replica()?;
|
||||||
.db_replica()
|
|
||||||
.web3_context("getting replica db for user's revert logs")?;
|
|
||||||
|
|
||||||
let uks = rpc_key::Entity::find()
|
let uks = rpc_key::Entity::find()
|
||||||
.filter(rpc_key::Column::UserId.eq(user.id))
|
.filter(rpc_key::Column::UserId.eq(user.id))
|
||||||
|
|
|
@ -35,9 +35,7 @@ pub async fn get_keys_as_subuser(
|
||||||
// First, authenticate
|
// First, authenticate
|
||||||
let (subuser, _semaphore) = app.bearer_is_authorized(bearer).await?;
|
let (subuser, _semaphore) = app.bearer_is_authorized(bearer).await?;
|
||||||
|
|
||||||
let db_replica = app
|
let db_replica = app.db_replica()?;
|
||||||
.db_replica()
|
|
||||||
.context("getting replica db for user's revert logs")?;
|
|
||||||
|
|
||||||
// TODO: JOIN over RPC_KEY, SUBUSER, PRIMARY_USER and return these items
|
// TODO: JOIN over RPC_KEY, SUBUSER, PRIMARY_USER and return these items
|
||||||
|
|
||||||
|
@ -102,9 +100,7 @@ pub async fn get_subusers(
|
||||||
// First, authenticate
|
// First, authenticate
|
||||||
let (user, _semaphore) = app.bearer_is_authorized(bearer).await?;
|
let (user, _semaphore) = app.bearer_is_authorized(bearer).await?;
|
||||||
|
|
||||||
let db_replica = app
|
let db_replica = app.db_replica()?;
|
||||||
.db_replica()
|
|
||||||
.context("getting replica db for user's revert logs")?;
|
|
||||||
|
|
||||||
let rpc_key: u64 = params
|
let rpc_key: u64 = params
|
||||||
.remove("key_id")
|
.remove("key_id")
|
||||||
|
@ -176,9 +172,7 @@ pub async fn modify_subuser(
|
||||||
// First, authenticate
|
// First, authenticate
|
||||||
let (user, _semaphore) = app.bearer_is_authorized(bearer).await?;
|
let (user, _semaphore) = app.bearer_is_authorized(bearer).await?;
|
||||||
|
|
||||||
let db_replica = app
|
let db_replica = app.db_replica()?;
|
||||||
.db_replica()
|
|
||||||
.context("getting replica db for user's revert logs")?;
|
|
||||||
|
|
||||||
trace!("Parameters are: {:?}", params);
|
trace!("Parameters are: {:?}", params);
|
||||||
|
|
||||||
|
@ -262,7 +256,7 @@ pub async fn modify_subuser(
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: There is a good chunk of duplicate logic as login-post. Consider refactoring ...
|
// TODO: There is a good chunk of duplicate logic as login-post. Consider refactoring ...
|
||||||
let db_conn = app.db_conn().web3_context("login requires a db")?;
|
let db_conn = app.db_conn()?;
|
||||||
let (subuser, _subuser_rpc_keys, _status_code) = match subuser {
|
let (subuser, _subuser_rpc_keys, _status_code) = match subuser {
|
||||||
None => {
|
None => {
|
||||||
let txn = db_conn.begin().await?;
|
let txn = db_conn.begin().await?;
|
||||||
|
@ -344,12 +338,12 @@ pub async fn modify_subuser(
|
||||||
let mut active_subuser_entry_secondary_user = secondary_user.into_active_model();
|
let mut active_subuser_entry_secondary_user = secondary_user.into_active_model();
|
||||||
if !keep_subuser {
|
if !keep_subuser {
|
||||||
// Remove the user
|
// Remove the user
|
||||||
active_subuser_entry_secondary_user.delete(&db_conn).await?;
|
active_subuser_entry_secondary_user.delete(db_conn).await?;
|
||||||
action = "removed";
|
action = "removed";
|
||||||
} else {
|
} else {
|
||||||
// Just change the role
|
// Just change the role
|
||||||
active_subuser_entry_secondary_user.role = sea_orm::Set(new_role.clone());
|
active_subuser_entry_secondary_user.role = sea_orm::Set(new_role.clone());
|
||||||
active_subuser_entry_secondary_user.save(&db_conn).await?;
|
active_subuser_entry_secondary_user.save(db_conn).await?;
|
||||||
action = "role modified";
|
action = "role modified";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,8 +43,7 @@ pub async fn get_user_id_from_params(
|
||||||
let user_login = login::Entity::find()
|
let user_login = login::Entity::find()
|
||||||
.filter(login::Column::BearerToken.eq(user_bearer_token.uuid()))
|
.filter(login::Column::BearerToken.eq(user_bearer_token.uuid()))
|
||||||
.one(db_replica.as_ref())
|
.one(db_replica.as_ref())
|
||||||
.await
|
.await?
|
||||||
.context("database error while querying for user")?
|
|
||||||
.ok_or(Web3ProxyError::AccessDenied)?;
|
.ok_or(Web3ProxyError::AccessDenied)?;
|
||||||
|
|
||||||
// if expired, delete ALL expired logins
|
// if expired, delete ALL expired logins
|
||||||
|
|
|
@ -194,7 +194,7 @@ impl Web3Rpcs {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let db_conn = app.db_conn();
|
let db_conn = app.db_conn().ok().cloned();
|
||||||
let http_client = app.http_client.clone();
|
let http_client = app.http_client.clone();
|
||||||
let vredis_pool = app.vredis_pool.clone();
|
let vredis_pool = app.vredis_pool.clone();
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@ use crate::http_params::{
|
||||||
get_chain_id_from_params, get_page_from_params, get_query_start_from_params,
|
get_chain_id_from_params, get_page_from_params, get_query_start_from_params,
|
||||||
get_query_window_seconds_from_params, get_user_id_from_params,
|
get_query_window_seconds_from_params, get_user_id_from_params,
|
||||||
};
|
};
|
||||||
use anyhow::Context;
|
|
||||||
use axum::response::IntoResponse;
|
use axum::response::IntoResponse;
|
||||||
use axum::Json;
|
use axum::Json;
|
||||||
use axum::{
|
use axum::{
|
||||||
|
@ -62,19 +61,13 @@ pub async fn query_user_stats<'a>(
|
||||||
params: &'a HashMap<String, String>,
|
params: &'a HashMap<String, String>,
|
||||||
stat_response_type: StatType,
|
stat_response_type: StatType,
|
||||||
) -> Web3ProxyResponse {
|
) -> Web3ProxyResponse {
|
||||||
let db_conn = app.db_conn().context("query_user_stats needs a db")?;
|
let db_conn = app.db_conn()?;
|
||||||
let db_replica = app
|
let db_replica = app.db_replica()?;
|
||||||
.db_replica()
|
let mut redis_conn = app.redis_conn().await?;
|
||||||
.context("query_user_stats needs a db replica")?;
|
|
||||||
let mut redis_conn = app
|
|
||||||
.redis_conn()
|
|
||||||
.await
|
|
||||||
.context("query_user_stats had a redis connection error")?
|
|
||||||
.context("query_user_stats needs a redis")?;
|
|
||||||
|
|
||||||
// get the user id first. if it is 0, we should use a cache on the app
|
// get the user id first. if it is 0, we should use a cache on the app
|
||||||
let user_id =
|
let user_id =
|
||||||
get_user_id_from_params(&mut redis_conn, &db_conn, &db_replica, bearer, params).await?;
|
get_user_id_from_params(&mut redis_conn, db_conn, db_replica, bearer, params).await?;
|
||||||
// get the query window seconds now so that we can pick a cache with a good TTL
|
// get the query window seconds now so that we can pick a cache with a good TTL
|
||||||
// TODO: for now though, just do one cache. its easier
|
// TODO: for now though, just do one cache. its easier
|
||||||
let query_window_seconds = get_query_window_seconds_from_params(params)?;
|
let query_window_seconds = get_query_window_seconds_from_params(params)?;
|
||||||
|
|
|
@ -46,9 +46,7 @@ pub async fn query_user_stats<'a>(
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let db_replica = app
|
let db_replica = app.db_replica()?;
|
||||||
.db_replica()
|
|
||||||
.context("query_user_stats needs a db replica")?;
|
|
||||||
|
|
||||||
// TODO: have a getter for this. do we need a connection pool on it?
|
// TODO: have a getter for this. do we need a connection pool on it?
|
||||||
let influxdb_client = app
|
let influxdb_client = app
|
||||||
|
|
Loading…
Reference in New Issue