Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f Enterprise-only files removed or emptied: 63 Enterprise-only snippets removed: 117 in 50 files Dangling module declarations removed: 5 Cargo edits turning enterprise off: 14 Verification: clean Enterprise feature gates left for rebuilt features: 19 in 18 files Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
470 lines
16 KiB
Rust
470 lines
16 KiB
Rust
/*
|
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
|
*/
|
|
|
|
use crate::{
|
|
parser::{DavParser, Token, tokenizer::Tokenizer},
|
|
schema::{
|
|
Element, NamedElement, Namespace,
|
|
property::{DavValue, Privilege},
|
|
request::{
|
|
Acl, AclPrincipalPropSet, DavPropertyValue, PrincipalMatch, PrincipalMatchProperties,
|
|
PrincipalPropertySearch, PropertySearch,
|
|
},
|
|
response::{Ace, GrantDeny, Href, List, Principal},
|
|
},
|
|
};
|
|
|
|
impl DavParser for Acl {
|
|
fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
|
|
stream.expect_named_element(NamedElement::dav(Element::Acl))?;
|
|
|
|
let mut acl = Acl { aces: vec![] };
|
|
|
|
loop {
|
|
match stream.token()? {
|
|
Token::ElementStart {
|
|
name:
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element: Element::Ace,
|
|
},
|
|
..
|
|
} => {
|
|
acl.aces.push(Ace::parse(stream)?);
|
|
}
|
|
Token::ElementEnd => {
|
|
break;
|
|
}
|
|
Token::UnknownElement(_) => {
|
|
stream.seek_element_end()?;
|
|
}
|
|
other => {
|
|
return Err(other.into_unexpected());
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(acl)
|
|
}
|
|
}
|
|
|
|
impl DavParser for Ace {
|
|
fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
|
|
let mut ace = Ace {
|
|
principal: Principal::All,
|
|
invert: false,
|
|
grant_deny: GrantDeny::Grant(List(vec![])),
|
|
protected: false,
|
|
inherited: None,
|
|
};
|
|
let mut depth = 1;
|
|
|
|
loop {
|
|
match stream.token()? {
|
|
Token::ElementStart {
|
|
name:
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element: Element::Principal,
|
|
},
|
|
..
|
|
} => {
|
|
ace.principal = Principal::parse(stream)?;
|
|
}
|
|
Token::ElementStart {
|
|
name:
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element: Element::Invert,
|
|
},
|
|
..
|
|
} if depth == 1 => {
|
|
ace.invert = true;
|
|
depth += 1;
|
|
}
|
|
Token::ElementStart {
|
|
name:
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element: Element::Protected,
|
|
},
|
|
..
|
|
} if depth == 1 => {
|
|
ace.protected = true;
|
|
stream.expect_element_end()?;
|
|
}
|
|
Token::ElementStart {
|
|
name:
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element: Element::Inherited,
|
|
},
|
|
..
|
|
} if depth == 1 => {
|
|
stream.expect_named_element(NamedElement::dav(Element::Href))?;
|
|
ace.inherited = stream.collect_string_value()?.map(Href);
|
|
stream.expect_element_end()?;
|
|
}
|
|
Token::ElementStart {
|
|
name:
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element: Element::Grant,
|
|
},
|
|
..
|
|
} if depth == 1 => {
|
|
ace.grant_deny = GrantDeny::Grant(List(stream.collect_privileges()?));
|
|
}
|
|
Token::ElementStart {
|
|
name:
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element: Element::Deny,
|
|
},
|
|
..
|
|
} if depth == 1 => {
|
|
ace.grant_deny = GrantDeny::Deny(List(stream.collect_privileges()?));
|
|
}
|
|
Token::ElementEnd => {
|
|
depth -= 1;
|
|
if depth == 0 {
|
|
break;
|
|
}
|
|
}
|
|
Token::UnknownElement(_) => {
|
|
stream.seek_element_end()?;
|
|
}
|
|
other => {
|
|
return Err(other.into_unexpected());
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(ace)
|
|
}
|
|
}
|
|
|
|
impl DavParser for Principal {
|
|
fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
|
|
let result = match stream.unwrap_named_element()? {
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element: Element::Href,
|
|
} => Principal::Href(Href(stream.collect_string_value()?.unwrap_or_default())),
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element: Element::All,
|
|
} => {
|
|
stream.expect_element_end()?;
|
|
Principal::All
|
|
}
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element: Element::Authenticated,
|
|
} => {
|
|
stream.expect_element_end()?;
|
|
Principal::Authenticated
|
|
}
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element: Element::Unauthenticated,
|
|
} => {
|
|
stream.expect_element_end()?;
|
|
Principal::Unauthenticated
|
|
}
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element: Element::Property,
|
|
} => {
|
|
let property = stream.collect_properties(Vec::new())?;
|
|
Principal::Property(List(
|
|
property
|
|
.into_iter()
|
|
.map(|prop| DavPropertyValue::new(prop, DavValue::Null))
|
|
.collect(),
|
|
))
|
|
}
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element: Element::Self_,
|
|
} => {
|
|
stream.expect_element_end()?;
|
|
Principal::Self_
|
|
}
|
|
other => return Err(other.into_unexpected()),
|
|
};
|
|
stream.expect_element_end()?;
|
|
Ok(result)
|
|
}
|
|
}
|
|
|
|
impl Tokenizer<'_> {
|
|
pub fn collect_privileges(&mut self) -> crate::parser::Result<Vec<Privilege>> {
|
|
let mut privileges = Vec::new();
|
|
let mut depth = 1;
|
|
|
|
loop {
|
|
match self.token()? {
|
|
Token::ElementStart { name, .. } => {
|
|
if let Some(privilege) = Privilege::from_element(name) {
|
|
privileges.push(privilege);
|
|
self.expect_element_end()?;
|
|
} else {
|
|
depth += 1;
|
|
}
|
|
}
|
|
Token::ElementEnd => {
|
|
depth -= 1;
|
|
if depth == 0 {
|
|
break;
|
|
}
|
|
}
|
|
Token::UnknownElement(_) => {
|
|
self.seek_element_end()?;
|
|
}
|
|
other => {
|
|
return Err(other.into_unexpected());
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(privileges)
|
|
}
|
|
}
|
|
|
|
impl Privilege {
|
|
pub fn from_element(element: NamedElement) -> Option<Self> {
|
|
match (element.ns, element.element) {
|
|
(Namespace::Dav, Element::Read) => Some(Privilege::Read),
|
|
(Namespace::Dav, Element::Write) => Some(Privilege::Write),
|
|
(Namespace::Dav, Element::WriteProperties) => Some(Privilege::WriteProperties),
|
|
(Namespace::Dav, Element::WriteContent) => Some(Privilege::WriteContent),
|
|
(Namespace::Dav, Element::Unlock) => Some(Privilege::Unlock),
|
|
(Namespace::Dav, Element::ReadAcl) => Some(Privilege::ReadAcl),
|
|
(Namespace::Dav, Element::ReadCurrentUserPrivilegeSet) => {
|
|
Some(Privilege::ReadCurrentUserPrivilegeSet)
|
|
}
|
|
(Namespace::Dav, Element::WriteAcl) => Some(Privilege::WriteAcl),
|
|
(Namespace::Dav, Element::Bind) => Some(Privilege::Bind),
|
|
(Namespace::Dav, Element::Unbind) => Some(Privilege::Unbind),
|
|
(Namespace::Dav, Element::All) => Some(Privilege::All),
|
|
(Namespace::CalDav, Element::ReadFreeBusy) => Some(Privilege::ReadFreeBusy),
|
|
(Namespace::CalDav, Element::ScheduleDeliver) => Some(Privilege::ScheduleDeliver),
|
|
(Namespace::CalDav, Element::ScheduleDeliverInvite) => {
|
|
Some(Privilege::ScheduleDeliverInvite)
|
|
}
|
|
(Namespace::CalDav, Element::ScheduleDeliverReply) => {
|
|
Some(Privilege::ScheduleDeliverReply)
|
|
}
|
|
(Namespace::CalDav, Element::ScheduleQueryFreebusy) => {
|
|
Some(Privilege::ScheduleQueryFreeBusy)
|
|
}
|
|
(Namespace::CalDav, Element::ScheduleSend) => Some(Privilege::ScheduleSend),
|
|
(Namespace::CalDav, Element::ScheduleSendInvite) => Some(Privilege::ScheduleSendInvite),
|
|
(Namespace::CalDav, Element::ScheduleSendReply) => Some(Privilege::ScheduleSendReply),
|
|
(Namespace::CalDav, Element::ScheduleSendFreebusy) => {
|
|
Some(Privilege::ScheduleSendFreeBusy)
|
|
}
|
|
_ => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl DavParser for AclPrincipalPropSet {
|
|
fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
|
|
let mut acps = AclPrincipalPropSet { properties: vec![] };
|
|
|
|
loop {
|
|
match stream.token()? {
|
|
Token::ElementStart {
|
|
name:
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element: Element::Prop,
|
|
},
|
|
..
|
|
} => {
|
|
acps.properties = stream.collect_properties(acps.properties)?;
|
|
}
|
|
Token::ElementEnd => {
|
|
break;
|
|
}
|
|
Token::UnknownElement(_) => {
|
|
stream.seek_element_end()?;
|
|
}
|
|
other => {
|
|
return Err(other.into_unexpected());
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(acps)
|
|
}
|
|
}
|
|
|
|
impl DavParser for PrincipalMatch {
|
|
fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
|
|
let mut pm = PrincipalMatch {
|
|
principal_properties: PrincipalMatchProperties::Self_,
|
|
properties: vec![],
|
|
};
|
|
|
|
loop {
|
|
match stream.token()? {
|
|
Token::ElementStart {
|
|
name:
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element: Element::PrincipalProperty,
|
|
},
|
|
..
|
|
} => {
|
|
pm.principal_properties = PrincipalMatchProperties::Properties(
|
|
stream.collect_properties(Vec::new())?,
|
|
);
|
|
}
|
|
Token::ElementStart {
|
|
name:
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element: Element::Self_,
|
|
},
|
|
..
|
|
} => {
|
|
pm.principal_properties = PrincipalMatchProperties::Self_;
|
|
stream.expect_element_end()?;
|
|
}
|
|
Token::ElementStart {
|
|
name:
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element: Element::Prop,
|
|
},
|
|
..
|
|
} => {
|
|
pm.properties = stream.collect_properties(pm.properties)?;
|
|
}
|
|
Token::ElementEnd => {
|
|
break;
|
|
}
|
|
Token::UnknownElement(_) => {
|
|
stream.seek_element_end()?;
|
|
}
|
|
other => {
|
|
return Err(other.into_unexpected());
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(pm)
|
|
}
|
|
}
|
|
|
|
impl DavParser for PrincipalPropertySearch {
|
|
fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Self> {
|
|
let mut pps = PrincipalPropertySearch {
|
|
property_search: vec![],
|
|
properties: vec![],
|
|
apply_to_principal_collection_set: false,
|
|
};
|
|
|
|
loop {
|
|
match stream.token()? {
|
|
Token::ElementStart {
|
|
name:
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element: Element::PropertySearch,
|
|
},
|
|
..
|
|
} => {
|
|
if let Some(prop) = PropertySearch::parse(stream)? {
|
|
pps.property_search.push(prop);
|
|
}
|
|
}
|
|
Token::ElementStart {
|
|
name:
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element: Element::Prop,
|
|
},
|
|
..
|
|
} => {
|
|
pps.properties = stream.collect_properties(pps.properties)?;
|
|
}
|
|
Token::ElementStart {
|
|
name:
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element: Element::ApplyToPrincipalCollectionSet,
|
|
},
|
|
..
|
|
} => {
|
|
stream.expect_element_end()?;
|
|
pps.apply_to_principal_collection_set = true;
|
|
}
|
|
Token::ElementEnd => {
|
|
break;
|
|
}
|
|
Token::UnknownElement(_) => {
|
|
stream.seek_element_end()?;
|
|
}
|
|
other => {
|
|
return Err(other.into_unexpected());
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(pps)
|
|
}
|
|
}
|
|
|
|
impl PropertySearch {
|
|
fn parse(stream: &mut Tokenizer<'_>) -> crate::parser::Result<Option<Self>> {
|
|
let mut property = None;
|
|
let mut match_ = None;
|
|
|
|
loop {
|
|
match stream.token()? {
|
|
Token::ElementStart {
|
|
name:
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element: Element::Prop,
|
|
},
|
|
..
|
|
} => {
|
|
property = stream.collect_properties(Vec::new())?.into_iter().next();
|
|
}
|
|
Token::ElementStart {
|
|
name:
|
|
NamedElement {
|
|
ns: Namespace::Dav,
|
|
element: Element::Match,
|
|
},
|
|
..
|
|
} => {
|
|
match_ = stream.collect_string_value()?;
|
|
}
|
|
Token::ElementEnd => {
|
|
break;
|
|
}
|
|
Token::UnknownElement(_) => {
|
|
stream.seek_element_end()?;
|
|
}
|
|
other => {
|
|
return Err(other.into_unexpected());
|
|
}
|
|
}
|
|
}
|
|
|
|
Ok(property.map(|property| PropertySearch {
|
|
property,
|
|
match_: match_.unwrap_or_default(),
|
|
}))
|
|
}
|
|
}
|