diff --git a/crates/dav/src/header/depth.rs b/crates/dav/src/header/depth.rs index e8d7219..d06f9d6 100644 --- a/crates/dav/src/header/depth.rs +++ b/crates/dav/src/header/depth.rs @@ -1,6 +1,6 @@ use actix_web::{FromRequest, HttpRequest, ResponseError, http::StatusCode}; use futures_util::future::{Ready, err, ok}; -use rustical_xml::ValueSerialize; +use rustical_xml::{ValueDeserialize, ValueSerialize, XmlError}; use thiserror::Error; #[derive(Error, Debug)] @@ -25,12 +25,25 @@ impl ValueSerialize for Depth { match self { Depth::Zero => "0", Depth::One => "1", - Depth::Infinity => "Infinity", + Depth::Infinity => "infinity", } .to_owned() } } +impl ValueDeserialize for Depth { + fn deserialize(val: &str) -> Result { + match val { + "0" => Ok(Self::Zero), + "1" => Ok(Self::One), + "infinity" | "Infinity" => Ok(Self::Infinity), + _ => Err(XmlError::InvalidVariant( + "Invalid value for depth".to_owned(), + )), + } + } +} + impl TryFrom<&[u8]> for Depth { type Error = InvalidDepthHeader; diff --git a/crates/dav_push/src/extension.rs b/crates/dav_push/src/extension.rs index 2b0d28e..102a2f6 100644 --- a/crates/dav_push/src/extension.rs +++ b/crates/dav_push/src/extension.rs @@ -1,6 +1,6 @@ -use crate::{ContentUpdate, PropertyUpdate, SupportedTrigger, SupportedTriggers, Transports}; +use crate::{ContentUpdate, PropertyUpdate, SupportedTriggers, Transports, Trigger}; use rustical_dav::header::Depth; -use rustical_xml::{EnumUnitVariants, EnumVariants, XmlDeserialize, XmlSerialize}; +use rustical_xml::{EnumUnitVariants, EnumVariants, Unparsed, XmlDeserialize, XmlSerialize}; #[derive(XmlDeserialize, XmlSerialize, PartialEq, Clone, EnumUnitVariants, EnumVariants)] #[xml(unit_variants_ident = "DavPushExtensionPropName")] @@ -21,8 +21,8 @@ pub trait DavPushExtension { fn supported_triggers(&self) -> SupportedTriggers { SupportedTriggers(vec![ - SupportedTrigger::ContentUpdate(ContentUpdate(Depth::One)), - SupportedTrigger::PropertyUpdate(PropertyUpdate(Depth::One)), + Trigger::ContentUpdate(ContentUpdate(Depth::One)), + Trigger::PropertyUpdate(PropertyUpdate(Depth::One)), ]) } diff --git a/crates/dav_push/src/prop.rs b/crates/dav_push/src/prop.rs index f596562..3ffba18 100644 --- a/crates/dav_push/src/prop.rs +++ b/crates/dav_push/src/prop.rs @@ -1,5 +1,5 @@ use rustical_dav::header::Depth; -use rustical_xml::XmlSerialize; +use rustical_xml::{Unparsed, XmlDeserialize, XmlSerialize}; #[derive(Debug, Clone, XmlSerialize, PartialEq)] pub enum Transport { @@ -22,23 +22,39 @@ impl Default for Transports { } } -#[derive(XmlSerialize, PartialEq, Clone)] -pub struct SupportedTriggers(#[xml(flatten, ty = "untagged")] pub Vec); +#[derive(XmlSerialize, XmlDeserialize, PartialEq, Clone)] +pub struct SupportedTriggers(#[xml(flatten, ty = "untagged")] pub Vec); -#[derive(XmlSerialize, PartialEq, Clone)] -pub enum SupportedTrigger { +#[derive(XmlSerialize, XmlDeserialize, PartialEq, Debug, Clone)] +pub enum Trigger { #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] ContentUpdate(ContentUpdate), #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] PropertyUpdate(PropertyUpdate), } -#[derive(XmlSerialize, PartialEq, Clone)] +#[derive(XmlSerialize, XmlDeserialize, PartialEq, Clone, Debug)] pub struct ContentUpdate( #[xml(rename = b"depth", ns = "rustical_dav::namespace::NS_DAV")] pub Depth, ); -#[derive(XmlSerialize, PartialEq, Clone)] +#[derive(XmlSerialize, PartialEq, Clone, Debug)] pub struct PropertyUpdate( #[xml(rename = b"depth", ns = "rustical_dav::namespace::NS_DAV")] pub Depth, ); + +impl XmlDeserialize for PropertyUpdate { + fn deserialize( + reader: &mut quick_xml::NsReader, + start: &quick_xml::events::BytesStart, + empty: bool, + ) -> Result { + #[derive(XmlDeserialize, PartialEq, Clone, Debug)] + struct FakePropertyUpdate( + #[xml(rename = b"depth", ns = "rustical_dav::namespace::NS_DAV")] pub Depth, + #[xml(rename = b"prop", ns = "rustical_dav::namespace::NS_DAV")] pub Unparsed, + ); + let FakePropertyUpdate(depth, _) = FakePropertyUpdate::deserialize(reader, start, empty)?; + Ok(Self(depth)) + } +} diff --git a/crates/dav_push/src/register.rs b/crates/dav_push/src/register.rs index 44c40de..6179b6c 100644 --- a/crates/dav_push/src/register.rs +++ b/crates/dav_push/src/register.rs @@ -1,10 +1,25 @@ -use rustical_xml::{XmlDeserialize, XmlRootTag}; +use crate::Trigger; +use rustical_xml::{XmlDeserialize, XmlRootTag, XmlSerialize}; #[derive(XmlDeserialize, Clone, Debug, PartialEq)] #[xml(ns = "crate::namespace::NS_DAVPUSH")] pub struct WebPushSubscription { #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] pub push_resource: String, + #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] + pub content_encoding: String, + #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] + pub subscription_public_key: SubscriptionPublicKey, + #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] + pub auth_secret: String, +} + +#[derive(XmlDeserialize, Clone, Debug, PartialEq)] +pub struct SubscriptionPublicKey { + #[xml(ty = "attr", rename = b"type")] + ty: String, + #[xml(ty = "text")] + key: String, } #[derive(XmlDeserialize, Clone, Debug, PartialEq)] @@ -13,6 +28,9 @@ pub struct SubscriptionElement { pub web_push_subscription: WebPushSubscription, } +#[derive(XmlDeserialize, XmlSerialize, Clone, Debug, PartialEq)] +pub struct TriggerElement(#[xml(ty = "untagged", flatten)] Vec); + #[derive(XmlDeserialize, XmlRootTag, Clone, Debug, PartialEq)] #[xml(root = b"push-register")] #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] @@ -21,11 +39,16 @@ pub struct PushRegister { pub subscription: SubscriptionElement, #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] pub expires: Option, + #[xml(ns = "rustical_dav::namespace::NS_DAVPUSH")] + pub trigger: TriggerElement, } #[cfg(test)] mod tests { + use crate::{ContentUpdate, PropertyUpdate}; + use super::*; + use rustical_dav::header::Depth; use rustical_xml::XmlDocument; #[test] @@ -33,12 +56,27 @@ mod tests { let push_register = PushRegister::parse_str( r#" - + https://up.example.net/yohd4yai5Phiz1wi + aes128gcm + BCVxsr7N_eNgVRqvHtD0zTZsEc6-VV-JvLexhqUzORcxaOzi6-AYWXvTBHm4bjyPjs7Vd8pZGH6SRpkNtoIAiw4 + BTBZMqHH6r4Tts7J_aSIgg + + + infinity + + + 0 + + + + + + Wed, 20 Dec 2023 10:03:31 GMT "#, @@ -49,10 +87,17 @@ mod tests { PushRegister { subscription: SubscriptionElement { web_push_subscription: WebPushSubscription { - push_resource: "https://up.example.net/yohd4yai5Phiz1wi".to_owned() + push_resource: "https://up.example.net/yohd4yai5Phiz1wi".to_owned(), + content_encoding: "aes128gcm".to_owned(), + subscription_public_key: SubscriptionPublicKey { ty: "p256dh".to_owned(), key: "BCVxsr7N_eNgVRqvHtD0zTZsEc6-VV-JvLexhqUzORcxaOzi6-AYWXvTBHm4bjyPjs7Vd8pZGH6SRpkNtoIAiw4".to_owned() }, + auth_secret: "BTBZMqHH6r4Tts7J_aSIgg".to_owned() } }, - expires: Some("Wed, 20 Dec 2023 10:03:31 GMT".to_owned()) + expires: Some("Wed, 20 Dec 2023 10:03:31 GMT".to_owned()), + trigger: TriggerElement(vec![ + Trigger::ContentUpdate(ContentUpdate(Depth::Infinity)), + Trigger::PropertyUpdate(PropertyUpdate(Depth::Zero)), + ]) } ) }