Commit Graph

806 Commits

Author SHA1 Message Date
Edouard Vanbelle 28e25f9d16 fix+test: check hash ref count on copy-on-write (a duplicated beeing updated) 2026-05-13 15:55:41 +02:00
Edouard Vanbelle 78cb37b311 feat: check thumbnail cleanup on files deletion + correct ref counter 2026-05-13 15:55:38 +02:00
Edouard Vanbelle 9dd5877bb2 chore: update comments to reflect hash alg used (SHA-256 -> Blake3) 2026-05-13 15:55:37 +02:00
Edouard Vanbelle f7946028f4 tests: add webdav tests 2026-05-13 15:55:34 +02:00
Edouard Vanbelle 07d1f18bf4 test API thumbnail fix on updates 2026-05-13 10:17:47 +02:00
Edouard Vanbelle 9f57776ec9 bugfix/thumbnails on update
Bug 1 & 2 (webdav_handler.rs handle_put() update branch):
  - After a successful file update via WebDAV PUT, if the content type is a supported image:
    a. delete_thumbnails(file_id) — evicts the stale moka cache entry
    b. Spawns a background task to read the new blob bytes and call generate_all_sizes_background_from_bytes

  Bug 3 & 4 (dedup_service.rs):
  - Added thumbnail_service: Option<Arc<ThumbnailService>> field with a with_thumbnail_service() builder
  - In remove_legacy_reference(): calls delete_blob_thumbnails(hash) when ref_count hits 0
  - In remove_manifest_reference(): calls delete_blob_thumbnails(file_hash) when manifest's last ref is dropped
  - Wired in di.rs — the thumbnail service is created before dedup service so the ordering works cleanly
2026-05-12 09:00:26 +02:00
Dionisio Pozo f62562d585 Merge pull request #362 from EdouardVanbelle/feat/copyFolder 2026-05-12 01:16:39 +02:00
Edouard Vanbelle 1afacb65cd style(srv): correct clippy recos 2026-05-12 00:34:11 +02:00
Edouard Vanbelle b4d4056a15 fix/security: move_folder(): check that target belongs to caller 2026-05-12 00:29:04 +02:00
Edouard Vanbelle 3a18507158 fix/security: copy_file_owned(): ensure that target is also owned by the user 2026-05-12 00:28:42 +02:00
Edouard Vanbelle e953236589 test(api): add functional test on copy_folder 2026-05-12 00:28:42 +02:00
Edouard Vanbelle 2f49daa4ee feat(folders): implement copy_folders taking care of ownership 2026-05-12 00:22:51 +02:00
Edouard Vanbelle 85c8c086ac fix(ui): fix go to parent + refactor types 2026-05-12 00:22:51 +02:00
Dionisio Pozo a4f8805bce Merge pull request #361 from EdouardVanbelle/test/api-critical-path 2026-05-11 20:22:50 +02:00
Edouard Vanbelle a0aa9c5cd1 ci: trigger test on /tests change 2026-05-11 20:00:22 +02:00
Edouard Vanbelle 5df4075f7f test(api): add API test coverage on files, folders, favorites, recent, trash 2026-05-11 19:31:12 +02:00
Dionisio Pozo 24c59989be Merge pull request #358 from EdouardVanbelle/feat/dropzone-only-on-files-section 2026-05-11 18:08:11 +02:00
Dionisio Pozo 57c6b3f57d Merge pull request #359 from EdouardVanbelle/feat/contacts 2026-05-11 15:30:13 +02:00
Edouard Vanbelle a6923da88a ci: build, api-test, front-test only on pull_request 2026-05-11 12:12:07 +02:00
Edouard Vanbelle d8625b9f39 ci: merge end-to-end workflow into ci, permits to reduce amount of built 2026-05-11 12:10:15 +02:00
Edouard Vanbelle cc14ec53ee ci(api-tests): add API test to CI 2026-05-11 10:53:59 +02:00
Edouard Vanbelle 8ab537797a test(api): add API test on contacts
next will be to add CI on it
2026-05-11 00:53:29 +02:00
Edouard Vanbelle 03aac93db3 chore: add /status /ready best practices for Docker & K8S 2026-05-11 00:53:25 +02:00
Edouard Vanbelle 8b08ee165d doc: update example.env and docs/config/env.md 2026-05-10 22:12:55 +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 7e1484ec2c chore(ui): correct about's github url 2026-05-10 22:08:25 +02:00
Edouard Vanbelle 89ec0d2c24 feat(contacts): add API to address-books, contacts, groups
* full gateway to /carddav
 * add system readonly address-book issued from OxiCloud users
2026-05-10 00:39:25 +02:00
Edouard Vanbelle 6e4699ff9c feat(ui): drop from system available only on files section
* prevent dropzone if not on files section
 * show a notification to user to use files section
 * solve #357
2026-05-09 19:22:15 +02:00
Dionisio Pozo a6eb81a13a Merge pull request #354 from EdouardVanbelle/feat/ui-error-handling 2026-05-09 00:27:48 +02:00
Edouard Vanbelle 7697f3d35b feat(ui): handle errors on folder creation or folder/file renaming
- protect file_management_service::rename_file with validate_storage_name
 - remove specific rename modal and use the generic modal class (less duplicate)
 - handle errors on modal action: do not close the modal on error and display this error
 - hide "Go to parent folder" contextMenu if section is files and folder is the same as current one
