Remove unnecessary boxing of filters

This might help with error handling, knowing what filter are fallible or not
This commit is contained in:
Quentin Gliech
2021-08-05 17:46:46 +02:00
parent 146a7e9005
commit 0abc40817d
14 changed files with 88 additions and 82 deletions

View File

@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::convert::Infallible;
use chacha20poly1305::{
aead::{generic_array::GenericArray, Aead, NewAead},
ChaCha20Poly1305,
@@ -66,32 +68,34 @@ impl EncryptedCookie {
}
}
pub fn maybe_encrypted<T>(name: &'static str, options: &CookiesConfig) -> BoxedFilter<(Option<T>,)>
pub fn maybe_encrypted<T>(
name: &'static str,
options: &CookiesConfig,
) -> impl Filter<Extract = (Option<T>,), Error = Infallible> + Clone + Send + Sync + 'static
where
T: DeserializeOwned + Send + 'static,
{
let secret = options.secret;
warp::cookie::optional(name)
.map(move |maybe_value: Option<String>| {
maybe_value
.and_then(|value| EncryptedCookie::from_cookie_value(&value).ok())
.and_then(|encrypted| encrypted.decrypt(&secret).ok())
})
.boxed()
warp::cookie::optional(name).map(move |maybe_value: Option<String>| {
maybe_value
.and_then(|value| EncryptedCookie::from_cookie_value(&value).ok())
.and_then(|encrypted| encrypted.decrypt(&secret).ok())
})
}
pub fn encrypted<T>(name: &'static str, options: &CookiesConfig) -> BoxedFilter<(T,)>
pub fn encrypted<T>(
name: &'static str,
options: &CookiesConfig,
) -> impl Filter<Extract = (T,), Error = Rejection> + Clone + Send + Sync + 'static
where
T: DeserializeOwned + Send + 'static,
{
let secret = options.secret;
warp::cookie::cookie(name)
.and_then(move |value: String| async move {
let encrypted = EncryptedCookie::from_cookie_value(&value).wrap_error()?;
let decrypted = encrypted.decrypt(&secret).wrap_error()?;
Ok::<_, Rejection>(decrypted)
})
.boxed()
warp::cookie::cookie(name).and_then(move |value: String| async move {
let encrypted = EncryptedCookie::from_cookie_value(&value).wrap_error()?;
let decrypted = encrypted.decrypt(&secret).wrap_error()?;
Ok::<_, Rejection>(decrypted)
})
}
pub struct WithTypedHeader<R, H> {

View File

@@ -95,22 +95,22 @@ impl<T> CsrfForm<T> {
}
}
pub fn csrf_token(cookies_config: &CookiesConfig) -> BoxedFilter<(CsrfToken,)> {
super::cookies::encrypted("csrf", cookies_config)
.and_then(move |token: CsrfToken| async move {
let verified = token.verify_expiration().wrap_error()?;
Ok::<_, Rejection>(verified)
})
.boxed()
pub fn csrf_token(
cookies_config: &CookiesConfig,
) -> impl Filter<Extract = (CsrfToken,), Error = Rejection> + Clone + Send + Sync + 'static {
super::cookies::encrypted("csrf", cookies_config).and_then(move |token: CsrfToken| async move {
let verified = token.verify_expiration().wrap_error()?;
Ok::<_, Rejection>(verified)
})
}
pub fn updated_csrf_token(
cookies_config: &CookiesConfig,
csrf_config: &CsrfConfig,
) -> BoxedFilter<(CsrfToken,)> {
) -> impl Filter<Extract = (CsrfToken,), Error = Rejection> + Clone + Send + Sync + 'static {
let ttl = csrf_config.ttl;
super::cookies::maybe_encrypted("csrf", cookies_config)
.and_then(move |maybe_token: Option<CsrfToken>| async move {
super::cookies::maybe_encrypted("csrf", cookies_config).and_then(
move |maybe_token: Option<CsrfToken>| async move {
// Explicitely specify the "Error" type here to have the `?` operation working
Ok::<_, Rejection>(
maybe_token
@@ -123,8 +123,8 @@ pub fn updated_csrf_token(
|token| token.refresh(ttl),
),
)
})
.boxed()
},
)
}
pub fn save_csrf_token<R: Reply, F>(
@@ -136,17 +136,16 @@ where
save_encrypted("csrf", cookies_config)
}
pub fn protected_form<T>(cookies_config: &CookiesConfig) -> BoxedFilter<(T,)>
pub fn protected_form<T>(
cookies_config: &CookiesConfig,
) -> impl Filter<Extract = (T,), Error = Rejection> + Clone + Send + Sync + 'static
where
T: DeserializeOwned + Send + 'static,
{
csrf_token(cookies_config)
.and(warp::body::form())
.and_then(
|csrf_token: CsrfToken, protected_form: CsrfForm<T>| async move {
let form = protected_form.verify_csrf(&csrf_token).wrap_error()?;
Ok::<_, Rejection>(form)
},
)
.boxed()
csrf_token(cookies_config).and(warp::body::form()).and_then(
|csrf_token: CsrfToken, protected_form: CsrfForm<T>| async move {
let form = protected_form.verify_csrf(&csrf_token).wrap_error()?;
Ok::<_, Rejection>(form)
},
)
}

View File

@@ -17,18 +17,24 @@ pub mod csrf;
pub mod cookies;
pub mod session;
use std::convert::Infallible;
use sqlx::PgPool;
use warp::{filters::BoxedFilter, Filter};
use warp::Filter;
pub use self::csrf::CsrfToken;
use crate::templates::Templates;
pub fn with_pool(pool: &PgPool) -> BoxedFilter<(PgPool,)> {
pub fn with_pool(
pool: &PgPool,
) -> impl Filter<Extract = (PgPool,), Error = Infallible> + Clone + Send + Sync + 'static {
let pool = pool.clone();
warp::any().map(move || pool.clone()).boxed()
warp::any().map(move || pool.clone())
}
pub fn with_templates(templates: &Templates) -> BoxedFilter<(Templates,)> {
pub fn with_templates(
templates: &Templates,
) -> impl Filter<Extract = (Templates,), Error = Infallible> + Clone + Send + Sync + 'static {
let templates = templates.clone();
warp::any().map(move || templates.clone()).boxed()
warp::any().map(move || templates.clone())
}

View File

@@ -50,7 +50,8 @@ impl Session {
pub fn with_optional_session(
pool: &PgPool,
cookies_config: &CookiesConfig,
) -> BoxedFilter<(Option<SessionInfo>,)> {
) -> impl Filter<Extract = (Option<SessionInfo>,), Error = Rejection> + Clone + Send + Sync + 'static
{
maybe_encrypted("session", cookies_config)
.and(with_pool(pool))
.and_then(|maybe_session: Option<Session>, pool: PgPool| async move {
@@ -61,17 +62,18 @@ pub fn with_optional_session(
};
Ok::<_, Rejection>(maybe_session_info)
})
.boxed()
}
pub fn with_session(pool: &PgPool, cookies_config: &CookiesConfig) -> BoxedFilter<(SessionInfo,)> {
pub fn with_session(
pool: &PgPool,
cookies_config: &CookiesConfig,
) -> impl Filter<Extract = (SessionInfo,), Error = Rejection> + Clone + Send + Sync + 'static {
encrypted("session", cookies_config)
.and(with_pool(pool))
.and_then(|session: Session, pool: PgPool| async move {
let session_info = session.load_session_info(&pool).await.wrap_error()?;
Ok::<_, Rejection>(session_info)
})
.boxed()
}
pub fn save_session<R: Reply, F>(

View File

@@ -16,16 +16,17 @@ use hyper::header::CONTENT_TYPE;
use mime::TEXT_PLAIN;
use sqlx::PgPool;
use tracing::{info_span, Instrument};
use warp::{filters::BoxedFilter, reply::with_header, Filter, Rejection, Reply};
use warp::{reply::with_header, Filter, Rejection, Reply};
use crate::{errors::WrapError, filters::with_pool};
pub fn filter(pool: &PgPool) -> BoxedFilter<(impl Reply,)> {
pub fn filter(
pool: &PgPool,
) -> impl Filter<Extract = (impl Reply,), Error = Rejection> + Clone + Send + Sync + 'static {
warp::get()
.and(warp::path("health"))
.and(with_pool(pool))
.and_then(get)
.boxed()
}
async fn get(pool: PgPool) -> Result<impl Reply, Rejection> {

View File

@@ -13,7 +13,7 @@
// limitations under the License.
use sqlx::PgPool;
use warp::{filters::BoxedFilter, Filter};
use warp::{Filter, Rejection, Reply};
use crate::{config::RootConfig, templates::Templates};
@@ -27,11 +27,10 @@ pub fn root(
pool: &PgPool,
templates: &Templates,
config: &RootConfig,
) -> BoxedFilter<(impl warp::Reply,)> {
) -> impl Filter<Extract = (impl Reply,), Error = Rejection> + Clone + Send + Sync + 'static {
health(pool)
.or(oauth2(pool, &config.oauth2, &config.cookies))
.or(views(pool, templates, &config.csrf, &config.cookies))
//.or(warp::get().map(|| StatusCode::NOT_FOUND)) <- This messes up the error reporting
.with(warp::log(module_path!()))
.boxed()
}

View File

@@ -20,7 +20,7 @@ use oauth2_types::{
};
use serde::Deserialize;
use sqlx::PgPool;
use warp::{filters::BoxedFilter, Filter, Rejection, Reply};
use warp::{Filter, Rejection, Reply};
use crate::{
config::{CookiesConfig, OAuth2ClientConfig, OAuth2Config},
@@ -42,7 +42,7 @@ pub fn filter(
pool: &PgPool,
oauth2_config: &OAuth2Config,
cookies_config: &CookiesConfig,
) -> BoxedFilter<(impl Reply,)> {
) -> impl Filter<Extract = (impl Reply,), Error = Rejection> + Clone + Send + Sync + 'static {
let clients = oauth2_config.clients.clone();
warp::get()
.and(warp::path!("oauth2" / "authorize"))
@@ -51,7 +51,6 @@ pub fn filter(
.and(with_optional_session(pool, cookies_config))
.and(with_pool(pool))
.and_then(get)
.boxed()
}
async fn get(

View File

@@ -13,11 +13,13 @@
// limitations under the License.
use oauth2_types::oidc::Metadata;
use warp::{filters::BoxedFilter, Filter, Reply};
use warp::{Filter, Rejection, Reply};
use crate::config::OAuth2Config;
pub(super) fn filter(config: &OAuth2Config) -> BoxedFilter<(impl Reply,)> {
pub(super) fn filter(
config: &OAuth2Config,
) -> impl Filter<Extract = (impl Reply,), Error = Rejection> + Clone + Send + Sync + 'static {
let base = config.issuer.clone();
let metadata = Metadata {
authorization_endpoint: base.join("oauth2/authorize").ok(),
@@ -38,5 +40,4 @@ pub(super) fn filter(config: &OAuth2Config) -> BoxedFilter<(impl Reply,)> {
.and(warp::path!(".well-known" / "openid-configuration"))
.map(move || warp::reply::json(&metadata))
.with(cors)
.boxed()
}

View File

@@ -13,7 +13,7 @@
// limitations under the License.
use sqlx::PgPool;
use warp::{filters::BoxedFilter, Filter, Reply};
use warp::{Filter, Rejection, Reply};
use crate::config::{CookiesConfig, OAuth2Config};
@@ -26,8 +26,6 @@ pub fn filter(
pool: &PgPool,
oauth2_config: &OAuth2Config,
cookies_config: &CookiesConfig,
) -> BoxedFilter<(impl Reply,)> {
discovery(oauth2_config)
.or(authorization(pool, oauth2_config, cookies_config))
.boxed()
) -> impl Filter<Extract = (impl Reply,), Error = Rejection> + Clone + Send + Sync + 'static {
discovery(oauth2_config).or(authorization(pool, oauth2_config, cookies_config))
}

View File

@@ -13,7 +13,7 @@
// limitations under the License.
use sqlx::PgPool;
use warp::{filters::BoxedFilter, reply::with_header, wrap_fn, Filter, Rejection, Reply};
use warp::{reply::with_header, wrap_fn, Filter, Rejection, Reply};
use crate::{
config::{CookiesConfig, CsrfConfig},
@@ -31,7 +31,7 @@ pub(super) fn filter(
templates: &Templates,
csrf_config: &CsrfConfig,
cookies_config: &CookiesConfig,
) -> BoxedFilter<(impl Reply,)> {
) -> impl Filter<Extract = (impl Reply,), Error = Rejection> + Clone + Send + Sync + 'static {
warp::get()
.and(warp::path::end())
.and(with_templates(templates))
@@ -40,7 +40,6 @@ pub(super) fn filter(
.and_then(get)
.untuple_one()
.with(wrap_fn(save_csrf_token(cookies_config)))
.boxed()
}
async fn get(

View File

@@ -14,9 +14,7 @@
use serde::Deserialize;
use sqlx::PgPool;
use warp::{
filters::BoxedFilter, hyper::Uri, reply::with_header, wrap_fn, Filter, Rejection, Reply,
};
use warp::{hyper::Uri, reply::with_header, wrap_fn, Filter, Rejection, Reply};
use crate::{
config::{CookiesConfig, CsrfConfig},
@@ -41,7 +39,7 @@ pub(super) fn filter(
templates: &Templates,
csrf_config: &CsrfConfig,
cookies_config: &CookiesConfig,
) -> BoxedFilter<(impl Reply,)> {
) -> impl Filter<Extract = (impl Reply,), Error = Rejection> + Clone + Send + Sync + 'static {
let get = warp::get()
.and(with_templates(templates))
.and(updated_csrf_token(cookies_config, csrf_config))
@@ -56,7 +54,7 @@ pub(super) fn filter(
.untuple_one()
.with(wrap_fn(save_session(cookies_config)));
warp::path("login").and(get.or(post)).boxed()
warp::path("login").and(get.or(post))
}
async fn get(

View File

@@ -13,7 +13,7 @@
// limitations under the License.
use sqlx::PgPool;
use warp::{filters::BoxedFilter, hyper::Uri, Filter, Rejection, Reply};
use warp::{hyper::Uri, Filter, Rejection, Reply};
use crate::{
config::CookiesConfig,
@@ -22,14 +22,16 @@ use crate::{
storage::SessionInfo,
};
pub(super) fn filter(pool: &PgPool, cookies_config: &CookiesConfig) -> BoxedFilter<(impl Reply,)> {
pub(super) fn filter(
pool: &PgPool,
cookies_config: &CookiesConfig,
) -> impl Filter<Extract = (impl Reply,), Error = Rejection> + Clone + Send + Sync + 'static {
warp::post()
.and(warp::path("logout"))
.and(with_session(pool, cookies_config))
.and(with_pool(pool))
.and(protected_form(cookies_config))
.and_then(post)
.boxed()
}
async fn post(session: SessionInfo, pool: PgPool, _form: ()) -> Result<impl Reply, Rejection> {

View File

@@ -13,7 +13,7 @@
// limitations under the License.
use sqlx::PgPool;
use warp::{filters::BoxedFilter, Filter, Reply};
use warp::{Filter, Rejection, Reply};
use crate::{
config::{CookiesConfig, CsrfConfig},
@@ -35,7 +35,7 @@ pub(super) fn filter(
templates: &Templates,
csrf_config: &CsrfConfig,
cookies_config: &CookiesConfig,
) -> BoxedFilter<(impl Reply,)> {
) -> impl Filter<Extract = (impl Reply,), Error = Rejection> + Clone + Send + Sync + 'static {
index(pool, templates, csrf_config, cookies_config)
.or(login(pool, templates, csrf_config, cookies_config))
.or(logout(pool, cookies_config))

View File

@@ -14,9 +14,7 @@
use serde::Deserialize;
use sqlx::PgPool;
use warp::{
filters::BoxedFilter, hyper::Uri, reply::with_header, wrap_fn, Filter, Rejection, Reply,
};
use warp::{hyper::Uri, reply::with_header, wrap_fn, Filter, Rejection, Reply};
use crate::{
config::{CookiesConfig, CsrfConfig},
@@ -40,7 +38,7 @@ pub(super) fn filter(
templates: &Templates,
csrf_config: &CsrfConfig,
cookies_config: &CookiesConfig,
) -> BoxedFilter<(impl Reply,)> {
) -> impl Filter<Extract = (impl Reply,), Error = Rejection> + Clone + Send + Sync + 'static {
let get = warp::get()
.and(with_templates(templates))
.and(updated_csrf_token(cookies_config, csrf_config))
@@ -55,7 +53,7 @@ pub(super) fn filter(
.and(protected_form(cookies_config))
.and_then(post);
warp::path("reauth").and(get.or(post)).boxed()
warp::path("reauth").and(get.or(post))
}
async fn get(