Commit Graph

44 Commits

Author SHA1 Message Date
Edouard Vanbelle 8fc9a50681 feat(passwordless): add cookie challenge + low TTL
magic-link as now 2 modes:

        - invitation: long TTL (24), no challenge
        - passwordless login: short TTL (10min), cookie challenge to ensure that
        user goes back to same browser (no man in the middle capturing email)
2026-06-03 00:35:25 +02:00
Edouard Vanbelle 130ff363dc feat(passwordless): pass4: add env variable to enable mgaiclink on account with password
OXICLOUD_MAGIC_LINK_OPEN_TO_PASSWORD_USERS (default false)
    For security I recommand to keep it false
    OIDC cannot be bypassed because OIDC may have MFA in place
2026-06-03 00:35:25 +02:00
Edouard Vanbelle 21c06da700 feat(magic-links): add rate limiting + archirecture documentation 2026-06-03 00:32:00 +02:00
Edouard Vanbelle df438b8269 feat(external user): add OXICLOUD_EXTERNAL_EMAIL_DOMAINS for allow list 2026-06-03 00:31:59 +02:00
Edouard Vanbelle c3fa1b3e93 feat(magiclink) prepare magic link support (login via email)
imortant on security side: magic link  will be enabled only for users who don't have password nor OIDC
2026-06-03 00:31:59 +02:00
Edouard Vanbelle 2011d19e71 feat(smtp): add SMTP support to reach MTA 2026-06-03 00:31:59 +02:00
Edouard Vanbelle ad711e18ea feat(contacts): add feature flag to enable/disable exposition of users in address-book 2026-05-10 22:12:11 +02:00
Edouard Vanbelle b90fa6f619 security: prevent re-use of refresh token (reduce surface for any stolen token)
Security: session hardening

  Refresh token rotation with theft detection (family_id)
  - Added family_id column to auth.sessions (migration 20260507000000_session_family.sql) grouping all tokens issued from the same login into a family
  - On refresh, the new session inherits the parent's family_id
  - If a revoked token is replayed (indicates the token was stolen after rotation), the entire family is immediately invalidated and a warning is logged — forcing re-authentication on all devices

  SameSite=Strict on refresh cookie
  - Access cookie stays SameSite=Lax (needed for top-level navigation)
  - Refresh cookie upgraded to SameSite=Strict — it is only ever used for explicit POST to /api/auth/refresh, never via cross-site navigation

  Refresh token TTL: 30 days → 7 days
  - With rotation, active sessions auto-renew and effectively never expire
  - Inactive sessions expire after 7 days instead of 30, reducing the theft window
2026-05-07 13:57:10 +02:00
Diocrafts cd3733b459 feat: pluggable storage backends (S3, Azure, local) with admin UI
Implement 4-phase external storage backends architecture:

Phase 1 - Foundation:
- BlobStorageBackend trait (application/ports/blob_storage_ports.rs)
- LocalBlobBackend: extracted all tokio::fs ops from DedupService
- S3BlobBackend: AWS SDK with custom endpoint support (MinIO, R2, B2)
- DedupService refactored to use Arc<dyn BlobStorageBackend>

Phase 2 - Admin Panel:
- StorageSettingsService with DB persistence + env override
- Storage tab in admin panel (backend selector, S3 form, provider presets)
- GET/PUT/POST endpoints for storage settings + connection test
- i18n keys (en/es) and BEM CSS

Phase 3 - Migration:
- MigrationBlobBackend decorator (dual-read: target-first + source fallback)
- Background migration job with parallel transfers + progress tracking
- Migration UI (progress bar, ETA, pause/resume/verify/complete)
- 6 admin API endpoints for migration lifecycle

Phase 4 - Enterprise Extras:
- CachedBlobBackend: LRU disk cache for remote backends
- EncryptedBlobBackend: AES-256-GCM at-rest encryption
- AzureBlobBackend: Azure Blob Storage support
- RetryBlobBackend: exponential backoff for transient errors
- Decorator composition in DI: retry → encryption → cache

All 223 tests passing, clippy clean, fmt verified.
2026-04-14 21:33:38 +02:00
Andrey Tkachenko da066f47fa Music Player & Playlist Manager 2026-04-08 15:14:03 +03:00
Edouard Vanbelle badf35f08f chore: remove all executable attributes on non bash files 2026-04-01 23:14:42 +02:00
Claude dacb8f388e fix(thumbnail): add timeout protection for large image processing
Resolves conflict between main and PR #229 by applying timeout support
on top of main's drop(data) memory optimization. Changes:
- Add thumbnail_generation_ms to TimeoutConfig (default 30s)
- Add generation_timeout field to ThumbnailService
- Wrap spawn_blocking in tokio::time::timeout to prevent hanging
- Update DI to pass timeout from config
- Update tests to provide timeout parameter

