consistent route name

This commit is contained in:
Bryan Stitt 2023-06-24 15:49:26 -07:00
parent 1d6e1ef9af
commit 38b266156a
4 changed files with 32 additions and 80 deletions

View File

@ -54,7 +54,7 @@ pub async fn query_admin_modify_usertier<'a>(
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, "query_admin_modify_usertier");
// 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()

View File

@ -47,7 +47,7 @@ pub async fn admin_increase_balance(
TypedHeader(Authorization(bearer)): TypedHeader<Authorization<Bearer>>, TypedHeader(Authorization(bearer)): TypedHeader<Authorization<Bearer>>,
Query(params): Query<HashMap<String, String>>, Query(params): Query<HashMap<String, String>>,
) -> Web3ProxyResponse { ) -> Web3ProxyResponse {
let (caller, _) = app.bearer_is_authorized(bearer).await?; let (caller, _semaphore) = app.bearer_is_authorized(bearer).await?;
let caller_id = caller.id; let caller_id = caller.id;
@ -59,7 +59,10 @@ pub async fn admin_increase_balance(
.filter(admin::Column::UserId.eq(caller_id)) .filter(admin::Column::UserId.eq(caller_id))
.one(&txn) .one(&txn)
.await? .await?
.ok_or(Web3ProxyError::AccessDenied)?; .ok_or_else(|| {
warn!(%caller_id, "not an admin");
Web3ProxyError::AccessDenied
})?;
// Get the user from params // Get the user from params
let user_address: Address = params let user_address: Address = params
@ -72,6 +75,7 @@ pub async fn admin_increase_balance(
Web3ProxyError::BadRequest("Unable to parse user_address as an Address".into()) Web3ProxyError::BadRequest("Unable to parse user_address as an Address".into())
})?; })?;
// Get the note from params
let note: String = params let note: String = params
.get("note") .get("note")
.ok_or_else(|| Web3ProxyError::BadRequest("Unable to find 'note' key in request".into()))? .ok_or_else(|| Web3ProxyError::BadRequest("Unable to find 'note' key in request".into()))?
@ -311,11 +315,11 @@ pub async fn admin_imitate_login_get(
Ok(message.into_response()) Ok(message.into_response())
} }
/// `POST /admin/login` - Admin login by posting a signed "siwe" message /// `POST /admin/imitate-login` - Admin login by posting a signed "siwe" message
/// It is recommended to save the returned bearer token in a cookie. /// It is recommended to save the returned bearer token in a cookie.
/// The bearer token can be used to authenticate other admin requests /// The bearer token can be used to authenticate other admin requests
#[debug_handler] #[debug_handler]
pub async fn admin_login_post( pub async fn admin_imitate_login_post(
Extension(app): Extension<Arc<Web3ProxyApp>>, Extension(app): Extension<Arc<Web3ProxyApp>>,
InsecureClientIp(ip): InsecureClientIp, InsecureClientIp(ip): InsecureClientIp,
Json(payload): Json<PostLogin>, Json(payload): Json<PostLogin>,
@ -479,44 +483,3 @@ pub async fn admin_login_post(
Ok(response) Ok(response)
} }
// TODO: This is basically an exact copy of the user endpoint, I should probabl refactor this code ...
/// `POST /admin/imitate-logout` - Forget the bearer token in the `Authentication` header.
#[debug_handler]
pub async fn admin_logout_post(
Extension(app): Extension<Arc<Web3ProxyApp>>,
TypedHeader(Authorization(bearer)): TypedHeader<Authorization<Bearer>>,
) -> Web3ProxyResponse {
let user_bearer = UserBearerToken::try_from(bearer)?;
let db_conn = app.db_conn()?;
if let Err(err) = login::Entity::delete_many()
.filter(login::Column::BearerToken.eq(user_bearer.uuid()))
.exec(db_conn)
.await
{
debug!("Failed to delete {}: {}", user_bearer.redis_key(), err);
}
let now = Utc::now();
// also delete any expired logins
let delete_result = login::Entity::delete_many()
.filter(login::Column::ExpiresAt.lte(now))
.exec(db_conn)
.await;
debug!("Deleted expired logins: {:?}", delete_result);
// also delete any expired pending logins
let delete_result = login::Entity::delete_many()
.filter(login::Column::ExpiresAt.lte(now))
.exec(db_conn)
.await;
debug!("Deleted expired pending logins: {:?}", delete_result);
// TODO: what should the response be? probably json something
Ok("goodbye".into_response())
}

View File

@ -216,15 +216,17 @@ pub async fn serve(
) )
.route("/admin/modify_role", post(admin::admin_change_user_roles)) .route("/admin/modify_role", post(admin::admin_change_user_roles))
.route( .route(
"/admin/imitate-login/:admin_address/:user_address", "/admin/imitate_login/:admin_address/:user_address",
get(admin::admin_imitate_login_get), get(admin::admin_imitate_login_get),
) )
.route( .route(
"/admin/imitate-login/:admin_address/:user_address/:message_eip", "/admin/imitate_login/:admin_address/:user_address/:message_eip",
get(admin::admin_imitate_login_get), get(admin::admin_imitate_login_get),
) )
.route("/admin/imitate-login", post(admin::admin_login_post)) .route(
.route("/admin/imitate-logout", post(admin::admin_logout_post)) "/admin/imitate_login",
post(admin::admin_imitate_login_post),
)
// //
// Axum layers // Axum layers
// layers are ordered bottom up // layers are ordered bottom up

