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.
427 lines
14 KiB
Rust
427 lines
14 KiB
Rust
/*
|
|
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
|
|
*
|
|
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
|
|
*/
|
|
|
|
use crate::{
|
|
responses::XmlEscape,
|
|
schema::{
|
|
Namespace, Namespaces,
|
|
property::{DavProperty, Privilege},
|
|
response::{
|
|
Ace, AclRestrictions, GrantDeny, Href, List, Principal, PrincipalSearchProperty,
|
|
PrincipalSearchPropertySet, RequiredPrincipal, Resource, SupportedPrivilege,
|
|
},
|
|
},
|
|
};
|
|
use std::fmt::Display;
|
|
|
|
impl Display for SupportedPrivilege {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "<D:supported-privilege>{}", self.privilege)?;
|
|
if self.abstract_ {
|
|
write!(f, "<D:abstract/>")?;
|
|
}
|
|
write!(f, "<D:description>")?;
|
|
self.description.write_escaped_to(f)?;
|
|
write!(
|
|
f,
|
|
"</D:description>{}</D:supported-privilege>",
|
|
self.supported_privilege
|
|
)
|
|
}
|
|
}
|
|
|
|
impl SupportedPrivilege {
|
|
pub fn new(privilege: Privilege, description: impl Into<String>) -> Self {
|
|
SupportedPrivilege {
|
|
privilege,
|
|
abstract_: false,
|
|
description: description.into(),
|
|
supported_privilege: List(vec![]),
|
|
}
|
|
}
|
|
|
|
pub fn with_abstract(mut self) -> Self {
|
|
self.abstract_ = true;
|
|
self
|
|
}
|
|
|
|
pub fn with_supported_privilege(mut self, supported_privilege: SupportedPrivilege) -> Self {
|
|
self.supported_privilege.0.push(supported_privilege);
|
|
self
|
|
}
|
|
|
|
pub fn with_opt_supported_privilege(
|
|
mut self,
|
|
supported_privilege: Option<SupportedPrivilege>,
|
|
) -> Self {
|
|
if let Some(supported_privilege) = supported_privilege {
|
|
self.supported_privilege.0.push(supported_privilege);
|
|
}
|
|
self
|
|
}
|
|
|
|
pub fn all_privileges(is_calendar: bool) -> SupportedPrivilege {
|
|
SupportedPrivilege::new(Privilege::All, "Any operation")
|
|
.with_abstract()
|
|
.with_supported_privilege(
|
|
SupportedPrivilege::new(Privilege::Read, "Read objects").with_supported_privilege(
|
|
SupportedPrivilege::new(
|
|
Privilege::ReadCurrentUserPrivilegeSet,
|
|
"Read current user privileges",
|
|
),
|
|
),
|
|
)
|
|
.with_supported_privilege(
|
|
SupportedPrivilege::new(Privilege::Write, "Write objects")
|
|
.with_supported_privilege(SupportedPrivilege::new(
|
|
Privilege::WriteProperties,
|
|
"Write properties",
|
|
))
|
|
.with_supported_privilege(SupportedPrivilege::new(
|
|
Privilege::WriteContent,
|
|
"Write object contents",
|
|
))
|
|
.with_supported_privilege(SupportedPrivilege::new(
|
|
Privilege::Bind,
|
|
"Add resources to a collection",
|
|
))
|
|
.with_supported_privilege(SupportedPrivilege::new(
|
|
Privilege::Unbind,
|
|
"Remove resources from a collection",
|
|
))
|
|
.with_supported_privilege(SupportedPrivilege::new(
|
|
Privilege::Unlock,
|
|
"Unlock resources",
|
|
)),
|
|
)
|
|
.with_supported_privilege(SupportedPrivilege::new(Privilege::ReadAcl, "Read ACL"))
|
|
.with_supported_privilege(SupportedPrivilege::new(Privilege::WriteAcl, "Write ACL"))
|
|
.with_opt_supported_privilege((is_calendar).then(|| {
|
|
SupportedPrivilege::new(Privilege::ReadFreeBusy, "Read free/busy information")
|
|
}))
|
|
}
|
|
|
|
pub fn all_scheduling_privileges(is_inbox: bool) -> SupportedPrivilege {
|
|
let privilege = SupportedPrivilege::new(Privilege::All, "Any operation")
|
|
.with_abstract()
|
|
.with_supported_privilege(
|
|
SupportedPrivilege::new(Privilege::Read, "Read objects").with_supported_privilege(
|
|
SupportedPrivilege::new(
|
|
Privilege::ReadCurrentUserPrivilegeSet,
|
|
"Read current user privileges",
|
|
),
|
|
),
|
|
);
|
|
|
|
if is_inbox {
|
|
privilege.with_supported_privilege(
|
|
SupportedPrivilege::new(
|
|
Privilege::ScheduleDeliver,
|
|
"Deliver calendar scheduling messages",
|
|
)
|
|
.with_supported_privilege(SupportedPrivilege::new(
|
|
Privilege::ScheduleDeliverInvite,
|
|
"Deliver calendar scheduling invites",
|
|
))
|
|
.with_supported_privilege(SupportedPrivilege::new(
|
|
Privilege::ScheduleDeliverReply,
|
|
"Deliver calendar scheduling replies",
|
|
))
|
|
.with_supported_privilege(SupportedPrivilege::new(
|
|
Privilege::ScheduleQueryFreeBusy,
|
|
"Query free/busy information",
|
|
)),
|
|
)
|
|
} else {
|
|
privilege.with_supported_privilege(
|
|
SupportedPrivilege::new(
|
|
Privilege::ScheduleSend,
|
|
"Send calendar scheduling messages",
|
|
)
|
|
.with_supported_privilege(SupportedPrivilege::new(
|
|
Privilege::ScheduleSendInvite,
|
|
"Send calendar scheduling invites",
|
|
))
|
|
.with_supported_privilege(SupportedPrivilege::new(
|
|
Privilege::ScheduleSendReply,
|
|
"Send calendar scheduling replies",
|
|
))
|
|
.with_supported_privilege(SupportedPrivilege::new(
|
|
Privilege::ScheduleSendFreeBusy,
|
|
"Send free/busy information",
|
|
)),
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Display for Ace {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "<D:ace>")?;
|
|
if self.invert {
|
|
write!(f, "<D:invert>")?;
|
|
}
|
|
self.principal.fmt(f)?;
|
|
if self.invert {
|
|
write!(f, "</D:invert>")?;
|
|
}
|
|
self.grant_deny.fmt(f)?;
|
|
if self.protected {
|
|
write!(f, "<D:protected/>")?;
|
|
}
|
|
if let Some(inherited) = &self.inherited {
|
|
write!(f, "<D:inherited>")?;
|
|
inherited.fmt(f)?;
|
|
write!(f, "</D:inherited>")?;
|
|
}
|
|
write!(f, "</D:ace>")
|
|
}
|
|
}
|
|
|
|
impl Display for Principal {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "<D:principal>")?;
|
|
match self {
|
|
Principal::Href(href) => href.fmt(f),
|
|
Principal::Response(response) => response.fmt(f),
|
|
Principal::All => "<D:all/>".fmt(f),
|
|
Principal::Authenticated => "<D:authenticated/>".fmt(f),
|
|
Principal::Unauthenticated => "<D:unauthenticated/>".fmt(f),
|
|
Principal::Property(property) => {
|
|
write!(f, "<D:property>{}</D:property>", property)
|
|
}
|
|
Principal::Self_ => "<D:self/>".fmt(f),
|
|
}?;
|
|
write!(f, "</D:principal>")
|
|
}
|
|
}
|
|
|
|
impl Display for GrantDeny {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
GrantDeny::Grant(privileges) => {
|
|
write!(f, "<D:grant>")?;
|
|
privileges.fmt(f)?;
|
|
write!(f, "</D:grant>")
|
|
}
|
|
GrantDeny::Deny(privileges) => {
|
|
write!(f, "<D:deny>")?;
|
|
privileges.fmt(f)?;
|
|
write!(f, "</D:deny>")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Display for AclRestrictions {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
if self.grant_only {
|
|
write!(f, "<D:grant-only/>")?;
|
|
}
|
|
if self.no_invert {
|
|
write!(f, "<D:no-invert/>")?;
|
|
}
|
|
if self.deny_before_grant {
|
|
write!(f, "<D:deny-before-grant/>")?;
|
|
}
|
|
if let Some(required_principal) = &self.required_principal {
|
|
required_principal.fmt(f)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl Display for RequiredPrincipal {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "<D:required-principal>")?;
|
|
match self {
|
|
RequiredPrincipal::All => "<D:all/>".fmt(f)?,
|
|
RequiredPrincipal::Authenticated => "<D:authenticated/>".fmt(f)?,
|
|
RequiredPrincipal::Unauthenticated => "<D:unauthenticated/>".fmt(f)?,
|
|
RequiredPrincipal::Self_ => "<D:self/>".fmt(f)?,
|
|
RequiredPrincipal::Href(hrefs) => hrefs.fmt(f)?,
|
|
RequiredPrincipal::Property(properties) => {
|
|
for property in properties {
|
|
write!(f, "<D:property>{}</D:property>", property)?;
|
|
}
|
|
}
|
|
}
|
|
write!(f, "</D:required-principal>")
|
|
}
|
|
}
|
|
|
|
impl Display for Privilege {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
Privilege::Read => "<D:privilege><D:read/></D:privilege>".fmt(f),
|
|
Privilege::Write => "<D:privilege><D:write/></D:privilege>".fmt(f),
|
|
Privilege::WriteProperties => "<D:privilege><D:write-properties/></D:privilege>".fmt(f),
|
|
Privilege::WriteContent => "<D:privilege><D:write-content/></D:privilege>".fmt(f),
|
|
Privilege::Unlock => "<D:privilege><D:unlock/></D:privilege>".fmt(f),
|
|
Privilege::ReadAcl => "<D:privilege><D:read-acl/></D:privilege>".fmt(f),
|
|
Privilege::ReadCurrentUserPrivilegeSet => {
|
|
"<D:privilege><D:read-current-user-privilege-set/></D:privilege>".fmt(f)
|
|
}
|
|
Privilege::WriteAcl => "<D:privilege><D:write-acl/></D:privilege>".fmt(f),
|
|
Privilege::Bind => "<D:privilege><D:bind/></D:privilege>".fmt(f),
|
|
Privilege::Unbind => "<D:privilege><D:unbind/></D:privilege>".fmt(f),
|
|
Privilege::All => "<D:privilege><D:all/></D:privilege>".fmt(f),
|
|
Privilege::ReadFreeBusy => "<D:privilege><A:read-free-busy/></D:privilege>".fmt(f),
|
|
Privilege::ScheduleDeliver => "<D:privilege><A:schedule-deliver/></D:privilege>".fmt(f),
|
|
Privilege::ScheduleDeliverInvite => {
|
|
"<D:privilege><A:schedule-deliver-invite/></D:privilege>".fmt(f)
|
|
}
|
|
Privilege::ScheduleDeliverReply => {
|
|
"<D:privilege><A:schedule-deliver-reply/></D:privilege>".fmt(f)
|
|
}
|
|
Privilege::ScheduleQueryFreeBusy => {
|
|
"<D:privilege><A:schedule-query-freebusy/></D:privilege>".fmt(f)
|
|
}
|
|
Privilege::ScheduleSend => "<D:privilege><A:schedule-send/></D:privilege>".fmt(f),
|
|
Privilege::ScheduleSendInvite => {
|
|
"<D:privilege><A:schedule-send-invite/></D:privilege>".fmt(f)
|
|
}
|
|
Privilege::ScheduleSendReply => {
|
|
"<D:privilege><A:schedule-send-reply/></D:privilege>".fmt(f)
|
|
}
|
|
Privilege::ScheduleSendFreeBusy => {
|
|
"<D:privilege><A:schedule-send-freebusy/></D:privilege>".fmt(f)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Display for Resource {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(
|
|
f,
|
|
"<D:resource>{}{}</D:resource>",
|
|
self.href, self.privilege
|
|
)
|
|
}
|
|
}
|
|
|
|
impl Display for PrincipalSearchPropertySet {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(f, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>")?;
|
|
write!(
|
|
f,
|
|
"<D:principal-search-property-set {}>{}</D:principal-search-property-set>",
|
|
self.namespaces, self.properties
|
|
)
|
|
}
|
|
}
|
|
|
|
impl Display for PrincipalSearchProperty {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
write!(
|
|
f,
|
|
"<D:principal-search-property><D:prop>{}</D:prop>",
|
|
self.name
|
|
)?;
|
|
write!(
|
|
f,
|
|
"<D:description>{}</D:description></D:principal-search-property>",
|
|
self.description
|
|
)
|
|
}
|
|
}
|
|
|
|
impl Resource {
|
|
pub fn new(href: impl Into<String>, privilege: Privilege) -> Self {
|
|
Resource {
|
|
href: Href(href.into()),
|
|
privilege,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl PrincipalSearchPropertySet {
|
|
pub fn new(properties: Vec<PrincipalSearchProperty>) -> Self {
|
|
PrincipalSearchPropertySet {
|
|
namespaces: Namespaces::default(),
|
|
properties: List(properties),
|
|
}
|
|
}
|
|
|
|
pub fn with_namespace(mut self, namespace: Namespace) -> Self {
|
|
self.namespaces.set(namespace);
|
|
self
|
|
}
|
|
}
|
|
|
|
impl PrincipalSearchProperty {
|
|
pub fn new(name: impl Into<DavProperty>, description: impl Into<String>) -> Self {
|
|
PrincipalSearchProperty {
|
|
name: name.into(),
|
|
description: description.into(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Ace {
|
|
pub fn new(principal: Principal, grant_deny: GrantDeny) -> Self {
|
|
Ace {
|
|
principal,
|
|
invert: false,
|
|
grant_deny,
|
|
protected: false,
|
|
inherited: None,
|
|
}
|
|
}
|
|
|
|
pub fn with_invert(mut self) -> Self {
|
|
self.invert = true;
|
|
self
|
|
}
|
|
|
|
pub fn with_protected(mut self) -> Self {
|
|
self.protected = true;
|
|
self
|
|
}
|
|
|
|
pub fn with_inherited(mut self, inherited: impl Into<String>) -> Self {
|
|
self.inherited = Some(Href(inherited.into()));
|
|
self
|
|
}
|
|
}
|
|
|
|
impl GrantDeny {
|
|
pub fn grant(privileges: Vec<Privilege>) -> Self {
|
|
GrantDeny::Grant(List(privileges))
|
|
}
|
|
|
|
pub fn deny(privileges: Vec<Privilege>) -> Self {
|
|
GrantDeny::Deny(List(privileges))
|
|
}
|
|
}
|
|
|
|
impl AclRestrictions {
|
|
pub fn new() -> Self {
|
|
Self::default()
|
|
}
|
|
|
|
pub fn with_grant_only(mut self) -> Self {
|
|
self.grant_only = true;
|
|
self
|
|
}
|
|
|
|
pub fn with_no_invert(mut self) -> Self {
|
|
self.no_invert = true;
|
|
self
|
|
}
|
|
|
|
pub fn with_deny_before_grant(mut self) -> Self {
|
|
self.deny_before_grant = true;
|
|
self
|
|
}
|
|
|
|
pub fn with_required_principal(mut self, required_principal: RequiredPrincipal) -> Self {
|
|
self.required_principal = Some(required_principal);
|
|
self
|
|
}
|
|
}
|