https://claude.ai/code/session_015FD62aAoMYx1XBZbzPvUu8
2026-03-28 18:40:34 +00:00
Edouard Vanbelle d78b279ec9 style: apply rust format + fix clippy warning 2026-03-26 10:05:44 +01:00
BillionClaw 0cbbb6b7ac fix: ARMv7 32-bit compilation overflow
The constant 10 * 1024 * 1024 * 1024 (10 GB) overflows on 32-bit systems
where usize is 32-bit (max ~4GB). This caused compilation failures on
ARMv7 architecture.

Fix by using architecture-appropriate limits:
- 64-bit: 10 GB (unchanged)
- 32-bit: 1 GB (safe maximum for 32-bit usize)

Fixes #206
2026-03-17 04:39:18 +08:00
Jared Wolff 4f7e79f605 style: collapse nested if-let in JWT secret config (clippy) 2026-03-05 16:37:47 -05:00
Dionisio f2d35ca792 feat: auto-persist JWT secret, remove setup token requirement
- JWT secret auto-generates and persists to <STORAGE_PATH>/.jwt_secret
- Remove setup token: first admin setup is open until system initialized
- Fix schema.sql: move CREATE EXTENSION pg_trgm/ltree to top
- Update login UI and auth.js to remove setup token fields
2026-03-05 22:12:53 +01:00
zjean 40b269c4eb fix: schema init, duplicate routes, and image preview bugs
- Move pg_trgm extension creation before CalDAV indexes that depend on it
- Remove duplicate app-password route registration that caused panic
- Fix missing comma in language selector array (Dutch entry)
- Await async canEdit() in file click handler (Promise was always truthy)
- Detect images by extension fallback when mime_type is octet-stream
  (files uploaded via Nextcloud WebDAV API lack correct mime types)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 20:46:28 +01:00
zjean 54eedf5483 feat(nextcloud): add Nextcloud-compatible API layer
Implement a complete Nextcloud client compatibility layer so that
Nextcloud desktop/mobile sync clients can connect to OxiCloud.

Key additions:
- Login Flow v2 (device auth) with OIDC bridge support
- WebDAV handler compatible with Nextcloud clients (PROPFIND, GET,
  PUT, DELETE, MKCOL, MOVE, COPY, HEAD, PROPPATCH)
- OCS API endpoints (user info, capabilities, notifications stubs,
  sharees, unified search)
- Basic Auth middleware with app password verification, account
  lockout integration, and blake3-keyed auth cache
- App password management: create, list, revoke via both native
  API (JWT-authenticated profile page) and Nextcloud OCS endpoints
- Nextcloud file ID mapping (oc:fileid) with persistent DB storage
- Chunked upload support (Nextcloud v2 chunking protocol)
- Trashbin WebDAV interface
- Avatar (SVG placeholder) and preview (redirect) handlers
- User profile page with app password management UI
- URL user validation on all DAV routes (403 on mismatch)
- Database schema for app_passwords and nextcloud_object_ids tables

All services are behind a `nextcloud.enabled` config flag and
cleanly separated under src/interfaces/nextcloud/.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 20:46:07 +01:00
Dionisio 4d81bcbd7b fix(security): V-01,V-02,V-04,V-05,V-06 - multiple vulnerability fixes
- V-01: CalDAV unbounded body limit → MAX_CALDAV_BODY = 1MB
- V-02: CardDAV unbounded body limit → MAX_CARDDAV_BODY = 1MB
- V-04: Batch operations without max size → MAX_BATCH_SIZE = 1000
- V-05: WOPI get_editor_url IDOR → authorize_wopi_access with ownership check
- V-06: JWT secret without entropy validation → panic <16, warn 16-31, accept >=32
2026-03-05 16:57:44 +01:00
Dionisio efcf88c4d7 style: cargo fmt --all 2026-03-03 01:49:18 +01:00
Dionisio 1df52fd702 security: add IP rate limiting + account lockout on auth endpoints
- Rate limit login (5/min), register (3/hr), refresh (10/min) per IP
- Account lockout after 5 consecutive failed logins (15 min cooldown)
- Fix stored XSS in admin panel (escapeHtml on all user-controlled data)
- All limits configurable via OXICLOUD_RATE_LIMIT_* / OXICLOUD_LOCKOUT_* env vars
- Zero new dependencies (uses existing moka crate for in-memory caches)
- Includes unit tests for lockout service
2026-03-03 01:44:39 +01:00
Dionisio 97cf6402e2 fix: resolve all clippy warnings and enforce cargo fmt
- display_helpers: convert module doc-comments to regular comments,
  merge identical text/markdown + text/ branches
