From d10710326da703f69eaa06723dc66e330fd32745 Mon Sep 17 00:00:00 2001 From: Vika Date: Wed, 1 Jan 2025 23:17:56 +0300 Subject: axum: 0.7.9 → 0.8.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some breaking changes. For better or for worse. The optional extractor breaking change is a double-edged sword, since not all extractors can be used with `Option` now, and you have to use `Result` even when you want to ignore an error coming from an extractor, such as `Query`. However, this allows catching errors on authorization extractors even in places where authorization is optional. Change-Id: I35f809d3adf27dbef0e7ee93dc1a7af178b7d014 --- src/frontend/mod.rs | 4 ++-- src/frontend/onboarding.rs | 3 ++- src/indieauth/mod.rs | 19 ++++++++++++++++--- src/indieauth/webauthn.rs | 4 ++-- src/lib.rs | 37 ++++++++++++------------------------- src/login.rs | 4 ++-- src/main.rs | 2 +- src/media/mod.rs | 5 +++-- src/micropub/mod.rs | 12 +++++++----- 9 files changed, 47 insertions(+), 43 deletions(-) (limited to 'src') diff --git a/src/frontend/mod.rs b/src/frontend/mod.rs index 9abbcf1..8338ac6 100644 --- a/src/frontend/mod.rs +++ b/src/frontend/mod.rs @@ -1,10 +1,10 @@ use crate::database::{Storage, StorageError}; use axum::{ - extract::{Host, Query, State}, + extract::{Query, State}, http::{StatusCode, Uri}, response::IntoResponse, }; -use axum_extra::headers::HeaderMapExt; +use axum_extra::{extract::Host, headers::HeaderMapExt}; use futures_util::FutureExt; use serde::Deserialize; use std::convert::TryInto; diff --git a/src/frontend/onboarding.rs b/src/frontend/onboarding.rs index a8d2ae6..4588157 100644 --- a/src/frontend/onboarding.rs +++ b/src/frontend/onboarding.rs @@ -2,11 +2,12 @@ use std::sync::Arc; use crate::database::{settings, Storage}; use axum::{ - extract::{FromRef, Host, State}, + extract::{FromRef, State}, http::StatusCode, response::{Html, IntoResponse}, Json, }; +use axum_extra::extract::Host; use kittybox_frontend_renderer::{ErrorPage, OnboardingPage, Template}; use serde::Deserialize; use tokio::{task::JoinSet, sync::Mutex}; diff --git a/src/indieauth/mod.rs b/src/indieauth/mod.rs index 0ac3dfd..ab38715 100644 --- a/src/indieauth/mod.rs +++ b/src/indieauth/mod.rs @@ -3,10 +3,10 @@ use microformats::types::Class; use tracing::error; use serde::Deserialize; use axum::{ - extract::{Form, FromRef, Host, Json, Query, State}, http::StatusCode, response::{Html, IntoResponse, Response} + extract::{Form, FromRef, Json, Query, State}, http::StatusCode, response::{Html, IntoResponse, Response} }; #[cfg_attr(not(feature = "webauthn"), allow(unused_imports))] -use axum_extra::extract::cookie::{CookieJar, Cookie}; +use axum_extra::extract::{Host, cookie::{CookieJar, Cookie}}; use axum_extra::{headers::{authorization::Bearer, Authorization, ContentType, HeaderMapExt}, TypedHeader}; use crate::database::Storage; use kittybox_indieauth::{ @@ -65,7 +65,20 @@ impl axum::response::IntoResponse for IndieAuthResourceError { } } -#[async_trait::async_trait] +impl , St: Clone + Send + Sync + 'static> axum::extract::OptionalFromRequestParts for User { + type Rejection = >::Rejection; + + async fn from_request_parts(req: &mut axum::http::request::Parts, state: &St) -> Result, Self::Rejection> { + let res = >::from_request_parts(req, state).await; + + match res { + Ok(user) => Ok(Some(user)), + Err(IndieAuthResourceError::Unauthorized) => Ok(None), + Err(err) => Err(err), + } + } +} + impl , St: Clone + Send + Sync + 'static> axum::extract::FromRequestParts for User { type Rejection = IndieAuthResourceError; diff --git a/src/indieauth/webauthn.rs b/src/indieauth/webauthn.rs index b7d8c71..0757e72 100644 --- a/src/indieauth/webauthn.rs +++ b/src/indieauth/webauthn.rs @@ -1,9 +1,9 @@ use axum::{ - extract::{Json, Host}, + extract::Json, response::{IntoResponse, Response}, http::StatusCode, Extension }; -use axum_extra::extract::cookie::{CookieJar, Cookie}; +use axum_extra::extract::{Host, cookie::{CookieJar, Cookie}}; use axum_extra::{TypedHeader, headers::{authorization::Bearer, Authorization}}; use super::backend::AuthBackend; diff --git a/src/lib.rs b/src/lib.rs index 5fe3b18..e6bc24c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,8 +3,8 @@ use std::sync::Arc; -use axum::extract::{FromRef, FromRequestParts}; -use axum_extra::extract::{cookie::Key, SignedCookieJar}; +use axum::extract::{FromRef, FromRequestParts, OptionalFromRequestParts}; +use axum_extra::extract::{cookie::{Cookie, Key}, SignedCookieJar}; use database::{FileStorage, PostgresStorage, Storage}; use indieauth::backend::{AuthBackend, FileBackend as FileAuthBackend}; use kittybox_util::queue::JobQueue; @@ -64,36 +64,23 @@ impl axum::response::IntoResponse for NoSessionError { } } -#[async_trait::async_trait] -impl FromRequestParts for Session +impl OptionalFromRequestParts for Session where SessionStore: FromRef, Key: FromRef, S: Send + Sync, { - type Rejection = NoSessionError; + type Rejection = std::convert::Infallible; - async fn from_request_parts(parts: &mut axum::http::request::Parts, state: &S) -> Result { + async fn from_request_parts(parts: &mut axum::http::request::Parts, state: &S) -> Result, Self::Rejection> { let jar = SignedCookieJar::::from_request_parts(parts, state).await.unwrap(); let session_store = SessionStore::from_ref(state).read_owned().await; - tracing::debug!("Cookie jar: {:#?}", jar); - let cookie = match jar.get("session_id") { - Some(cookie) => { - tracing::debug!("Session ID cookie: {}", cookie); - cookie - }, - None => { return Err(NoSessionError) } - }; - - session_store.get( - &dbg!(cookie.value_trimmed()) - .parse() - .map_err(|err| { - tracing::error!("Error parsing cookie: {}", err); - NoSessionError - })? - ).cloned().ok_or(NoSessionError) + Ok(jar.get("session_id") + .as_ref() + .map(Cookie::value_trimmed) + .and_then(|id| uuid::Uuid::parse_str(id).ok()) + .and_then(|id| session_store.get(&id).cloned())) } } @@ -264,7 +251,7 @@ pub mod companion { axum::Router::new() .route( - "/:filename", + "/{filename}", axum::routing::get(map_to_static) .layer(Extension(resources)) ) @@ -309,7 +296,7 @@ St: Clone + Send + Sync + 'static .route("/.kittybox/health", get(health_check::)) .nest("/.kittybox/login", crate::login::router::()) .route( - "/.kittybox/static/:path", + "/.kittybox/static/{path}", axum::routing::get(crate::frontend::statics) ) .route("/.kittybox/coffee", get(teapot_route)) diff --git a/src/login.rs b/src/login.rs index 19bfaf7..eaa787c 100644 --- a/src/login.rs +++ b/src/login.rs @@ -1,8 +1,8 @@ use std::{borrow::Cow, str::FromStr}; use futures_util::FutureExt; -use axum::{extract::{FromRef, Host, Query, State}, http::HeaderValue, response::IntoResponse, Form}; -use axum_extra::{extract::{cookie::{self, Cookie}, SignedCookieJar}, headers::HeaderMapExt, TypedHeader}; +use axum::{extract::{FromRef, Query, State}, http::HeaderValue, response::IntoResponse, Form}; +use axum_extra::{extract::{Host, cookie::{self, Cookie}, SignedCookieJar}, headers::HeaderMapExt, TypedHeader}; use hyper::{header::{CACHE_CONTROL, LOCATION}, StatusCode}; use kittybox_frontend_renderer::{Template, LoginPage, LogoutPage}; use kittybox_indieauth::{AuthorizationResponse, Error, GrantType, PKCEVerifier, Scope, Scopes}; diff --git a/src/main.rs b/src/main.rs index f57b0be..bd3684e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -224,7 +224,7 @@ async fn main() { } }; - let mut servers: Vec> = vec![]; + let mut servers: Vec> = vec![]; let build_hyper = |tcp: std::net::TcpListener| { tracing::info!("Listening on {}", tcp.local_addr().unwrap()); diff --git a/src/media/mod.rs b/src/media/mod.rs index 3ed6810..199f05f 100644 --- a/src/media/mod.rs +++ b/src/media/mod.rs @@ -1,7 +1,8 @@ use axum::{ - extract::{multipart::Multipart, FromRef, Host, Path, State}, response::{IntoResponse, Response} + extract::{multipart::Multipart, FromRef, Path, State}, response::{IntoResponse, Response} }; use axum_extra::headers::{ContentLength, HeaderMapExt, HeaderValue, IfNoneMatch}; +use axum_extra::extract::Host; use axum_extra::TypedHeader; use kittybox_util::micropub::{Error as MicropubError, ErrorKind as ErrorType}; use kittybox_indieauth::Scope; @@ -132,5 +133,5 @@ pub fn router() -> axum::Router where { axum::Router::new() .route("/", axum::routing::post(upload::)) - .route("/uploads/*file", axum::routing::get(serve::)) + .route("/uploads/{*file}", axum::routing::get(serve::)) } diff --git a/src/micropub/mod.rs b/src/micropub/mod.rs index 621d4f9..719fbf0 100644 --- a/src/micropub/mod.rs +++ b/src/micropub/mod.rs @@ -6,8 +6,9 @@ use crate::database::{MicropubChannel, Storage, StorageError}; use crate::indieauth::backend::AuthBackend; use crate::indieauth::User; use crate::micropub::util::form_to_mf2_json; -use axum::extract::{FromRef, Host, Query, State}; +use axum::extract::{FromRef, Query, State}; use axum::body::Body as BodyStream; +use axum_extra::extract::Host; use axum_extra::headers::ContentType; use axum::response::{IntoResponse, Response}; use axum_extra::TypedHeader; @@ -603,13 +604,13 @@ pub(crate) async fn post( #[tracing::instrument(skip(db))] pub(crate) async fn query( State(db): State, - query: Option>, + query: Result, as axum::extract::FromRequestParts<()>>::Rejection>, Host(host): Host, user: User, ) -> axum::response::Response { // We handle the invalid query case manually to return a // MicropubError instead of HTTP 422 - let query = if let Some(Query(query)) = query { + let query = if let Ok(Query(query)) = query { query } else { return MicropubError::from_static( @@ -771,7 +772,8 @@ mod tests { use super::FetchedPostContext; use kittybox_indieauth::{Scopes, Scope, TokenData}; - use axum::extract::{Host, State}; + use axum::extract::State; + use axum_extra::extract::Host; #[test] fn test_populate_reply_context() { @@ -927,7 +929,7 @@ mod tests { async fn test_query_foreign_url() { let res = super::query( State(crate::database::MemoryStorage::default()), - Some(axum::extract::Query(super::MicropubQuery::source( + Ok(axum::extract::Query(super::MicropubQuery::source( "https://aaronparecki.com/feeds/main", ))), Host("aaronparecki.com".to_owned()), -- cgit 1.4.1