caldav: Add some access control-related properties and advertise calendar-proxy

This commit is contained in:
Lennart
2025-06-12 19:51:02 +02:00
parent feb8b3ff09
commit 0e2f08d7f2
4 changed files with 43 additions and 5 deletions

View File

@@ -50,7 +50,7 @@ impl<C: CalendarStore, S: SubscriptionStore> ResourceService for CalendarResourc
type Principal = User; type Principal = User;
type PrincipalUri = CalDavPrincipalUri; type PrincipalUri = CalDavPrincipalUri;
const DAV_HEADER: &str = "1, 3, access-control, calendar-access"; const DAV_HEADER: &str = "1, 3, access-control, calendar-access, calendar-proxy";
async fn get_resource( async fn get_resource(
&self, &self,

View File

@@ -2,7 +2,7 @@ use crate::Error;
use rustical_dav::extensions::CommonPropertiesExtension; use rustical_dav::extensions::CommonPropertiesExtension;
use rustical_dav::privileges::UserPrivilegeSet; use rustical_dav::privileges::UserPrivilegeSet;
use rustical_dav::resource::{PrincipalUri, Resource, ResourceName}; use rustical_dav::resource::{PrincipalUri, Resource, ResourceName};
use rustical_dav::xml::{Resourcetype, ResourcetypeInner}; use rustical_dav::xml::{Resourcetype, ResourcetypeInner, SupportedReportSet};
use rustical_store::auth::User; use rustical_store::auth::User;
mod service; mod service;
@@ -13,6 +13,7 @@ pub use prop::*;
#[derive(Clone)] #[derive(Clone)]
pub struct PrincipalResource { pub struct PrincipalResource {
principal: User, principal: User,
members: Vec<String>,
} }
impl ResourceName for PrincipalResource { impl ResourceName for PrincipalResource {
@@ -32,6 +33,11 @@ impl Resource for PrincipalResource {
Resourcetype(&[ Resourcetype(&[
ResourcetypeInner(Some(rustical_dav::namespace::NS_DAV), "collection"), ResourcetypeInner(Some(rustical_dav::namespace::NS_DAV), "collection"),
ResourcetypeInner(Some(rustical_dav::namespace::NS_DAV), "principal"), ResourcetypeInner(Some(rustical_dav::namespace::NS_DAV), "principal"),
// https://github.com/apple/ccs-calendarserver/blob/13c706b985fb728b9aab42dc0fef85aae21921c3/doc/Extensions/caldav-proxy.txt
ResourcetypeInner(
Some(rustical_dav::namespace::NS_CALENDARSERVER),
"calendar-proxy-write",
),
]) ])
} }
@@ -64,6 +70,14 @@ impl Resource for PrincipalResource {
PrincipalPropName::CalendarUserAddressSet => { PrincipalPropName::CalendarUserAddressSet => {
PrincipalProp::CalendarUserAddressSet(principal_url.into()) PrincipalProp::CalendarUserAddressSet(principal_url.into())
} }
PrincipalPropName::GroupMemberSet => {
PrincipalProp::GroupMemberSet(GroupMemberSet(
self.members
.iter()
.map(|principal| puri.principal_uri(principal).into())
.collect(),
))
}
PrincipalPropName::GroupMembership => { PrincipalPropName::GroupMembership => {
PrincipalProp::GroupMembership(GroupMembership( PrincipalProp::GroupMembership(GroupMembership(
self.principal self.principal
@@ -79,6 +93,9 @@ impl Resource for PrincipalResource {
puri.principal_collection().into(), puri.principal_collection().into(),
)) ))
} }
PrincipalPropName::SupportedReportSet => {
PrincipalProp::SupportedReportSet(SupportedReportSet::all())
}
}) })
} }
PrincipalPropWrapperName::Common(prop) => PrincipalPropWrapper::Common( PrincipalPropWrapperName::Common(prop) => PrincipalPropWrapper::Common(

View File

@@ -1,6 +1,10 @@
use rustical_dav::{extensions::CommonPropertiesProp, xml::HrefElement}; use rustical_dav::{
extensions::CommonPropertiesProp,
xml::{HrefElement, SupportedReportSet},
};
use rustical_store::auth::user::PrincipalType; use rustical_store::auth::user::PrincipalType;
use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize}; use rustical_xml::{EnumVariants, PropName, XmlDeserialize, XmlSerialize};
use strum_macros::VariantArray;
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)] #[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumVariants, PropName)]
#[xml(unit_variants_ident = "PrincipalPropName")] #[xml(unit_variants_ident = "PrincipalPropName")]
@@ -16,10 +20,14 @@ pub enum PrincipalProp {
PrincipalUrl(HrefElement), PrincipalUrl(HrefElement),
#[xml(ns = "rustical_dav::namespace::NS_DAV")] #[xml(ns = "rustical_dav::namespace::NS_DAV")]
GroupMembership(GroupMembership), GroupMembership(GroupMembership),
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
GroupMemberSet(GroupMemberSet),
#[xml(ns = "rustical_dav::namespace::NS_DAV", rename = b"alternate-URI-set")] #[xml(ns = "rustical_dav::namespace::NS_DAV", rename = b"alternate-URI-set")]
AlternateUriSet, AlternateUriSet,
#[xml(ns = "rustical_dav::namespace::NS_DAV")] #[xml(ns = "rustical_dav::namespace::NS_DAV")]
PrincipalCollectionSet(PrincipalCollectionSet), PrincipalCollectionSet(PrincipalCollectionSet),
#[xml(ns = "rustical_dav::namespace::NS_DAV", skip_deserializing)]
SupportedReportSet(SupportedReportSet<ReportMethod>),
// CalDAV (RFC 4791) // CalDAV (RFC 4791)
#[xml(ns = "rustical_dav::namespace::NS_CALDAV")] #[xml(ns = "rustical_dav::namespace::NS_CALDAV")]
@@ -39,5 +47,15 @@ pub struct CalendarHomeSet(#[xml(ty = "untagged", flatten)] pub(super) Vec<HrefE
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone)] #[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone)]
pub struct GroupMembership(#[xml(ty = "untagged", flatten)] pub(super) Vec<HrefElement>); pub struct GroupMembership(#[xml(ty = "untagged", flatten)] pub(super) Vec<HrefElement>);
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone)]
pub struct GroupMemberSet(#[xml(ty = "untagged", flatten)] pub(super) Vec<HrefElement>);
#[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone)] #[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone)]
pub struct PrincipalCollectionSet(#[xml(ty = "untagged")] pub(super) HrefElement); pub struct PrincipalCollectionSet(#[xml(ty = "untagged")] pub(super) HrefElement);
#[derive(XmlSerialize, PartialEq, Clone, VariantArray)]
pub enum ReportMethod {
// We don't actually support principal-match
#[xml(ns = "rustical_dav::namespace::NS_DAV")]
PrincipalMatch,
}

View File

@@ -43,7 +43,7 @@ impl<AP: AuthenticationProvider, S: SubscriptionStore, CS: CalendarStore> Resour
type Principal = User; type Principal = User;
type PrincipalUri = CalDavPrincipalUri; type PrincipalUri = CalDavPrincipalUri;
const DAV_HEADER: &str = "1, 3, access-control, calendar-access"; const DAV_HEADER: &str = "1, 3, access-control, calendar-access, calendar-proxy";
async fn get_resource( async fn get_resource(
&self, &self,
@@ -54,7 +54,10 @@ impl<AP: AuthenticationProvider, S: SubscriptionStore, CS: CalendarStore> Resour
.get_principal(principal) .get_principal(principal)
.await? .await?
.ok_or(crate::Error::NotFound)?; .ok_or(crate::Error::NotFound)?;
Ok(PrincipalResource { principal: user }) Ok(PrincipalResource {
members: self.auth_provider.list_members(&user.id).await?,
principal: user,
})
} }
async fn get_members( async fn get_members(