- search_service: replace needless range loops with slice-based pagination
- folder_repository, folder_db_repository: collapse nested if statements
- favorites_pg_repository: remove unnecessary borrow on generic arg
- file_blob_read_repository: collapse 6 nested if-let blocks
- file_blob_write_repository: collapse nested if for dedup ref decrement
- chunked_upload_service: use div_ceil(), collapse 2 nested if blocks
- folder_handler: collapse nested if-let for owner check
- webdav_handler: replace 7x io::Error::new(ErrorKind::Other, ..) with
  io::Error::other(..)
- cargo fmt applied to all files

Passes: cargo clippy --all-targets --all-features -- -D warnings
2026-02-25 10:28:34 +01:00
Dionisio 9f692f03c3 Implement dual DB pools (primary + maintenance) and wire services 2026-02-24 19:28:00 +01:00
Dionisio 28966ce28e optimize folder search: SQL-level filtering, user isolation, no in-memory filter; batch cascade trigger 2026-02-24 17:15:36 +01:00
Diocrafts 92e0364a60 fix: OOM protection, lock-free thumbnail cache, OIDC JWKS TTL
- Streaming WebDAV PUT: body spooled to tempfile with incremental SHA-256,
  peak RAM ~64KB regardless of file size (Solution 2)
- RequestBodyLimitLayer (1MB) on CalDAV/CardDAV routers (Solution 3)
- All body::to_bytes(body, usize::MAX) replaced with explicit limits:
  PROPFIND/PROPPATCH/LOCK → 1MB, MKCOL → 4KB
- Added AppError::payload_too_large (HTTP 413)
- Added max_upload_size to StorageConfig (default 10GB, env override)
- New streaming update chain: FileWritePort::update_file_content_from_temp
  → FileUploadUseCase::update_file_streaming
- ThumbnailService: migrated from RwLock<LruCache> to moka::future::Cache
  with weight-based eviction — eliminates lock contention on read hot-path
- OIDC: discovery + JWKS caches now expire after 1 hour (Cached<T> wrapper)
  so IdP key rotation no longer requires server restart
2026-02-22 23:28:03 +01:00
George Wu 2c428678b6 docs: add example.env and document all environment variables
- Create example.env with all 31 environment variables documented
- Update docker-compose.yml to use env_file directive
- Update doc/deployment.md with Quick Start and missing variables
- Add OXICLOUD_BASE_URL and WOPI configuration docs
- Update README.md Docker section with .env setup
- Remove duplicate port mapping (incorporates 4577e56)
- Fix server port default from 8085 to 8086
2026-02-21 18:44:38 -08:00
Jan Wiebe 4e2c9d2592 feat(wopi): add WOPI protocol support for collaborative editing
Implement the Web Application Open Platform Interface (WOPI) protocol
to enable collaborative document editing with Collabora Online and
OnlyOffice through OxiCloud.

Backend:
- WOPI token service with HMAC-SHA256 signed access tokens
- WOPI lock service with in-memory lock management and expiry
- WOPI discovery service for auto-detecting editor capabilities
- WOPI HTTP handler: CheckFileInfo, GetFile, PutFile, Lock/Unlock
- File entity extended with owner_id for WOPI file-info responses
- Configuration via WOPI_* environment variables
- Services wired through DI in AppState

Frontend:
- WOPI editor component with modal and new-tab viewing modes
- Context menu integration for opening files in online editors
- Inline viewer integration for document preview

Infrastructure:
- Docker Compose file for local Collabora/OnlyOffice dev setup

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 13:39:27 +01:00
Dionisio 4c98c5a657 style: apply cargo fmt to entire codebase
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.
2026-02-14 01:29:34 +01:00
Dionisio 67137a3ef2 refactor: apply clippy auto-fixes (162 warnings resolved)
- Fix needless borrows and references
- Collapse nested if statements
- Replace manual strip_prefix with str::strip_prefix()
- Remove redundant closures in map/unwrap_or_else
- Use Iterator::next_back() instead of rev().next()
- Simplify map_or patterns
- Use std::io::Error::other() instead of new(ErrorKind::Other, ..)
- Use div_ceil() instead of manual ceiling division
- Consolidate format! string arguments
- Various other idiomatic Rust improvements

