some preparations for WebDav Push

This commit is contained in:
Lennart
2024-11-11 19:33:06 +01:00
parent b77a7f2a03
commit 6747fde623
8 changed files with 89 additions and 3 deletions

1
Cargo.lock generated
View File

@@ -2469,6 +2469,7 @@ dependencies = [
"rustical_dav",
"rustical_store",
"serde",
"sha2",
"strum",
"thiserror",
"tokio",

View File

@@ -25,3 +25,4 @@ url = { workspace = true }
rustical_dav = { workspace = true }
rustical_store = { workspace = true }
chrono = { workspace = true }
sha2 = { workspace = true }

View File

@@ -1,2 +1,3 @@
pub mod mkcalendar;
pub mod post;
pub mod report;

View File

@@ -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<C: CalendarStore + ?Sized>(
path: Path<(String, String)>,
body: String,
user: User,
store: Data<C>,
root_span: RootSpan,
) -> impl Responder {
"asd"
}

View File

@@ -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<TransportWrapper>,
}
impl Default for Transports {
fn default() -> Self {
Self {
transports: vec![TransportWrapper {
transport: Transport::WebPush,
}],
}
}
}

View File

@@ -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<C: CalendarStore + ?Sized> {
#[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<String>),
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<String>),
@@ -111,7 +126,7 @@ impl Resource for CalendarResource {
fn get_prop(
&self,
_rmap: &ResourceMap,
rmap: &ResourceMap,
_user: &User,
prop: &Self::PropName,
) -> Result<Self::Prop, Self::Error> {
@@ -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<C: CalendarStore + ?Sized> ResourceService for CalendarResourceService<C> {
res.route(report_method.to(route_report_calendar::<C>))
.route(mkcalendar_method.to(route_mkcalendar::<C>))
.post(route_post::<C>)
}
}

View File

@@ -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",

View File

@@ -79,6 +79,8 @@ pub struct MultistatusElement<PropType: Serialize, MemberPropType: Serialize> {
pub member_responses: Vec<ResponseElement<MemberPropType>>,
#[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<T1: Serialize, T2: Serialize> Default for MultistatusElement<T1, T2> {
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(),