fix: URL-decode DAV paths with spaces + feat: app passwords for Basic Auth
Bug fix: - URL-decode paths in extract_webdav_path(), extract_caldav_path(), extract_carddav_path() so folders with spaces (e.g. 'My Folder') no longer return 404 when accessed via encoded URIs (%20) - Properly encode href values in PROPFIND/PROPPATCH/LOCK XML responses - Decode Destination header in MOVE/COPY operations New feature - App Passwords (API keys for DAV clients): - POST /api/auth/app-passwords → create (shows token once) - GET /api/auth/app-passwords → list (prefix only) - DELETE /api/auth/app-passwords/:id → revoke - Auth middleware now accepts both Bearer JWT and Basic Auth - Argon2 hashed, scoped (webdav/caldav/carddav), optional expiry - Compatible with DAVx5, Thunderbird, rclone, curl Tested: 12/12 E2E tests pass (create, list, WebDAV/CalDAV/CardDAV Basic Auth, URL-decode with spaces, wrong password 401, revoke, post- revoke 401).
This commit is contained in:
@@ -22,6 +22,7 @@ use axum::{
|
||||
response::Response,
|
||||
};
|
||||
use bytes::Buf;
|
||||
use percent_encoding::percent_decode_str;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::application::adapters::caldav_adapter::{CalDavAdapter, CalDavReportType};
|
||||
@@ -86,19 +87,21 @@ async fn handle_caldav_methods_inner(
|
||||
}
|
||||
}
|
||||
|
||||
/// Extract the CalDAV path from the full URI path.
|
||||
/// Extract the CalDAV path from the full URI path, percent-decoding the result.
|
||||
fn extract_caldav_path(uri_path: &str) -> String {
|
||||
if let Some(pos) = uri_path.find("/caldav/") {
|
||||
let encoded = if let Some(pos) = uri_path.find("/caldav/") {
|
||||
let after = &uri_path[pos + 8..];
|
||||
after.trim_end_matches('/').to_string()
|
||||
after.trim_end_matches('/')
|
||||
} else if uri_path.ends_with("/caldav") {
|
||||
String::new()
|
||||
""
|
||||
} else {
|
||||
uri_path
|
||||
.trim_start_matches('/')
|
||||
.trim_end_matches('/')
|
||||
.to_string()
|
||||
}
|
||||
};
|
||||
percent_decode_str(encoded)
|
||||
.decode_utf8_lossy()
|
||||
.into_owned()
|
||||
}
|
||||
|
||||
// ─── Helper: extract user from request ───────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user