Compare commits

...

8 Commits

Author SHA1 Message Date
Lennart
de2a8a2a8e bump version to 0.8.6 2025-08-17 15:48:37 +02:00
Lennart
51d2293ff9 frontend: Show unauthorized messages instead of redirecting to the login screen for non-user resources 2025-08-17 15:47:35 +02:00
Lennart
5c77719ce4 Add log warning for failed login attempts 2025-08-17 15:38:29 +02:00
Lennart
91996465f9 ical: Remove unused generic around CalendarObject 2025-08-17 15:38:07 +02:00
Lennart
83f4506578 bump version to 0.8.5 2025-08-12 17:19:36 +02:00
Lennart
a5bbb82712 dav_push: Add TTL header to notifcation requests (thanks @drift8797)
see #108
2025-08-12 17:19:16 +02:00
Lennart
6a26f44dd7 bump version to 0.8.4 2025-08-10 14:01:25 +02:00
Lennart
f8a660c222 rename session cookie to rustical_session
To prevent possible clashes with other services, #105
2025-08-10 14:01:00 +02:00
7 changed files with 34 additions and 32 deletions

22
Cargo.lock generated
View File

@@ -3026,7 +3026,7 @@ dependencies = [
[[package]] [[package]]
name = "rustical" name = "rustical"
version = "0.8.3" version = "0.8.6"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"argon2", "argon2",
@@ -3069,7 +3069,7 @@ dependencies = [
[[package]] [[package]]
name = "rustical_caldav" name = "rustical_caldav"
version = "0.8.3" version = "0.8.6"
dependencies = [ dependencies = [
"async-std", "async-std",
"async-trait", "async-trait",
@@ -3109,7 +3109,7 @@ dependencies = [
[[package]] [[package]]
name = "rustical_carddav" name = "rustical_carddav"
version = "0.8.3" version = "0.8.6"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"axum", "axum",
@@ -3141,7 +3141,7 @@ dependencies = [
[[package]] [[package]]
name = "rustical_dav" name = "rustical_dav"
version = "0.8.3" version = "0.8.6"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"axum", "axum",
@@ -3166,7 +3166,7 @@ dependencies = [
[[package]] [[package]]
name = "rustical_dav_push" name = "rustical_dav_push"
version = "0.8.3" version = "0.8.6"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"axum", "axum",
@@ -3191,7 +3191,7 @@ dependencies = [
[[package]] [[package]]
name = "rustical_frontend" name = "rustical_frontend"
version = "0.8.3" version = "0.8.6"
dependencies = [ dependencies = [
"askama", "askama",
"askama_web", "askama_web",
@@ -3224,7 +3224,7 @@ dependencies = [
[[package]] [[package]]
name = "rustical_ical" name = "rustical_ical"
version = "0.8.3" version = "0.8.6"
dependencies = [ dependencies = [
"axum", "axum",
"chrono", "chrono",
@@ -3242,7 +3242,7 @@ dependencies = [
[[package]] [[package]]
name = "rustical_oidc" name = "rustical_oidc"
version = "0.8.3" version = "0.8.6"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"axum", "axum",
@@ -3257,7 +3257,7 @@ dependencies = [
[[package]] [[package]]
name = "rustical_store" name = "rustical_store"
version = "0.8.3" version = "0.8.6"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@@ -3291,7 +3291,7 @@ dependencies = [
[[package]] [[package]]
name = "rustical_store_sqlite" name = "rustical_store_sqlite"
version = "0.8.3" version = "0.8.6"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"chrono", "chrono",
@@ -3312,7 +3312,7 @@ dependencies = [
[[package]] [[package]]
name = "rustical_xml" name = "rustical_xml"
version = "0.8.3" version = "0.8.6"
dependencies = [ dependencies = [
"quick-xml", "quick-xml",
"thiserror 2.0.12", "thiserror 2.0.12",

View File

@@ -2,7 +2,7 @@
members = ["crates/*"] members = ["crates/*"]
[workspace.package] [workspace.package]
version = "0.8.3" version = "0.8.6"
edition = "2024" edition = "2024"
description = "A CalDAV server" description = "A CalDAV server"
repository = "https://github.com/lennart-k/rustical" repository = "https://github.com/lennart-k/rustical"

View File

@@ -183,6 +183,7 @@ impl<S: SubscriptionStore> DavPushController<S> {
header::CONTENT_TYPE, header::CONTENT_TYPE,
HeaderValue::from_static("application/octet-stream"), HeaderValue::from_static("application/octet-stream"),
); );
hdrs.insert("TTL", HeaderValue::from(60));
client.execute(request).await?; client.execute(request).await?;
Ok(()) Ok(())

View File

@@ -45,38 +45,38 @@ pub fn frontend_router<AP: AuthenticationProvider, CS: CalendarStore, AS: Addres
frontend_config: FrontendConfig, frontend_config: FrontendConfig,
oidc_config: Option<OidcConfig>, oidc_config: Option<OidcConfig>,
) -> Router { ) -> Router {
let mut router = Router::new(); let user_router = Router::new()
router = router .route("/", get(route_get_home))
.route("/", get(route_root)) .route("/{user}", get(route_user_named::<CS, AS, AP>))
.route("/user", get(route_get_home))
.route("/user/{user}", get(route_user_named::<CS, AS, AP>))
// App token management // App token management
.route("/user/{user}/app_token", post(route_post_app_token::<AP>)) .route("/{user}/app_token", post(route_post_app_token::<AP>))
.route( .route(
// POST because HTML5 forms don't support DELETE method // POST because HTML5 forms don't support DELETE method
"/user/{user}/app_token/{id}/delete", "/{user}/app_token/{id}/delete",
post(route_delete_app_token::<AP>), post(route_delete_app_token::<AP>),
) )
// Calendar // Calendar
.route("/user/{user}/calendar", get(route_calendars::<CS>)) .route("/{user}/calendar", get(route_calendars::<CS>))
.route("/{user}/calendar/{calendar}", get(route_calendar::<CS>))
.route( .route(
"/user/{user}/calendar/{calendar}", "/{user}/calendar/{calendar}/restore",
get(route_calendar::<CS>),
)
.route(
"/user/{user}/calendar/{calendar}/restore",
post(route_calendar_restore::<CS>), post(route_calendar_restore::<CS>),
) )
// Addressbook // Addressbook
.route("/user/{user}/addressbook", get(route_addressbooks::<AS>)) .route("/{user}/addressbook", get(route_addressbooks::<AS>))
.route( .route(
"/user/{user}/addressbook/{addressbook}", "/{user}/addressbook/{addressbook}",
get(route_addressbook::<AS>), get(route_addressbook::<AS>),
) )
.route( .route(
"/user/{user}/addressbook/{addressbook}/restore", "/{user}/addressbook/{addressbook}/restore",
post(route_addressbook_restore::<AS>), post(route_addressbook_restore::<AS>),
) )
.layer(middleware::from_fn(unauthorized_handler));
let router = Router::new()
.route("/", get(route_root))
.nest("/user", user_router)
.route("/login", get(route_get_login).post(route_post_login::<AP>)) .route("/login", get(route_get_login).post(route_post_login::<AP>))
.route("/logout", post(route_post_logout)); .route("/logout", post(route_post_logout));
@@ -109,8 +109,7 @@ pub fn frontend_router<AP: AuthenticationProvider, CS: CalendarStore, AS: Addres
.layer(Extension(cal_store.clone())) .layer(Extension(cal_store.clone()))
.layer(Extension(addr_store.clone())) .layer(Extension(addr_store.clone()))
.layer(Extension(frontend_config.clone())) .layer(Extension(frontend_config.clone()))
.layer(Extension(oidc_config.clone())) .layer(Extension(oidc_config.clone()));
.layer(middleware::from_fn(unauthorized_handler));
Router::new() Router::new()
.nest(prefix, router) .nest(prefix, router)

View File

@@ -13,7 +13,7 @@ use http::StatusCode;
use rustical_store::auth::AuthenticationProvider; use rustical_store::auth::AuthenticationProvider;
use serde::Deserialize; use serde::Deserialize;
use tower_sessions::Session; use tower_sessions::Session;
use tracing::instrument; use tracing::{instrument, warn};
use url::Url; use url::Url;
#[derive(Template, WebTemplate)] #[derive(Template, WebTemplate)]
@@ -98,6 +98,7 @@ pub async fn route_post_login<AP: AuthenticationProvider>(
session.insert("user", user.id).await.unwrap(); session.insert("user", user.id).await.unwrap();
Redirect::to(&redirect_uri).into_response() Redirect::to(&redirect_uri).into_response()
} else { } else {
warn!("Failed password login attempt as {username}");
StatusCode::UNAUTHORIZED.into_response() StatusCode::UNAUTHORIZED.into_response()
} }
} }

View File

@@ -67,7 +67,7 @@ impl Default for CalendarObjectComponent {
} }
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct CalendarObject<const VERIFIED: bool = true> { pub struct CalendarObject {
data: CalendarObjectComponent, data: CalendarObjectComponent,
properties: Vec<Property>, properties: Vec<Property>,
ics: String, ics: String,

View File

@@ -126,6 +126,7 @@ pub fn make_app<AS: AddressbookStore, CS: CalendarStore, S: SubscriptionStore>(
router router
.layer( .layer(
SessionManagerLayer::new(session_store) SessionManagerLayer::new(session_store)
.with_name("rustical_session")
.with_secure(true) .with_secure(true)
.with_same_site(SameSite::Strict) .with_same_site(SameSite::Strict)
.with_expiry(Expiry::OnInactivity( .with_expiry(Expiry::OnInactivity(