39 files changed, 220 insertions(+), 320 deletions(-)
2026-02-14 01:26:02 +01:00
Dionisio 099d1d1c55 fix: share URL respects scheme in OXICLOUD_SERVER_HOST (#103)
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
2026-02-14 00:18:59 +01:00
Dionisio 76d9038e5b fix: resolve compiler warnings and downgrade JWT secret log to warn
- 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
2026-02-12 12:29:12 +01:00
Dionisio d31a413e57 chore: translate all Spanish comments and log messages to English 2026-02-12 09:41:25 +01:00
Dionisio f60c0df9f9 feat(admin): add admin settings panel for OIDC configuration
- Admin UI at /admin.html with settings management interface
- REST API: GET/PUT /api/admin/settings/oidc, POST .../test, GET .../general
- DB-backed settings in auth.admin_settings table (PostgreSQL)
- OIDC auto-discovery from issuer URL (.well-known/openid-configuration)
- Hot-reload: OIDC config changes apply without server restart
- Role-based access: admin-only endpoints with 403 for regular users
- Client secret stored securely, never exposed in GET responses
- Env var override detection shown in admin UI
- Clean architecture: repository trait, PG implementation, service, handler
2026-02-11 00:15:26 +01:00
Dionisio 8ef62109a3 feat(auth): add OpenID Connect (OIDC) authentication support
Implements OIDC Authorization Code Flow for external identity providers
(Authentik, Keycloak, etc.) with JIT user provisioning.

New features:
- OidcService with OpenID Discovery, JWKS caching, RS256 ID token validation
- Authorization Code Flow: /api/auth/oidc/authorize -> IdP -> /api/auth/oidc/callback
- JIT user provisioning from OIDC claims (sub, email, name, groups)
- OIDC group-to-role mapping (admin_groups config)
- Provider info endpoint: GET /api/auth/oidc/providers
- Option to disable password login entirely (OXICLOUD_OIDC_DISABLE_PASSWORD_LOGIN)
- Auto-provision toggle (OXICLOUD_OIDC_AUTO_PROVISION)
- Email collision detection (security: prevents account takeover)

Configuration (env vars):
- OXICLOUD_OIDC_ENABLED, OXICLOUD_OIDC_ISSUER_URL
- OXICLOUD_OIDC_CLIENT_ID, OXICLOUD_OIDC_CLIENT_SECRET
- OXICLOUD_OIDC_REDIRECT_URI, OXICLOUD_OIDC_SCOPES
- OXICLOUD_OIDC_FRONTEND_URL, OXICLOUD_OIDC_PROVIDER_NAME
- OXICLOUD_OIDC_AUTO_PROVISION, OXICLOUD_OIDC_ADMIN_GROUPS
- OXICLOUD_OIDC_DISABLE_PASSWORD_LOGIN

DB migration:
- ALTER TABLE auth.users ADD oidc_provider, oidc_subject columns
- UNIQUE index on (oidc_provider, oidc_subject)

Files changed: 14 files, ~1400 lines added
Dependencies: reqwest 0.12 (rustls-tls-webpki-roots), base64 0.22
2026-02-10 20:32:32 +01:00
Diocrafts a82faa5eaf refactoring hexagonal and clean architecture 2026-02-08 13:40:23 +01:00
Dionisio 52840e57df refactor: remove serde from domain entities for Clean Architecture compliance
- 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)
2026-02-02 23:56:40 +01:00
DioCrafts 3a4cb75ac7 configuring backend topology 2025-03-28 12:38:48 +01:00
DioCrafts 7affff379d adding search engine 2025-03-27 01:13:34 +01:00
DioCrafts bd623ec07e adding trash folder 2025-03-24 17:49:53 +01:00
DioCrafts 38b0e9594b fix auth errors and add primigenial paper trash 2025-03-24 16:47:42 +01:00
DioCrafts 9a9fd72f61 fixing bugs 2025-03-23 22:44:18 +01:00
DioCrafts cafad0fbfd adding user authentication 2025-03-20 09:22:31 +01:00
DioCrafts 6e055c3043 adding features 2025-03-19 19:52:12 +01:00
DioCrafts d9bbd575d2 adding several features 2025-03-19 00:44:27 +01:00