From 6747fde623191061891f280e2e5f8f23b46bba17 Mon Sep 17 00:00:00 2001 From: Lennart <18233294+lennart-k@users.noreply.github.com> Date: Mon, 11 Nov 2024 19:33:06 +0100 Subject: [PATCH] some preparations for WebDav Push --- Cargo.lock | 1 + crates/caldav/Cargo.toml | 1 + crates/caldav/src/calendar/methods/mod.rs | 1 + crates/caldav/src/calendar/methods/post.rs | 15 ++++++++++ crates/caldav/src/calendar/prop.rs | 34 ++++++++++++++++++++++ crates/caldav/src/calendar/resource.rs | 34 ++++++++++++++++++++-- crates/dav/src/namespace.rs | 3 ++ crates/dav/src/xml/multistatus.rs | 3 ++ 8 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 crates/caldav/src/calendar/methods/post.rs diff --git a/Cargo.lock b/Cargo.lock index 025b5b7..f0e11c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2469,6 +2469,7 @@ dependencies = [ "rustical_dav", "rustical_store", "serde", + "sha2", "strum", "thiserror", "tokio", diff --git a/crates/caldav/Cargo.toml b/crates/caldav/Cargo.toml index 15b222a..c433cf3 100644 --- a/crates/caldav/Cargo.toml +++ b/crates/caldav/Cargo.toml @@ -25,3 +25,4 @@ url = { workspace = true } rustical_dav = { workspace = true } rustical_store = { workspace = true } chrono = { workspace = true } +sha2 = { workspace = true } diff --git a/crates/caldav/src/calendar/methods/mod.rs b/crates/caldav/src/calendar/methods/mod.rs index 436ff41..bd97f27 100644 --- a/crates/caldav/src/calendar/methods/mod.rs +++ b/crates/caldav/src/calendar/methods/mod.rs @@ -1,2 +1,3 @@ pub mod mkcalendar; +pub mod post; pub mod report; diff --git a/crates/caldav/src/calendar/methods/post.rs b/crates/caldav/src/calendar/methods/post.rs new file mode 100644 index 0000000..6ec18ee --- /dev/null +++ b/crates/caldav/src/calendar/methods/post.rs @@ -0,0 +1,15 @@ +use actix_web::{web::Data, web::Path, Responder}; +use rustical_store::{auth::User, CalendarStore}; +use tracing::instrument; +use tracing_actix_web::RootSpan; + +#[instrument(parent = root_span.id(), skip(store, root_span))] +pub async fn route_post( + path: Path<(String, String)>, + body: String, + user: User, + store: Data, + root_span: RootSpan, +) -> impl Responder { + "asd" +} diff --git a/crates/caldav/src/calendar/prop.rs b/crates/caldav/src/calendar/prop.rs index e1c5922..0485c13 100644 --- a/crates/caldav/src/calendar/prop.rs +++ b/crates/caldav/src/calendar/prop.rs @@ -86,3 +86,37 @@ impl Default for SupportedReportSet { } } } + +#[derive(Debug, Clone, Serialize, PartialEq)] +#[serde(rename_all = "kebab-case")] +pub enum Transport { + #[serde(rename = "P:web-push")] + WebPush, +} + +#[derive(Debug, Clone, Serialize, PartialEq)] +#[serde(rename_all = "kebab-case")] +pub struct TransportWrapper { + #[serde(rename = "$value")] + transport: Transport, +} + +#[derive(Debug, Clone, Serialize, PartialEq)] +#[serde(rename_all = "kebab-case")] +pub struct Transports { + // NOTE: Here we implement an older version of the spec since the new property name is not reflected + // in DAVx5 yet + // https://github.com/bitfireAT/webdav-push/commit/461259a2f2174454b2b00033419b11fac52b79e3 + #[serde(rename = "P:transport")] + transports: Vec, +} + +impl Default for Transports { + fn default() -> Self { + Self { + transports: vec![TransportWrapper { + transport: Transport::WebPush, + }], + } + } +} diff --git a/crates/caldav/src/calendar/resource.rs b/crates/caldav/src/calendar/resource.rs index ad62905..9197010 100644 --- a/crates/caldav/src/calendar/resource.rs +++ b/crates/caldav/src/calendar/resource.rs @@ -1,8 +1,9 @@ use super::methods::mkcalendar::route_mkcalendar; +use super::methods::post::route_post; use super::methods::report::route_report_calendar; use super::prop::{ SupportedCalendarComponent, SupportedCalendarComponentSet, SupportedCalendarData, - SupportedReportSet, + SupportedReportSet, Transports, }; use crate::calendar_object::resource::CalendarObjectResource; use crate::principal::PrincipalResource; @@ -12,6 +13,8 @@ use actix_web::http::Method; use actix_web::web; use actix_web::{web::Data, HttpRequest}; use async_trait::async_trait; +use base64::prelude::{BASE64_STANDARD, BASE64_URL_SAFE}; +use base64::Engine; use derive_more::derive::{From, Into}; use rustical_dav::privileges::UserPrivilegeSet; use rustical_dav::resource::{Resource, ResourceService}; @@ -19,6 +22,7 @@ use rustical_dav::xml::HrefElement; use rustical_store::auth::User; use rustical_store::{Calendar, CalendarStore}; use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; use std::str::FromStr; use std::sync::Arc; use strum::{EnumString, VariantNames}; @@ -33,13 +37,15 @@ pub struct CalendarResourceService { #[strum(serialize_all = "kebab-case")] pub enum CalendarPropName { Displayname, + Getcontenttype, + Transports, + Topic, CalendarColor, CalendarDescription, CalendarTimezone, CalendarOrder, SupportedCalendarComponentSet, SupportedCalendarData, - Getcontenttype, MaxResourceSize, SupportedReportSet, SyncToken, @@ -54,6 +60,15 @@ pub enum CalendarProp { Displayname(Option), Getcontenttype(String), + // WebDav Push + // NOTE: Here we implement an older version of the spec since the new property name is not reflected + // in DAVx5 yet + // https://github.com/bitfireAT/webdav-push/commit/461259a2f2174454b2b00033419b11fac52b79e3 + #[serde(skip_deserializing)] + #[serde(rename = "P:push-transports", alias = "push-transports")] + Transports(Transports), + Topic(String), + // CalDAV (RFC 4791) #[serde(rename = "IC:calendar-color", alias = "calendar-color")] CalendarColor(Option), @@ -111,7 +126,7 @@ impl Resource for CalendarResource { fn get_prop( &self, - _rmap: &ResourceMap, + rmap: &ResourceMap, _user: &User, prop: &Self::PropName, ) -> Result { @@ -146,6 +161,14 @@ impl Resource for CalendarResource { CalendarPropName::Getcontenttype => { CalendarProp::Getcontenttype("text/calendar;charset=utf-8".to_owned()) } + CalendarPropName::Transports => CalendarProp::Transports(Default::default()), + CalendarPropName::Topic => { + let url = CalendarResource::get_url(rmap, [&self.0.principal, &self.0.id]).unwrap(); + let mut hasher = Sha256::new(); + hasher.update(url); + let topic = format!("{:x}", hasher.finalize()); + CalendarProp::Topic(topic) + } CalendarPropName::MaxResourceSize => CalendarProp::MaxResourceSize(10000000), CalendarPropName::SupportedReportSet => { CalendarProp::SupportedReportSet(SupportedReportSet::default()) @@ -185,6 +208,8 @@ impl Resource for CalendarResource { } CalendarProp::SupportedCalendarData(_) => Err(rustical_dav::Error::PropReadOnly), CalendarProp::Getcontenttype(_) => Err(rustical_dav::Error::PropReadOnly), + CalendarProp::Transports(_) => Err(rustical_dav::Error::PropReadOnly), + CalendarProp::Topic(_) => Err(rustical_dav::Error::PropReadOnly), CalendarProp::MaxResourceSize(_) => Err(rustical_dav::Error::PropReadOnly), CalendarProp::SupportedReportSet(_) => Err(rustical_dav::Error::PropReadOnly), CalendarProp::SyncToken(_) => Err(rustical_dav::Error::PropReadOnly), @@ -222,6 +247,8 @@ impl Resource for CalendarResource { } CalendarPropName::SupportedCalendarData => Err(rustical_dav::Error::PropReadOnly), CalendarPropName::Getcontenttype => Err(rustical_dav::Error::PropReadOnly), + CalendarPropName::Transports => Err(rustical_dav::Error::PropReadOnly), + CalendarPropName::Topic => Err(rustical_dav::Error::PropReadOnly), CalendarPropName::MaxResourceSize => Err(rustical_dav::Error::PropReadOnly), CalendarPropName::SupportedReportSet => Err(rustical_dav::Error::PropReadOnly), CalendarPropName::SyncToken => Err(rustical_dav::Error::PropReadOnly), @@ -329,5 +356,6 @@ impl ResourceService for CalendarResourceService { res.route(report_method.to(route_report_calendar::)) .route(mkcalendar_method.to(route_mkcalendar::)) + .post(route_post::) } } diff --git a/crates/dav/src/namespace.rs b/crates/dav/src/namespace.rs index ff401b9..c48707a 100644 --- a/crates/dav/src/namespace.rs +++ b/crates/dav/src/namespace.rs @@ -5,6 +5,7 @@ use quick_xml::events::attributes::Attribute; // Can also generate appropriate attributes for quick_xml pub enum Namespace { Dav, + DavPush, CalDAV, CardDAV, ICal, @@ -16,6 +17,7 @@ impl Namespace { pub fn as_str(&self) -> &'static str { match self { Self::Dav => "DAV:", + Self::DavPush => "DAV:Push", Self::CalDAV => "urn:ietf:params:xml:ns:caldav", Self::CardDAV => "urn:ietf:params:xml:ns:carddav", Self::ICal => "http://apple.com/ns/ical/", @@ -28,6 +30,7 @@ impl Namespace { pub fn xml_attr(&self) -> &'static str { match self { Self::Dav => "xmlns", + Self::DavPush => "xmlns:P", Self::CalDAV => "xmlns:C", Self::CardDAV => "xmlns:CARD", Self::ICal => "xmlns:IC", diff --git a/crates/dav/src/xml/multistatus.rs b/crates/dav/src/xml/multistatus.rs index 1ff9aa2..b78df9a 100644 --- a/crates/dav/src/xml/multistatus.rs +++ b/crates/dav/src/xml/multistatus.rs @@ -79,6 +79,8 @@ pub struct MultistatusElement { pub member_responses: Vec>, #[serde(rename = "@xmlns")] pub ns_dav: &'static str, + #[serde(rename = "@xmlns:P")] + pub ns_davpush: &'static str, #[serde(rename = "@xmlns:C")] pub ns_caldav: &'static str, #[serde(rename = "@xmlns:IC")] @@ -97,6 +99,7 @@ impl Default for MultistatusElement { responses: vec![], member_responses: vec![], ns_dav: Namespace::Dav.as_str(), + ns_davpush: Namespace::DavPush.as_str(), ns_caldav: Namespace::CalDAV.as_str(), ns_ical: Namespace::ICal.as_str(), ns_calendarserver: Namespace::CServer.as_str(),