use std::sync::Arc;
use warp::Filter;
use crate::{invoice::HealthResponse, server::filters, signature::KeyRing};
pub fn api<P, I, Authn, Authz, S>(
store: P,
index: I,
authn: Authn,
authz: Authz,
secret_store: S,
verification_strategy: crate::VerificationStrategy,
keyring: KeyRing,
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone
where
P: crate::provider::Provider + Clone + Send + Sync + 'static,
I: crate::search::Search + Clone + Send + Sync + 'static,
S: crate::invoice::signature::SecretKeyStorage + Clone + Send + Sync + 'static,
Authn: crate::authn::Authenticator + Clone + Send + Sync + 'static,
Authz: crate::authz::Authorizer + Clone + Send + Sync + 'static,
{
let health = warp::path("healthz").map(|| {
warp::reply::json(&HealthResponse {
status: "OK".to_string(),
version: env!("CARGO_PKG_VERSION").to_string(),
})
});
let wrapped_keyring = Arc::new(keyring);
warp::path("v1")
.and(filters::authenticate_and_authorize(authn.clone(), authz))
.untuple_one()
.and(
v1::invoice::query(index)
.or(v1::invoice::create_toml(
store.clone(),
secret_store.clone(),
verification_strategy.clone(),
wrapped_keyring.clone(),
))
.boxed()
.or(v1::invoice::create_json(
store.clone(),
secret_store.clone(),
verification_strategy,
wrapped_keyring,
))
.boxed()
.or(v1::invoice::get(store.clone()))
.boxed()
.or(v1::invoice::head(store.clone()))
.boxed()
.or(v1::invoice::yank(store.clone()))
.boxed()
.or(v1::parcel::create(store.clone()))
.boxed()
.or(v1::parcel::get(store.clone()))
.boxed()
.or(v1::parcel::head(store.clone()))
.boxed()
.or(v1::relationships::get_missing_parcels(store))
.boxed()
.or(v1::auth::login(
authn.client_id().to_owned(),
authn.auth_url().to_owned(),
authn.token_url().to_owned(),
))
.boxed()
.or(v1::keyring::host_keys(secret_store))
.boxed(),
)
.or(health)
.boxed()
.recover(filters::handle_invalid_request_path)
.recover(filters::handle_authn_rejection)
.recover(filters::handle_authz_rejection)
.with(warp::trace::request())
}
pub mod v1 {
use crate::provider::Provider;
use crate::search::Search;
use crate::server::handlers::v1::*;
use crate::server::{filters, routes::with_store};
use warp::Filter;
pub mod auth {
use super::*;
use crate::LoginParams;
pub fn login(
provider_client_id: String,
device_auth_url: String,
token_url: String,
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
warp::path("login")
.and(warp::get())
.and(warp::query::<LoginParams>())
.and(warp::any().map(move || provider_client_id.clone()))
.and(warp::any().map(move || device_auth_url.clone()))
.and(warp::any().map(move || token_url.clone()))
.and(warp::header::optional::<String>("accept"))
.and_then(crate::server::handlers::v1::login)
.boxed()
}
}
pub mod invoice {
use crate::{
server::routes::with_secret_store,
signature::{KeyRing, SecretKeyStorage},
};
use super::*;
use std::sync::Arc;
pub fn query<S>(
index: S,
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone
where
S: Search + Clone + Send + Sync,
{
warp::path("_q")
.and(warp::get().or(warp::head()).unify())
.and(warp::query::<crate::QueryOptions>())
.and(warp::any().map(move || index.clone()))
.and(warp::header::optional::<String>("accept"))
.and_then(query_invoices)
}
pub fn create_toml<P, S>(
store: P,
secret_store: S,
verification_strategy: crate::VerificationStrategy,
keyring: Arc<KeyRing>,
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone
where
P: Provider + Clone + Send + Sync,
S: SecretKeyStorage + Clone + Send + Sync,
{
warp::path("_i")
.and(warp::path::end())
.and(warp::post())
.and(with_store(store))
.and(with_secret_store(secret_store))
.and(warp::any().map(move || verification_strategy.clone()))
.and(warp::any().map(move || keyring.clone()))
.and(filters::toml())
.and(warp::header::optional::<String>("accept"))
.and_then(create_invoice)
.recover(filters::handle_deserialize_rejection)
}
pub fn create_json<P, S>(
store: P,
secret_store: S,
verification_strategy: crate::VerificationStrategy,
keyring: Arc<KeyRing>,
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone
where
P: Provider + Clone + Send + Sync,
S: SecretKeyStorage + Clone + Send + Sync,
{
warp::path("_i")
.and(warp::path::end())
.and(warp::post())
.and(with_store(store))
.and(with_secret_store(secret_store))
.and(warp::any().map(move || verification_strategy.clone()))
.and(warp::any().map(move || keyring.clone()))
.and(warp::body::json())
.and(warp::header::optional::<String>("accept"))
.and_then(create_invoice)
.recover(filters::handle_deserialize_rejection)
}
pub fn get<P>(
store: P,
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone
where
P: Provider + Clone + Send + Sync,
{
filters::invoice()
.and(warp::get())
.and(warp::query::<filters::InvoiceQuery>())
.and(with_store(store))
.and(warp::header::optional::<String>("accept"))
.and_then(get_invoice)
}
pub fn head<P>(
store: P,
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone
where
P: Provider + Clone + Send + Sync,
{
filters::invoice()
.and(warp::head())
.and(warp::query::<filters::InvoiceQuery>())
.and(with_store(store))
.and(warp::header::optional::<String>("accept"))
.and_then(head_invoice)
}
pub fn yank<P>(
store: P,
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone
where
P: Provider + Clone + Send + Sync,
{
warp::path("_i")
.and(warp::path::tail())
.and(warp::delete())
.and(with_store(store))
.and(warp::header::optional::<String>("accept"))
.and_then(yank_invoice)
}
}
pub mod parcel {
use super::*;
pub fn create<P>(
store: P,
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone
where
P: Provider + Clone + Send + Sync,
{
filters::parcel()
.and(warp::post())
.and(warp::body::stream())
.and(with_store(store))
.and(warp::header::optional::<String>("accept"))
.and_then(create_parcel)
}
pub fn get<P>(
store: P,
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone
where
P: Provider + Clone + Send + Sync,
{
filters::parcel()
.and(warp::get())
.and(with_store(store))
.and_then(get_parcel)
}
pub fn head<P>(
store: P,
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone
where
P: Provider + Clone + Send + Sync,
{
filters::parcel()
.and(warp::head())
.and(with_store(store))
.and_then(head_parcel)
}
}
pub mod relationships {
use super::*;
pub fn get_missing_parcels<P>(
store: P,
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone
where
P: Provider + Clone + Send + Sync,
{
warp::path("_r")
.and(warp::path("missing"))
.and(warp::path::tail())
.and(warp::get())
.and(with_store(store))
.and(warp::header::optional::<String>("accept"))
.and_then(get_missing)
}
}
pub mod keyring {
use super::*;
use crate::server::routes::with_secret_store;
use crate::signature::SecretKeyStorage;
pub fn host_keys<S>(
secret_store: S,
) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone
where
S: SecretKeyStorage + Clone + Send + Sync,
{
warp::path("bindle-keys")
.and(warp::get().or(warp::head()).unify())
.and(warp::query::<crate::KeyOptions>())
.and(with_secret_store(secret_store))
.and(warp::header::optional::<String>("accept"))
.and_then(bindle_keys)
}
}
}
pub(crate) fn with_store<P>(
store: P,
) -> impl Filter<Extract = (P,), Error = std::convert::Infallible> + Clone
where
P: crate::provider::Provider + Clone + Send,
{
warp::any().map(move || store.clone())
}
pub(crate) fn with_secret_store<P>(
store: P,
) -> impl Filter<Extract = (P,), Error = std::convert::Infallible> + Clone
where
P: crate::invoice::signature::SecretKeyStorage + Clone + Send,
{
warp::any().map(move || store.clone())
}