Remove legacy abstractions that are no longer used after the
100% blob storage model migration (#113):
- IdMappingPort trait from application/ports/outbound.rs
- storage_mediator.rs module (StorageMediator trait + impls)
- StorageMediator impl from PathService
- write_behind_cache.rs (FS-based, incompatible with blob model)
The WriteBehindCachePort trait and Optional fields in services
are preserved for potential future blob-compatible caching.
-968 lines of dead code removed. Build clean, RC=0.
Root cause: when window.app.currentPath was empty/falsy (due to timing,
page state reset, or initialization), the frontend sent parent_id: null.
The backend then created folders at the storage root instead of inside
the user's home folder.
Backend fix (folder_handler.rs):
- Added AuthUser extractor to create_folder handler
- When parent_id is None, auto-resolves the user's home folder
('My Folder - {username}') as the parent folder
- Folders are now always created inside the user's directory tree
Frontend fix (fileOperations.js):
- Changed parent_id fallback from null to window.app.userHomeFolderId
- Prevents sending null parent_id even if currentPath is reset
Search in subfolders: no fix needed — search_recursive() already
traverses the filesystem correctly; it was only failing because folders
were physically flat instead of nested.
Bumps service worker cache to v12.
Standardize code formatting across all 173 Rust source files
using rustfmt. No functional changes - purely cosmetic.
This establishes a consistent code style baseline for the
project going forward.
When OXICLOUD_SERVER_HOST contains a full URL with scheme (e.g.
https://oxi.example.com), the share link no longer prepends
http:// or appends :port, avoiding malformed URLs like
http://https://host:8085/s/token.
- Add AppConfig::base_url() helper with smart URL construction
- Replace all 6 inline format!() calls in share_service.rs
- Replace inline construction in di.rs (admin settings base URL)
- Priority: OXICLOUD_BASE_URL > full-URL host > http://host:port
Add server-side routes for /profile, /admin, and /shared that
serve their respective HTML pages directly (same pattern already
used for /login). Updated all frontend references to use clean
URLs instead of .html extensions.
Fixes#99
Non-admin users were seeing all users' root folders, including the
admin's. Three root causes fixed:
1. Backend: list_root_folders now extracts AuthUser and filters
results so each user only sees their own home folder at the
root level (folders matching 'My Folder - {username}' or
'Mi Carpeta - {username}').
2. Frontend: findUserHomeFolder() searched only for the Spanish
pattern 'Mi Carpeta - {username}' but the backend creates
folders with the English pattern 'My Folder - {username}'.
Now checks both naming conventions.
3. Frontend: when the home folder was not found, the code fell
back to folderList[0] — which was usually the admin's folder.
Removed that dangerous fallback; now shows empty root instead.
Fixes#94
Axum's default body limit for Multipart extraction is 2 MB.
OxiCloud never overrode this default, so any file upload larger
than ~2 MB was silently truncated.
Added DefaultBodyLimit::max(10 GB) both globally on the app
router and specifically on the file upload routes, matching the
chunked upload capability already in place for large files.
Previously the admin quota was hardcoded to 100 GB and the regular
user quota to 1 GB, regardless of actual disk capacity. On systems
with less than 100 GB free this produced misleading quota values.
Added the fs2 crate to query available disk space on the storage
filesystem. A new capped_quota() helper now returns
min(default_quota, available_disk_space) when assigning quotas
during user registration, admin setup, and OIDC provisioning.
get_authorize_url() was synchronous and fell back to constructing
{issuer}/authorize when the discovery cache was empty. This produced
incorrect URLs for providers like Keycloak whose authorization
endpoint is {issuer}/protocol/openid-connect/auth.
Made get_authorize_url() async so it can call get_discovery() to
fetch the real authorization_endpoint from .well-known/openid-configuration
before the first redirect. The discovery document is cached after the
initial fetch.
- Added directory name filtering in folder_fs_repository.rs
- Filters out directories starting with '.' in list_folders, list_folders_paginated, and count_directory_items
- Matches existing file listing behavior
- Also added Italian language to popular languages list
Fixes#87
Backend:
- POST /api/admin/users — admin-only user creation endpoint
- username & password required, email optional (auto-generated placeholder)
- role, quota_bytes, active all configurable
- creates personal folder automatically
- PUT /api/admin/users/{id}/password — admin password reset
- GET/PUT /api/admin/settings/registration — toggle public registration
- Supports env var OXICLOUD_DISABLE_REGISTRATION override
- Blocks POST /api/auth/register when disabled
- AdminCreateUserDto, AdminResetPasswordDto added to settings DTOs
- registration_enabled field added to DashboardStatsDto
Frontend (admin.html):
- 'Create User' button in Users tab with full modal form
(username, password, email, role, quota)
- 'Reset Password' button per user in actions column
- 'Allow public self-registration' toggle in Dashboard > System
with warning banner when disabled
Closes#85
- Fix showShareDialog: add try-catch, null checks, prevent textContent
from destroying header icon (use span child instead)
- Capture file/folder target before closeContextMenu to prevent race
- createSharedLink now calls real backend POST /api/shares instead of
localStorage-only mock (still caches locally for offline compat)
- Fix share_handler.rs: use OptionalAuthUser instead of AuthUser to
prevent 401 when auth is disabled (same pattern as delete/trash)
- Add null-safety to closeShareDialog
- Reset new-share-section on dialog open
- Add ?metadata=true support to GET /api/files/{id} to return JSON metadata
instead of binary content (was the root cause of favorites not loading)
- Fix favorites loadFileDetails to use metadata endpoint with auth headers
- Add star icon on favorited files/folders in grid view (top-left corner)
- Add star icon on favorited files/folders in list view (next to name)
- Refresh file view when toggling favorites so star appears/disappears
- Add CSS styles for .favorite-star and .favorite-star-inline
- Fix rename: context menu was nullifying target reference before rename dialog could use it
- Fix delete files/folders: auth extractors were mandatory, causing 401 when auth not configured
- Fix view-file: async fetch race condition with context menu cleanup
- Fix orphaned ID mappings on file deletion
- Fix Authorization: Bearer null headers sent without token
- Add OptionalUserId and OptionalAuthUser infallible extractors
Three bugs caused 403 errors when creating the first admin on fresh
Docker deployments (Unraid, Komodo):
1. db.rs: Schema application failures were silently swallowed. The app
started with no tables, causing all auth queries to fail. Now the
startup aborts if schema cannot be applied, with a fallback
statement-by-statement executor that handles dollar-quoted blocks.
Retries increased to 5 with 2s intervals.
2. auth_application_service.rs: count_admin_users() used fragile string
matching (contains "does not exist")) on multi-layer wrapped errors.
count_all_users() rejected admin creation on any DB error. Both now
allow admin creation on any error for bootstrap scenarios.
3. auth_handler.rs: Redundant 60-line handler-level admin detection
duplicated service-layer logic and generated noisy ERROR logs on
fresh installs. Removed entirely - service layer handles it all.
Closes#81
- Auto-apply schema.sql when database tables don't exist (embedded in binary)
- Handle missing tables gracefully during admin registration (treat as fresh install)
- Fix docker-compose depends_on to wait for postgres healthcheck
- Rename personal folder from 'Mi Carpeta' to 'My Folder' with backward compat
- Translate remaining Spanish messages to English
- Downgrade OXICLOUD_JWT_SECRET missing log from error to warn level,
since generating a random secret per session is valid behavior
- Remove unused import super::* in calendar_storage_adapter tests
- Remove unused import tokio_stream::StreamExt in compression_service tests
- Prefix unused validate_user_ownership with _ in trash_service
- Add nohup.out to .gitignore
The translation commit accidentally removed the match statement and
opening arms (match item_result, Ok(Some(item)), match item.item_type)
while keeping the body, causing a brace mismatch compilation error.
Root cause: Docker named volumes are created as root, but the container
ran as the unprivileged 'oxicloud' user (UID 1001). Services like
thumbnail_service, image_transcode, and dedup_service call
create_dir_all under /app/storage during initialization, which fails
with 'Permission denied (os error 13)'.
Changes:
- Add entrypoint.sh that runs as root to chown /app/storage, then
drops privileges via su-exec before executing the application
- Update Dockerfile to install su-exec, copy entrypoint, and use
ENTRYPOINT instead of USER+CMD
- Downgrade id_mapping_service initial write failure from ERROR to WARN
(empty in-memory map is perfectly valid, will persist on next save)
- Improve panic message in main.rs to hint at Docker permission issue
Fixes #<issue>
- Add admin panel link and profile modal in user menu dropdown
- Add French, German and Portuguese locale support (full translations)
- Register new locales across JS frontend and Rust backend
- Create CI pipeline (fmt, clippy, test, audit, build)
- Fix docker-build.yml (cache, real tests, reduced timeout)
- Fix docker-publish.yml (multi-arch via QEMU, latest tag, pre-publish tests)
- Add dependabot.yml for automated dependency updates
Security fixes for OIDC authentication flow:
1. CSRF state validation (High): State nonce is now stored server-side
and validated on callback (single-use, 600s TTL)
2. PKCE S256 (Medium): code_challenge/code_verifier pair generated per
RFC 9126, sent in authorize URL and token exchange
3. Nonce in ID token (Medium): Random nonce included in authorize URL,
verified against ID token claims to prevent token replay
4. Secure token delivery (Medium): Tokens no longer in URL fragments.
One-time exchange code redirected to frontend, tokens retrieved via
POST /api/auth/oidc/exchange endpoint (60s TTL, single-use)
5. Registration guard (Low): POST /api/auth/register returns 403 when
disable_password_login is active in OIDC-only mode
- Move WebDAV routes to top-level (out of /api nest) for proper path handling
- Add trailing slash routes and HEAD method support
- Refactor all 12 handlers to use Axum State extractor instead of req.extensions()
- Fix MOVE handler to support rename (same-folder move) via rename_file service
- Add Overwrite header support in MOVE/COPY operations
- Add extract_webdav_path() helper for consistent path parsing
- Add precondition_failed variant to AppError
- All 17 integration tests passing: OPTIONS, PROPFIND, MKCOL, PUT, GET, HEAD,
PROPPATCH, COPY, MOVE, LOCK, DELETE (files and folders)
- Remove Serialize/Deserialize from File, Folder, Session, User, Contact entities
- Create contact_persistence_dto.rs for JSONB persistence in infrastructure layer
- Update contact_pg_repository to use persistence DTOs
- Fix dependency on zip crate (downgrade from 7.2.0 to 2.1.0)
- Fix unused variable warnings in main.rs
- Move PathService import from domain to infrastructure
- Add missing fields to CoreServices and RepositoryServices
- Create proper service initialization in main.rs
Clean Architecture improvements:
- Domain layer no longer depends on serde framework
- Persistence concerns isolated to infrastructure layer
- TokenClaims in auth_service.rs is only exception (required for JWT)