Skip to content

Commit

Permalink
Auth
Browse files Browse the repository at this point in the history
  • Loading branch information
Dzejkop committed Jun 3, 2024
1 parent a913dd6 commit 4b12a60
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 26 deletions.
72 changes: 46 additions & 26 deletions src/new_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ use poem::listener::{Acceptor, Listener, TcpListener};
use poem::web::{Data, LocalAddr};
use poem::{EndpointExt, Result, Route};
use poem_openapi::param::Path;
use poem_openapi::payload::{Json, PlainText};
use poem_openapi::payload::Json;
use poem_openapi::{ApiResponse, OpenApi, OpenApiService};
use security::BasicAuth;
use url::Url;

use crate::api_key::ApiKey;
Expand All @@ -21,36 +22,31 @@ use crate::types::{
RelayerInfo, RelayerUpdate,
};

struct AdminApi;

#[derive(ApiResponse)]
enum AdminResponse {
#[oai(status = 200)]
RelayerCreated(Json<CreateRelayerResponse>),

#[oai(status = 200)]
NetworkCreated,
mod security;

#[oai(status = 500)]
InternalServerError(PlainText<String>),
}
struct AdminApi;

#[OpenApi(prefix_path = "/1/admin/")]
impl AdminApi {
/// Create Relayer
#[oai(path = "/relayer", method = "post")]
async fn create_relayer(
&self,
app: Data<&Arc<App>>,
req: Json<CreateRelayerRequest>,
) -> AdminResponse {
basic_auth: BasicAuth,
Data(app): Data<&Arc<App>>,
Json(req): Json<CreateRelayerRequest>,
) -> Result<Json<CreateRelayerResponse>> {
basic_auth.validate(app).await?;

let (key_id, signer) = match app.keys_source.new_signer(&req.name).await
{
Ok(signer) => signer,
Err(e) => {
tracing::error!("Failed to create signer: {:?}", e);
return AdminResponse::InternalServerError(PlainText(

return Err(poem::error::Error::from_string(
"Failed to create signer".to_string(),
StatusCode::INTERNAL_SERVER_ERROR,
));
}
};
Expand All @@ -75,13 +71,15 @@ impl AdminApi {
Ok(()) => {}
Err(e) => {
tracing::error!("Failed to create relayer: {:?}", e);
return AdminResponse::InternalServerError(PlainText(

return Err(poem::error::Error::from_string(
"Failed to create relayer".to_string(),
StatusCode::INTERNAL_SERVER_ERROR,
));
}
}

AdminResponse::RelayerCreated(Json(CreateRelayerResponse {
Ok(Json(CreateRelayerResponse {
relayer_id,
address: address.into(),
}))
Expand All @@ -91,8 +89,11 @@ impl AdminApi {
#[oai(path = "/relayers", method = "get")]
async fn get_relayers(
&self,
app: Data<&Arc<App>>,
basic_auth: BasicAuth,
Data(app): Data<&Arc<App>>,
) -> Result<Json<Vec<RelayerInfo>>> {
basic_auth.validate(app).await?;

let relayer_info = app.db.get_relayers().await?;

Ok(Json(relayer_info))
Expand All @@ -102,9 +103,12 @@ impl AdminApi {
#[oai(path = "/relayer/:relayer_id", method = "get")]
async fn get_relayer(
&self,
app: Data<&Arc<App>>,
basic_auth: BasicAuth,
Data(app): Data<&Arc<App>>,
Path(relayer_id): Path<String>,
) -> Result<Json<RelayerInfo>> {
basic_auth.validate(app).await?;

let relayer_info =
app.db.get_relayer(&relayer_id).await.map_err(|err| {
poem::error::Error::from_string(
Expand All @@ -120,10 +124,13 @@ impl AdminApi {
#[oai(path = "/relayer/:relayer_id", method = "post")]
async fn update_relayer(
&self,
app: Data<&Arc<App>>,
basic_auth: BasicAuth,
Data(app): Data<&Arc<App>>,
Path(relayer_id): Path<String>,
Json(req): Json<RelayerUpdate>,
) -> Result<()> {
basic_auth.validate(app).await?;

app.db
.update_relayer(&relayer_id, &req)
.await
Expand All @@ -143,9 +150,12 @@ impl AdminApi {
#[oai(path = "/relayer/:relayer_id/reset", method = "post")]
async fn purge_unsent_txs(
&self,
app: Data<&Arc<App>>,
basic_auth: BasicAuth,
Data(app): Data<&Arc<App>>,
Path(relayer_id): Path<String>,
) -> Result<()> {
basic_auth.validate(app).await?;

app.db.purge_unsent_txs(&relayer_id).await.map_err(|err| {
poem::error::Error::from_string(
err.to_string(),
Expand All @@ -160,9 +170,12 @@ impl AdminApi {
#[oai(path = "/relayer/:relayer_id/key", method = "post")]
async fn create_relayer_api_key(
&self,
app: Data<&Arc<App>>,
basic_auth: BasicAuth,
Data(app): Data<&Arc<App>>,
Path(relayer_id): Path<String>,
) -> Result<Json<CreateApiKeyResponse>> {
basic_auth.validate(app).await?;

let api_key = ApiKey::random(&relayer_id);

app.db
Expand All @@ -176,10 +189,13 @@ impl AdminApi {
#[oai(path = "/network/:chain_id", method = "post")]
async fn create_network(
&self,
app: Data<&Arc<App>>,
basic_auth: BasicAuth,
Data(app): Data<&Arc<App>>,
Path(chain_id): Path<u64>,
Json(network): Json<NewNetworkInfo>,
) -> Result<()> {
basic_auth.validate(app).await?;

let http_url: Url = network
.http_rpc
.parse::<Url>()
Expand Down Expand Up @@ -220,8 +236,11 @@ impl AdminApi {
#[oai(path = "/networks", method = "get")]
async fn list_networks(
&self,
app: Data<&Arc<App>>,
basic_auth: BasicAuth,
Data(app): Data<&Arc<App>>,
) -> Result<Json<Vec<NetworkInfo>>> {
basic_auth.validate(app).await?;

let networks = app.db.get_networks().await.map_err(|err| {
poem::error::Error::from_string(
err.to_string(),
Expand All @@ -248,6 +267,7 @@ enum ServiceResponse {

#[OpenApi]
impl ServiceApi {
/// Health
#[oai(path = "/", method = "get")]
async fn health(&self) -> ServiceResponse {
ServiceResponse::Healthy
Expand Down
25 changes: 25 additions & 0 deletions src/new_server/security.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use poem::Result;
use poem_openapi::{auth, SecurityScheme};

use crate::app::App;

#[derive(SecurityScheme)]
#[oai(ty = "basic")]
pub struct BasicAuth(auth::Basic);

impl BasicAuth {
pub async fn validate(&self, app: impl AsRef<App>) -> Result<()> {
let app = app.as_ref();

if let Some((username, password)) = app.config.server.credentials() {
if username != self.0.username && password != self.0.password {
return Err(poem::error::Error::from_string(
"Unauthorized".to_string(),
poem::http::StatusCode::UNAUTHORIZED,
));
}
}

Ok(())
}
}

0 comments on commit 4b12a60

Please sign in to comment.