fix(security): apply 4 vulnerability fixes from security audit

1. Share password bypass (HIGH): enforce password check in get_shared_link_by_token,
   verify_shared_link_password now returns ShareDto only on correct password.
2. WebDAV MOVE ownership (MEDIUM): add assert_owner on destination parent folder
   for file moves in both PathResolver and legacy branches.
3. Path traversal defense-in-depth (LOW): add reject_path_traversal() to WebDAV,
   CalDAV, and CardDAV handlers rejecting '..' segments at HTTP boundary.
4. Setup race condition (LOW): atomic INSERT ... ON CONFLICT DO NOTHING in
   try_claim_initialization prevents duplicate admin creation.
This commit is contained in:
Dionisio
2026-03-05 16:09:37 +01:00
parent 33cfb0faef
commit 4197cc3b7b
9 changed files with 198 additions and 14 deletions
@@ -23,4 +23,35 @@ pub trait SettingsRepository: Send + Sync + 'static {
/// Delete a setting by key
async fn delete(&self, key: &str) -> Result<(), DomainError>;
/// Atomically claim system initialization.
///
/// Inserts `system_initialized = "true"` **only if the key does not
/// already exist**. Returns `true` when this call was the one that
/// performed the insert (i.e. the caller "won" the race), `false` if
/// the system was already initialized.
///
/// The default implementation falls back to the non-atomic
/// get-then-set pattern for repositories that don't support a native
/// atomic upsert.
async fn try_claim_initialization(
&self,
admin_user_id: &str,
) -> Result<bool, DomainError> {
// Default: non-atomic fallback (overridden by PG implementation)
match self.get("system_initialized").await? {
Some(v) if v == "true" => Ok(false),
_ => {
self.set(
"system_initialized",
"true",
"system",
false,
Some(admin_user_id),
)
.await?;
Ok(true)
}
}
}
}