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:
+11
@@ -164,6 +164,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
if config.features.enable_auth {
|
||||
use interfaces::api::handlers::auth_handler::auth_routes;
|
||||
use oxicloud::interfaces::api::handlers::device_auth_handler;
|
||||
use oxicloud::interfaces::api::handlers::app_password_handler;
|
||||
use oxicloud::interfaces::middleware::auth::auth_middleware;
|
||||
|
||||
let auth_router = auth_routes().with_state(app_state.clone());
|
||||
@@ -180,6 +181,14 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
))
|
||||
.with_state(app_state.clone());
|
||||
|
||||
// App Password management endpoints (protected — require JWT)
|
||||
let app_password_protected = app_password_handler::app_password_routes()
|
||||
.layer(axum::middleware::from_fn_with_state(
|
||||
app_state.clone(),
|
||||
auth_middleware,
|
||||
))
|
||||
.with_state(app_state.clone());
|
||||
|
||||
// Protected API routes — require valid JWT token
|
||||
let protected_api = api_routes.layer(axum::middleware::from_fn_with_state(
|
||||
app_state.clone(),
|
||||
@@ -207,6 +216,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
.nest("/api/auth/device", device_public)
|
||||
// Device Auth Grant protected endpoints (verify + device management)
|
||||
.nest("/api/auth/device", device_protected)
|
||||
// App Password management endpoints (create, list, revoke)
|
||||
.nest("/api/auth", app_password_protected)
|
||||
// Public API routes (share access, i18n) — no auth required
|
||||
.nest("/api", public_api_routes)
|
||||
// All other API routes are protected by auth middleware
|
||||
|
||||
Reference in New Issue
Block a user