put or post for user key management

This commit is contained in:
Bryan Stitt 2022-10-31 20:51:06 +00:00
parent 91eb907a2d
commit 2540182b7c
2 changed files with 27 additions and 26 deletions

View File

@ -12,7 +12,7 @@ use crate::app::Web3ProxyApp;
use axum::{ use axum::{
body::Body, body::Body,
handler::Handler, handler::Handler,
routing::{get, post}, routing::{get, post, put},
Extension, Router, Extension, Router,
}; };
use http::header::AUTHORIZATION; use http::header::AUTHORIZATION;
@ -75,7 +75,8 @@ pub async fn serve(port: u16, proxy_app: Arc<Web3ProxyApp>) -> anyhow::Result<()
.route("/user/balance", get(users::user_balance_get)) .route("/user/balance", get(users::user_balance_get))
.route("/user/balance/:txid", post(users::user_balance_post)) .route("/user/balance/:txid", post(users::user_balance_post))
.route("/user/keys", get(users::rpc_keys_get)) .route("/user/keys", get(users::rpc_keys_get))
.route("/user/keys", post(users::rpc_keys_post)) .route("/user/keys", post(users::rpc_keys_management))
.route("/user/keys", put(users::rpc_keys_management))
.route("/user/revert_logs", get(users::user_revert_logs_get)) .route("/user/revert_logs", get(users::user_revert_logs_get))
.route( .route(
"/user/stats/aggregate", "/user/stats/aggregate",

View File

@ -38,7 +38,6 @@ use std::sync::Arc;
use time::{Duration, OffsetDateTime}; use time::{Duration, OffsetDateTime};
use tracing::{instrument, warn}; use tracing::{instrument, warn};
use ulid::Ulid; use ulid::Ulid;
use uuid::Uuid;
/// `GET /user/login/:user_address` or `GET /user/login/:user_address/:message_eip` -- Start the "Sign In with Ethereum" (siwe) login flow. /// `GET /user/login/:user_address` or `GET /user/login/:user_address/:message_eip` -- Start the "Sign In with Ethereum" (siwe) login flow.
/// ///
@ -479,12 +478,25 @@ pub async fn rpc_keys_get(
Ok(Json(response_json).into_response()) Ok(Json(response_json).into_response())
} }
/// the JSON input to the `rpc_keys_post` handler. /// `DELETE /user/keys` -- Use a bearer token to delete an existing key.
#[debug_handler]
#[instrument(level = "trace")]
pub async fn rpc_keys_delete(
Extension(app): Extension<Arc<Web3ProxyApp>>,
TypedHeader(Authorization(bearer)): TypedHeader<Authorization<Bearer>>,
) -> FrontendResult {
let (user, _semaphore) = app.bearer_is_authorized(bearer).await?;
// TODO: think about how cascading deletes and billing should work
Err(anyhow::anyhow!("work in progress").into())
}
/// the JSON input to the `rpc_keys_management` handler.
/// If `key_id` is set, it updates an existing key.
/// If `key_id` is not set, it creates a new key.
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub struct UserKeysPost { pub struct UserKeyManagement {
// TODO: make sure the email address is valid. probably have a "verified" column in the database key_id: Option<u64>,
existing_key_id: Option<u64>,
existing_key: Option<RpcApiKey>,
description: Option<String>, description: Option<String>,
private_txs: Option<bool>, private_txs: Option<bool>,
active: Option<bool>, active: Option<bool>,
@ -497,22 +509,21 @@ pub struct UserKeysPost {
// do not allow! `max_concurrent_requests: Option<u64>,` // do not allow! `max_concurrent_requests: Option<u64>,`
} }
/// `POST /user/keys` -- Use a bearer token to create a new key or modify an existing key. /// `POST /user/keys` or `PUT /user/keys` -- Use a bearer token to create or update an existing key.
///
/// TODO: read json from the request body
/// TODO: one key per request? maybe /user/keys/:rpc_key?
#[debug_handler] #[debug_handler]
#[instrument(level = "trace")] #[instrument(level = "trace")]
pub async fn rpc_keys_post( pub async fn rpc_keys_management(
Extension(app): Extension<Arc<Web3ProxyApp>>, Extension(app): Extension<Arc<Web3ProxyApp>>,
TypedHeader(Authorization(bearer)): TypedHeader<Authorization<Bearer>>, TypedHeader(Authorization(bearer)): TypedHeader<Authorization<Bearer>>,
Json(payload): Json<UserKeysPost>, Json(payload): Json<UserKeyManagement>,
) -> FrontendResult { ) -> FrontendResult {
// TODO: is there a way we can know if this is a PUT or POST? right now we can modify or create keys with either. though that probably doesn't matter
let (user, _semaphore) = app.bearer_is_authorized(bearer).await?; let (user, _semaphore) = app.bearer_is_authorized(bearer).await?;
let db_conn = app.db_conn().context("getting db for user's keys")?; let db_conn = app.db_conn().context("getting db for user's keys")?;
let mut uk = if let Some(existing_key_id) = payload.existing_key_id { let mut uk = if let Some(existing_key_id) = payload.key_id {
// get the key and make sure it belongs to the user // get the key and make sure it belongs to the user
let uk = rpc_keys::Entity::find() let uk = rpc_keys::Entity::find()
.filter(rpc_keys::Column::UserId.eq(user.id)) .filter(rpc_keys::Column::UserId.eq(user.id))
@ -522,17 +533,6 @@ pub async fn rpc_keys_post(
.context("failed loading user's key")? .context("failed loading user's key")?
.context("key does not exist or is not controlled by this bearer token")?; .context("key does not exist or is not controlled by this bearer token")?;
uk.try_into().unwrap()
} else if let Some(existing_key) = payload.existing_key {
// get the key and make sure it belongs to the user
let uk = rpc_keys::Entity::find()
.filter(rpc_keys::Column::UserId.eq(user.id))
.filter(rpc_keys::Column::RpcKey.eq(Uuid::from(existing_key)))
.one(&db_conn)
.await
.context("failed loading user's key")?
.context("key does not exist or is not controlled by this bearer token")?;
uk.try_into().unwrap() uk.try_into().unwrap()
} else { } else {
// make a new key // make a new key