diff --git a/Cargo.lock b/Cargo.lock index 9226e0b..e357aeb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1496,6 +1496,7 @@ dependencies = [ "rand_core 0.6.4", "rsa", "sec1", + "serde", "sha2 0.10.6", "signature", "ssh-encoding", @@ -1696,6 +1697,7 @@ dependencies = [ "tower", "tower-layer", "tower-service", + "tracing", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 2204e09..d73b5a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ edition = "2021" [features] default = [ "client", "reload" ] reload = [] +info = [ "axum/json", "ssh-key/serde" ] client = [ "dep:url", "dep:reqwest" ] @@ -24,7 +25,7 @@ ssh-key = { version = "0.5.1", features = ["ed25519", "p256", "p384", "rsa", "si thiserror = "1.0.37" tokio = { version = "1.22.0", features = ["io-std", "test-util", "tracing", "macros", "fs"] } tower = { version = "0.4.13", features = ["util"] } -tower-http = { version = "0.3.4", features = ["map-request-body"] } +tower-http = { version = "0.3.4", features = ["map-request-body", "trace"] } tracing = { version = "0.1.37", features = ["release_max_level_debug"] } tracing-subscriber = "0.3.16" url = { version = "2.3.1", optional = true } diff --git a/src/api.rs b/src/api.rs index dc715bd..f0242db 100644 --- a/src/api.rs +++ b/src/api.rs @@ -11,8 +11,8 @@ use crate::env_key; use anyhow::Context; use axum::body; use axum::extract::{Path, State}; -use axum::routing::post; -use axum::{http::StatusCode, response::IntoResponse, Router}; + +use axum::{http::StatusCode, response::IntoResponse, Json, Router}; use axum_extra::routing::{ RouterExt, // for `Router::typed_*` TypedPath, @@ -22,8 +22,8 @@ use serde::Deserialize; use ssh_key::{Certificate, PublicKey}; use tokio::sync::Mutex; use tower::ServiceBuilder; -use tower_http::ServiceBuilderExt; -use tracing::{debug, instrument, trace}; +use tower_http::{trace::TraceLayer, ServiceBuilderExt}; +use tracing::{debug, trace}; use self::extract::CertificateBody; @@ -133,9 +133,11 @@ pub async fn run( let app = Router::new() .typed_get(get_certs_identifier) .typed_put(put_cert_update) - .route("/certs/:identifier", post(post_certs_identifier)) + .typed_get(get_cert_info) + .typed_post(post_certs_identifier) .fallback(fallback_404) .layer(ServiceBuilder::new().map_request_body(body::boxed)) + .layer(TraceLayer::new_for_http()) .with_state(state); // run our app with hyper @@ -193,7 +195,6 @@ pub struct GetCert { /// return Unauthorized with an challenge /// upon which the client will ssh-keysign /// the challenge an issue an post request -#[instrument(skip_all, ret)] async fn get_certs_identifier( GetCert { identifier }: GetCert, State(ApiState { certs, .. }): State, @@ -205,9 +206,41 @@ async fn get_certs_identifier( Ok(cert.to_openssh().context("to openssh")?) } +#[derive(TypedPath, Deserialize)] +#[typed_path("/certs/:identifier/info")] +pub struct GetCertInfo { + pub identifier: String, +} + +#[cfg(feature = "info")] +async fn get_cert_info( + GetCertInfo { identifier }: GetCertInfo, + State(ApiState { certs, .. }): State, +) -> ApiResult> { + let certs = certs.lock().await; + let cert = certs + .get(&identifier) + .ok_or(ApiError::CertificateNotFound)?; + Ok(Json(cert.clone())) +} + +#[cfg(not(feature = "info"))] +async fn get_cert_info( + GetCertInfo { identifier: _ }: GetCertInfo, + State(ApiState { certs: _, .. }): State, +) -> ApiResult<()> { + unimplemented!() +} + +#[derive(TypedPath, Deserialize)] +#[typed_path("/certs/:identifier")] +pub struct PostCertInfo { + pub identifier: String, +} + /// POST with signed challenge -#[instrument(skip_all, ret)] async fn post_certs_identifier( + PostCertInfo { identifier: _ }: PostCertInfo, State(ApiState { .. }): State, Path(_identifier): Path, ) -> ApiResult { @@ -219,7 +252,6 @@ async fn post_certs_identifier( pub struct PutCert; /// Upload an cert with an higher serial than the previous -#[instrument(skip_all, ret)] async fn put_cert_update( _: PutCert, State(ApiState { @@ -237,7 +269,6 @@ async fn put_cert_update( ) -> ApiResult { cert.validate(&[ca.fingerprint(Default::default())]) .map_err(|_| ApiError::CertificateInvalid)?; - let _string_repr = cert.to_openssh(); let prev = load_cert_by_id(&cert_dir, &ca, cert.key_id()).await?; let mut prev_serial = 0; let serial = cert.serial();