changes from review. will test now
This commit is contained in:
parent
7877958ab3
commit
b1f18460d1
|
@ -1,3 +1,3 @@
|
||||||
sea-orm-cli migrate up
|
# sea-orm-cli migrate up
|
||||||
|
# sea-orm-cli generate entity -u mysql://root:dev_web3_proxy@127.0.0.1:13306/dev_web3_proxy -o entities/src --with-serde both
|
||||||
# sea-orm-cli generate entity -t <table_name>
|
# sea-orm-cli generate entity -t <table_name>
|
|
@ -8,8 +8,10 @@ use axum::{
|
||||||
TypedHeader,
|
TypedHeader,
|
||||||
};
|
};
|
||||||
use axum::response::{IntoResponse, Response};
|
use axum::response::{IntoResponse, Response};
|
||||||
use entities::{admin, user, user_tier};
|
use entities::{admin, login, user, user_tier};
|
||||||
use ethers::prelude::Address;
|
use ethers::prelude::Address;
|
||||||
|
use ethers::types::Bytes;
|
||||||
|
use ethers::utils::keccak256;
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use http::StatusCode;
|
use http::StatusCode;
|
||||||
use migration::sea_orm::{self, ActiveModelTrait, ColumnTrait, EntityTrait, IntoActiveModel, QueryFilter};
|
use migration::sea_orm::{self, ActiveModelTrait, ColumnTrait, EntityTrait, IntoActiveModel, QueryFilter};
|
||||||
|
@ -32,29 +34,13 @@ pub async fn query_admin_modify_usertier<'a>(
|
||||||
// Quickly return if any of the input tokens are bad
|
// Quickly return if any of the input tokens are bad
|
||||||
let user_address: Vec<u8> = params
|
let user_address: Vec<u8> = params
|
||||||
.get("user_address")
|
.get("user_address")
|
||||||
.ok_or_else(||
|
.ok_or_else(|| FrontendErrorResponse::BadRequest("Unable to find user_address key in request".to_string()))?
|
||||||
FrontendErrorResponse::StatusCode(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
"Unable to find user_address key in request".to_string(),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
)?
|
|
||||||
.parse::<Address>()
|
.parse::<Address>()
|
||||||
.map_err(|err| {
|
.map_err(|_| FrontendErrorResponse::BadRequest("Unable to parse user_address as an Address".to_string()))?
|
||||||
FrontendErrorResponse::StatusCode(
|
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
"Unable to parse user_address as an Address".to_string(),
|
|
||||||
Some(err.into()),
|
|
||||||
)
|
|
||||||
})?
|
|
||||||
.to_fixed_bytes().into();
|
.to_fixed_bytes().into();
|
||||||
let user_tier_title = params
|
let user_tier_title = params
|
||||||
.get("user_tier_title")
|
.get("user_tier_title")
|
||||||
.ok_or_else(|| FrontendErrorResponse::StatusCode(
|
.ok_or_else(||FrontendErrorResponse::BadRequest("Unable to get the user_tier_title key from the request".to_string()))?;
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
"Unable to get the user_tier_title key from the request".to_string(),
|
|
||||||
None,
|
|
||||||
))?;
|
|
||||||
|
|
||||||
// Prepare output body
|
// Prepare output body
|
||||||
let mut response_body = HashMap::new();
|
let mut response_body = HashMap::new();
|
||||||
|
@ -78,22 +64,18 @@ pub async fn query_admin_modify_usertier<'a>(
|
||||||
// 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_replica.conn())
|
||||||
.await?
|
.await?
|
||||||
.ok_or(AccessDenied.into())?;
|
.ok_or(AccessDenied)?;
|
||||||
|
|
||||||
// If we are here, that means an admin was found, and we can safely proceed
|
// If we are here, that means an admin was found, and we can safely proceed
|
||||||
|
|
||||||
// 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))
|
.filter(user::Column::Address.eq(user_address))
|
||||||
.one(&db_conn)
|
.one(db_replica.conn())
|
||||||
.await?
|
.await?
|
||||||
.ok_or(FrontendErrorResponse::StatusCode(
|
.ok_or(FrontendErrorResponse::BadRequest("No user with this id found".to_string()))?;
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
"No user with this id found".to_string(),
|
|
||||||
None,
|
|
||||||
))?;
|
|
||||||
// Return early if the target user_tier_id is the same as the original user_tier_id
|
// Return early if the target user_tier_id is the same as the original user_tier_id
|
||||||
response_body.insert(
|
response_body.insert(
|
||||||
"user_tier_title",
|
"user_tier_title",
|
||||||
|
@ -101,20 +83,16 @@ 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_replica.conn())
|
||||||
.await?
|
.await?
|
||||||
.ok_or(|| FrontendErrorResponse::StatusCode(
|
.ok_or(FrontendErrorResponse::BadRequest("User Tier name was not found".to_string()))?;
|
||||||
StatusCode::BAD_REQUEST,
|
|
||||||
"User Tier name was not found".to_string(),
|
|
||||||
None,
|
|
||||||
))?;
|
|
||||||
|
|
||||||
if user.user_tier_id == new_user_tier.id {
|
if user.user_tier_id == new_user_tier.id {
|
||||||
info!("user already has that tier");
|
info!("user already has that tier");
|
||||||
} else {
|
} else {
|
||||||
let mut user = user.into_active_model();
|
let mut user = user.clone().into_active_model();
|
||||||
|
|
||||||
user.user_tier_id = sea_orm::Set(new_user_tier.id);
|
user.user_tier_id = sea_orm::Set(new_user_tier.id);
|
||||||
|
|
||||||
|
@ -123,11 +101,35 @@ pub async fn query_admin_modify_usertier<'a>(
|
||||||
info!("user's tier changed");
|
info!("user's tier changed");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, remove the user from redis
|
// Query the login table, and get all bearer tokens by this user
|
||||||
// TODO: Also remove the user from the redis
|
let bearer_tokens = login::Entity::find()
|
||||||
// redis_conn.zrem();
|
.filter(login::Column::UserId.eq(user.id))
|
||||||
// redis_conn.get::<_, u64>(&user.) // TODO: Where do i find the bearer token ...
|
.all(db_replica.conn())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// TODO: Remove from Redis
|
||||||
|
// Remove multiple items simultaneously, but this should be quick let's not prematurely optimize
|
||||||
|
let recent_user_id_key = format!("recent_users:id:{}", app.config.chain_id);
|
||||||
|
let salt = app
|
||||||
|
.config
|
||||||
|
.public_recent_ips_salt
|
||||||
|
.as_ref()
|
||||||
|
.expect("public_recent_ips_salt must exist in here");
|
||||||
|
|
||||||
|
// TODO: How do I remove the redis items (?)
|
||||||
|
for bearer_token in bearer_tokens {
|
||||||
|
let salted_user_id = format!("{}:{}", salt, bearer_token.user_id);
|
||||||
|
let hashed_user_id = Bytes::from(keccak256(salted_user_id.as_bytes()));
|
||||||
|
redis_conn
|
||||||
|
.zrem(&recent_user_id_key, hashed_user_id.to_string())
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now delete these tokens ...
|
||||||
|
login::Entity::delete_many()
|
||||||
|
.filter(login::Column::UserId.eq(user.id))
|
||||||
|
.exec(&db_conn)
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(Json(&response_body).into_response())
|
Ok(Json(&response_body).into_response())
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use argh::FromArgs;
|
use argh::FromArgs;
|
||||||
use entities::{admin, login, user};
|
use entities::{admin, login, user};
|
||||||
use ethers::types::Address;
|
use ethers::types::{Address, Bytes};
|
||||||
|
use ethers::utils::keccak256;
|
||||||
|
use http::StatusCode;
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
use migration::sea_orm::{
|
use migration::sea_orm::{
|
||||||
self, ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, ModelTrait, IntoActiveModel,
|
self, ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, ModelTrait, IntoActiveModel,
|
||||||
|
@ -34,17 +36,19 @@ impl ChangeUserAdminStatusSubCommand {
|
||||||
.filter(user::Column::Address.eq(address.clone()))
|
.filter(user::Column::Address.eq(address.clone()))
|
||||||
.one(db_conn)
|
.one(db_conn)
|
||||||
.await?
|
.await?
|
||||||
.context("No user found with that address")?;
|
.context(format!("No user with this id found {:?}", address))?;
|
||||||
|
|
||||||
// Check if there is a record in the database
|
|
||||||
let mut admin = admin::Entity::find()
|
|
||||||
.filter(admin::Column::UserId.eq(address))
|
|
||||||
.all(db_conn)
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
debug!("user: {:#?}", user);
|
debug!("user: {:#?}", user);
|
||||||
|
|
||||||
match admin.pop() {
|
// Check if there is a record in the database
|
||||||
|
match admin::Entity::find()
|
||||||
|
.filter(admin::Column::UserId.eq(address))
|
||||||
|
.one(db_conn)
|
||||||
|
.await? {
|
||||||
|
Some(old_admin) if !should_be_admin => {
|
||||||
|
// User is already an admin, but shouldn't be
|
||||||
|
old_admin.delete(db_conn).await?;
|
||||||
|
}
|
||||||
None if should_be_admin => {
|
None if should_be_admin => {
|
||||||
// User is not an admin yet, but should be
|
// User is not an admin yet, but should be
|
||||||
let new_admin = admin::ActiveModel {
|
let new_admin = admin::ActiveModel {
|
||||||
|
@ -52,19 +56,42 @@ impl ChangeUserAdminStatusSubCommand {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
new_admin.insert(db_conn).await?;
|
new_admin.insert(db_conn).await?;
|
||||||
},
|
}
|
||||||
Some(old_admin) if !should_be_admin => {
|
_ => {
|
||||||
// User is already an admin, but shouldn't be
|
// Do nothing in this case
|
||||||
old_admin.delete(db_conn).await?;
|
debug!("no change needed for: {:#?}", user);
|
||||||
},
|
// Early return
|
||||||
_ => {}
|
return Ok(());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the bearer tokens of this user and delete them ...
|
||||||
|
let bearer_tokens = login::Entity::find()
|
||||||
|
.filter(login::Column::UserId.eq(user.id))
|
||||||
|
.all(db_conn)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
// // TODO: Remove from Redis
|
||||||
|
// // Remove multiple items simultaneously, but this should be quick let's not prematurely optimize
|
||||||
|
// let recent_user_id_key = format!("recent_users:id:{}", app.config.chain_id);
|
||||||
|
// let salt = app
|
||||||
|
// .config
|
||||||
|
// .public_recent_ips_salt
|
||||||
|
// .as_ref()
|
||||||
|
// .expect("public_recent_ips_salt must exist in here");
|
||||||
|
//
|
||||||
|
// // TODO: Also clear redis ...
|
||||||
|
// let salted_user_id = format!("{}:{}", salt, bearer_token.user_id);
|
||||||
|
// let hashed_user_id = Bytes::from(keccak256(salted_user_id.as_bytes()));
|
||||||
|
// redis_conn
|
||||||
|
// .zrem(&recent_user_id_key, hashed_user_id.to_string())
|
||||||
|
// .await?;
|
||||||
|
|
||||||
// Remove any user logins from the database (incl. bearer tokens)
|
// Remove any user logins from the database (incl. bearer tokens)
|
||||||
let delete_result = login::Entity::delete_many()
|
let delete_result = 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?;
|
||||||
|
|
||||||
debug!("cleared modified logins: {:?}", delete_result);
|
debug!("cleared modified logins: {:?}", delete_result);
|
||||||
|
|
||||||
|
|
|
@ -309,7 +309,7 @@ fn main() -> anyhow::Result<()> {
|
||||||
SubCommand::ChangeUserTierByAddress(x) => {
|
SubCommand::ChangeUserTierByAddress(x) => {
|
||||||
let db_url = cli_config
|
let db_url = cli_config
|
||||||
.db_url
|
.db_url
|
||||||
.expect("'--config' (with a db) or '--db-url' is required to run proxyd");
|
.expect("'--config' (with a db) or '--db-url' is required to run change_user_admin_status");
|
||||||
|
|
||||||
let db_conn = get_db(db_url, 1, 1).await?;
|
let db_conn = get_db(db_url, 1, 1).await?;
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ use axum::{
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
Extension, Json, TypedHeader,
|
Extension, Json, TypedHeader,
|
||||||
};
|
};
|
||||||
use axum_client_ip::ClientIp;
|
use axum_client_ip::InsecureClientIp;
|
||||||
use axum_macros::debug_handler;
|
use axum_macros::debug_handler;
|
||||||
use chrono::{TimeZone, Utc};
|
use chrono::{TimeZone, Utc};
|
||||||
use entities::sea_orm_active_enums::{LogLevel, Role};
|
use entities::sea_orm_active_enums::{LogLevel, Role};
|
||||||
|
@ -67,7 +67,7 @@ pub async fn admin_change_user_roles(
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
pub async fn admin_login_get(
|
pub async fn admin_login_get(
|
||||||
Extension(app): Extension<Arc<Web3ProxyApp>>,
|
Extension(app): Extension<Arc<Web3ProxyApp>>,
|
||||||
ClientIp(ip): ClientIp,
|
InsecureClientIp(ip): InsecureClientIp,
|
||||||
Path(mut params): Path<HashMap<String, String>>,
|
Path(mut params): Path<HashMap<String, String>>,
|
||||||
) -> FrontendResult {
|
) -> FrontendResult {
|
||||||
// First check if the login is authorized
|
// First check if the login is authorized
|
||||||
|
@ -229,7 +229,7 @@ pub async fn admin_login_get(
|
||||||
#[debug_handler]
|
#[debug_handler]
|
||||||
pub async fn admin_login_post(
|
pub async fn admin_login_post(
|
||||||
Extension(app): Extension<Arc<Web3ProxyApp>>,
|
Extension(app): Extension<Arc<Web3ProxyApp>>,
|
||||||
ClientIp(ip): ClientIp,
|
InsecureClientIp(ip): InsecureClientIp,
|
||||||
Query(query): Query<PostLoginQuery>,
|
Query(query): Query<PostLoginQuery>,
|
||||||
Json(payload): Json<PostLogin>,
|
Json(payload): Json<PostLogin>,
|
||||||
) -> FrontendResult {
|
) -> FrontendResult {
|
||||||
|
|
|
@ -172,7 +172,7 @@ pub async fn serve(port: u16, proxy_app: Arc<Web3ProxyApp>) -> anyhow::Result<()
|
||||||
.route("/admin/modify_role", get(admin::admin_change_user_roles))
|
.route("/admin/modify_role", get(admin::admin_change_user_roles))
|
||||||
.route("/admin/imitate-login/:user_address", get(admin::admin_login_get))
|
.route("/admin/imitate-login/:user_address", get(admin::admin_login_get))
|
||||||
.route(
|
.route(
|
||||||
"/user/imitate-login/:user_address/:message_eip",
|
"/admin/imitate-login/:user_address/:message_eip",
|
||||||
get(admin::admin_login_get),
|
get(admin::admin_login_get),
|
||||||
)
|
)
|
||||||
.route("/admin/imitate-login", post(admin::admin_login_post))
|
.route("/admin/imitate-login", post(admin::admin_login_post))
|
||||||
|
|
Loading…
Reference in New Issue