Merge branch 'main' into rfc-4331-quota-properties
# Conflicts: # src/interfaces/nextcloud/report_handler.rs # src/interfaces/nextcloud/webdav_handler.rs # tests/api/run.sh
This commit is contained in:
@@ -72,6 +72,46 @@ impl std::fmt::Display for QualifiedName {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether PROPPATCH must refuse to set/remove this property as a dead
|
||||
/// property (RFC 4918 §9.2 — server MAY reject a PROPPATCH attempt on a
|
||||
/// live property; DeadPropertyStore has no business holding a value that
|
||||
/// PROPFIND / REPORT already emit from live server state).
|
||||
pub fn is_protected_property(qn: &QualifiedName) -> bool {
|
||||
match qn.namespace.as_str() {
|
||||
// RFC 4918 §15 — the DAV: namespace is server-owned in its
|
||||
// entirety. Any PROPPATCH into it either forges a live
|
||||
// property (dual-emission) or accumulates unread garbage
|
||||
// (silent litter).
|
||||
"DAV:" => true,
|
||||
|
||||
// Every name below appears verbatim in write_folder_response
|
||||
// / write_file_response in the NC handler. Adding a new
|
||||
// live emitter → add its name here.
|
||||
"http://owncloud.org/ns" => matches!(
|
||||
qn.name.as_str(),
|
||||
"favorite"
|
||||
| "fileid"
|
||||
| "id"
|
||||
| "owner-id"
|
||||
| "owner-display-name"
|
||||
| "permissions"
|
||||
| "share-types"
|
||||
| "size"
|
||||
),
|
||||
|
||||
"http://nextcloud.org/ns" => matches!(
|
||||
qn.name.as_str(),
|
||||
"has-preview" | "is-encrypted" | "mount-type" | "creation_time" | "upload_time"
|
||||
),
|
||||
|
||||
"http://open-collaboration-services.org/ns" => {
|
||||
matches!(qn.name.as_str(), "share-permissions")
|
||||
}
|
||||
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// PROPFIND request type
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum PropFindType {
|
||||
@@ -470,7 +510,12 @@ impl WebDavAdapter {
|
||||
///
|
||||
/// Written AFTER the live-property propstats inside a `<D:response>`.
|
||||
/// Only emitted when `dead_props` is non-empty.
|
||||
fn write_dead_props_propstat<W: Write>(
|
||||
///
|
||||
/// `pub(crate)` so the NextCloud-compatible handler
|
||||
/// (`interfaces::nextcloud::webdav_handler`) can append the same
|
||||
/// dead-property block to its own bespoke PROPFIND writers instead
|
||||
/// of duplicating this XML shape.
|
||||
pub(crate) fn write_dead_props_propstat<W: Write>(
|
||||
xml_writer: &mut Writer<W>,
|
||||
dead_props: &[(QualifiedName, Option<String>)],
|
||||
) -> Result<()> {
|
||||
|
||||
@@ -150,6 +150,26 @@ pub trait AuthorizationEngine: Send + Sync + 'static {
|
||||
expires_at: Option<chrono::DateTime<chrono::Utc>>,
|
||||
) -> Result<(), DomainError>;
|
||||
|
||||
/// Delete every row from `storage.role_grants` whose `expires_at` is
|
||||
/// more than `grace_days` in the past. Returns the count of rows
|
||||
/// removed.
|
||||
///
|
||||
/// The engine's `check` / `list_grants_*` paths already ignore
|
||||
/// expired rows (they filter on `expires_at > NOW()` in-query), so
|
||||
/// this is pure garbage collection — no live authorization decision
|
||||
/// changes. The grace window preserves the audit / support answer
|
||||
/// to "what happened to my access?" for a couple of weeks past
|
||||
/// expiration.
|
||||
///
|
||||
/// Grace of `0` means "delete every row whose `expires_at` is in
|
||||
/// the past, right now" — used by the admin `?force=true` trigger
|
||||
/// endpoint to enable Hurl regression testing without waiting the
|
||||
/// configured grace out.
|
||||
///
|
||||
/// Rows with `expires_at IS NULL` (permanent grants) are never
|
||||
/// touched.
|
||||
async fn purge_expired_grants(&self, grace_days: u32) -> Result<u64, DomainError>;
|
||||
|
||||
/// Revoke a single role grant by its UUID. Idempotent — returns `Ok(())`
|
||||
/// whether or not the row existed. The id comes from a prior listing
|
||||
/// or `find_grant_full_by_id` lookup.
|
||||
|
||||
Reference in New Issue
Block a user