2026-05-09 00:06:36 +02:00
Dionisio Pozo c2837eb52d Merge pull request #343 from EdouardVanbelle/e2e-tests 2026-05-08 23:56:02 +02:00
Dionisio Pozo cbddbdc3d5 Merge pull request #320 from EdouardVanbelle/feat/client_ip 2026-05-08 23:55:41 +02:00
Edouard Vanbelle ddf6104749 chore(e2e-test): fix snapshot pixel ratio + try to reuse cargo build to reduce cpu consumption 2026-05-08 21:41:28 +02:00
Edouard Vanbelle 10f43e00a3 ci: retrigger playwright workflow 2026-05-08 21:41:28 +02:00
EdouardVanbelle b550a5def9 test(e2e): update playwright linux snapshots 2026-05-08 21:41:28 +02:00
Edouard Vanbelle 3c3d24ac72 test: initial end to end test with playwright 2026-05-08 21:41:28 +02:00
Dionisio Pozo 52f4a865a9 Merge pull request #349 from EdouardVanbelle/feat/item-path-tool-tip+go-to-parent
show item path on Recent + Favorite, add go to parent folder, fix Folder browsing in Favorites
2026-05-08 01:22:08 +02:00
Dionisio Pozo 71fd84dd9d Merge pull request #350 from EdouardVanbelle/fix/blank-section-on-token-expired
fix(ui): handle any session expired and trigger transparently a refresh token
2026-05-08 01:21:42 +02:00
Dionisio Pozo fec9bb1f96 Merge pull request #351 from EdouardVanbelle/security/refresh-token-rotation
security: prevent re-use of refresh token (reduce surface for any stolen token)
2026-05-08 01:21:27 +02:00
Dionisio Pozo 420eda22fb Merge pull request #353 from EdouardVanbelle/fix/sanity_check_files_and_folder_names
fix(storage names): enure folder and file names are not using reserved chars
2026-05-08 01:21:05 +02:00
Dionisio Pozo 9ed03fada5 Merge pull request #352 from EdouardVanbelle/fix/admin-missing-icons-library
fix(ui): admin panel, profile, etc: restore missing icons library
2026-05-08 01:20:52 +02:00
Edouard Vanbelle 6696ba3ae4 fix(storage names): enure folder and file names are not using reserved chars
- create common function `validate_storage_name()` to check files & folder name
 - replace previous duplicate check with this one
 - better check on create_folder rename_folder (was only checking non empty)
 - use correct error class to ensure 400 on API (was 500)

fix: #345
note: no unit test here, but plan e2e test for that
next: improve UI to display error
2026-05-08 00:26:44 +02:00
Edouard Vanbelle 93d9a21013 fix(ui): admin panel, profile: restore missing icons library 2026-05-07 22:43:02 +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
Edouard Vanbelle a69dde35ce fix(ui): handle any session expired and trigger transparently a refresh token
this change replace original window.fetch by a wrapper that check any 401 response, is so it will request a refresh token
this solve current issue with Favorites & Recent sections that give blank page when token is expired

- exclusion of requests to other domain (401 will not be handled here)
- security with shares /api/s is not handled

- check with CSRF, no risk
2026-05-07 00:55:21 +02:00
Edouard Vanbelle 8e1e9fe201 show item path on Recent + Favorites, add go to parent folder, fix Folder browsing in Favorites 2026-05-06 23:36:05 +02:00
Dionisio Pozo 405721c679 Merge pull request #346 from abnvle/fix/share-password-download 2026-05-05 23:44:36 +02:00
abnvle 8527765bf2 style(share-dialog): give share button breathing room
The Share button moved into .share-options in bdb5a6c sat flush
against the section bottom border. Adds 20px bottom padding plus
margin-top:16px and margin-left:auto on the button so it aligns
right with the Close button below.
2026-05-05 21:57:15 +02:00
abnvle 3bc5c0873b fix(share): password-protected downloads via signed unlock cookie
After successful POST /api/s/{token}/verify, the server issues a
short-lived signed JWT cookie (oxi_share_unlock_<token>; HttpOnly;
SameSite=Lax; 1h TTL). Subsequent /api/s/{token} and
/api/s/{token}/download requests honour the cookie to bypass the
password gate, so password-protected file downloads work end-to-end.

- New module src/infrastructure/services/share_unlock_cookie.rs:
  issue_jwt, verify_jwt, extract_from_cookie_header, build_set_cookie
  + 10 unit tests.
- New ShareService methods issue_unlock_jwt and
  get_shared_link_with_unlock; trait method get_shared_link_by_token
  delegates to a private fetch_share_resolved with an
  allow_password_protected flag.
- access_shared_item, verify_shared_item_password, and
  download_shared_file honour the unlock cookie.

Reuses OXICLOUD_JWT_SECRET, no new env var. Auth-token JWTs and
unlock-cookie JWTs cannot be confused: auth requires
username/email/role/jti claims, unlock has only sub/exp/iat.
Cross-share replay rejected via claims.sub == requested_token check.
2026-05-05 21:56:49 +02:00
Edouard Vanbelle d0c025c316 add X-Request-Id for each req, log all 400 errors 2026-05-05 09:44:25 +02:00