View File

@ -63,9 +63,9 @@ pub async fn user_login_get(
let nonce = Ulid::new(); let nonce = Ulid::new();
let issued_at = OffsetDateTime::now_utc(); let now = OffsetDateTime::now_utc();
let expiration_time = issued_at.add(Duration::new(expire_seconds as i64, 0)); let expiration_time = now.add(Duration::new(expire_seconds as i64, 0));
// TODO: allow ENS names here? // TODO: allow ENS names here?
let user_address: Address = params let user_address: Address = params
@ -93,7 +93,7 @@ pub async fn user_login_get(
version: siwe::Version::V1, version: siwe::Version::V1,
chain_id: app.config.chain_id, 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: now.into(),
nonce: nonce.to_string(), nonce: nonce.to_string(),
not_before: None, not_before: None,
request_id: None, request_id: None,
@ -102,15 +102,20 @@ pub async fn user_login_get(
let db_conn = app.db_conn()?; let db_conn = app.db_conn()?;
// delete ALL expired rows. // delete any expired logins
let now = Utc::now(); let expired_logins = login::Entity::delete_many()
let _ = pending_login::Entity::delete_many() .filter(login::Column::ExpiresAt.lte(now))
.filter(pending_login::Column::ExpiresAt.lte(now))
.exec(db_conn) .exec(db_conn)
.await?; .await;
trace!(?expired_logins, "deleted");
// delete any expired pending logins
let expired_pending_logins = pending_login::Entity::delete_many()
.filter(login::Column::ExpiresAt.lte(now))
.exec(db_conn)
.await;
trace!(?expired_pending_logins, "deleted");
// massage types to fit in the database. sea-orm does not make this very elegant
let uuid = Uuid::from_u128(nonce.into());
// we add 1 to expire_seconds just to be sure the database has the key for the full expiration_time // we add 1 to expire_seconds just to be sure the database has the key for the full expiration_time
let expires_at = Utc let expires_at = Utc
.timestamp_opt(expiration_time.unix_timestamp() + 1, 0) .timestamp_opt(expiration_time.unix_timestamp() + 1, 0)
@ -120,7 +125,7 @@ pub async fn user_login_get(
// add a row to the database for this user // add a row to the database for this user
let user_pending_login = pending_login::ActiveModel { let user_pending_login = pending_login::ActiveModel {
id: sea_orm::NotSet, id: sea_orm::NotSet,
nonce: sea_orm::Set(uuid), nonce: sea_orm::Set(nonce.into()),
message: sea_orm::Set(message.to_string()), message: sea_orm::Set(message.to_string()),
expires_at: sea_orm::Set(expires_at), expires_at: sea_orm::Set(expires_at),
imitating_user: sea_orm::Set(None), imitating_user: sea_orm::Set(None),
@ -388,7 +393,7 @@ pub async fn user_login_post(
let user_login = login::ActiveModel { let user_login = login::ActiveModel {
id: sea_orm::NotSet, id: sea_orm::NotSet,
bearer_token: sea_orm::Set(user_bearer_token.uuid()), bearer_token: sea_orm::Set(user_bearer_token.into()),
user_id: sea_orm::Set(caller.id), user_id: sea_orm::Set(caller.id),
expires_at: sea_orm::Set(expires_at), expires_at: sea_orm::Set(expires_at),
read_only: sea_orm::Set(false), read_only: sea_orm::Set(false),
@ -424,24 +429,6 @@ pub async fn user_logout_post(
warn!("Failed to delete {}: {}", user_bearer.redis_key(), err); warn!("Failed to delete {}: {}", user_bearer.redis_key(), err);
} }
let now = Utc::now();
// also delete any expired logins
let delete_result = login::Entity::delete_many()
.filter(login::Column::ExpiresAt.lte(now))
.exec(db_conn)
.await;
trace!("Deleted expired logins: {:?}", delete_result);
// also delete any expired pending logins
let delete_result = login::Entity::delete_many()
.filter(login::Column::ExpiresAt.lte(now))
.exec(db_conn)
.await;
trace!("Deleted expired pending logins: {:?}", delete_result);
// TODO: what should the response be? probably json something // TODO: what should the response be? probably json something
Ok("goodbye".into_response()) Ok("goodbye".into_response())
} }