Commit Graph

1445 Commits

Author SHA1 Message Date
Edouard Vanbelle 0a6368e1bf feat(plugins): annotation to allow panic 2026-07-03 02:27:48 +02:00
Edouard Vanbelle 92d1a10d45 security(quick-xml): bump version to 0.41.0
- and protect amount of properties
 - azure_core 0.21.0 is using quick-xml 0.31.0  which is Dos-able
   azure_core is no more maintained, would migrte to official azure lib
   later
2026-07-03 02:12:36 +02:00
Edouard Vanbelle dff0e7365e feat(drive): remove all user_id ref in file or folder 2026-07-03 02:12:32 +02:00
Edouard Vanbelle 37467ed9d3 feat(drive): remove all owner_id from {File,Folder}Dto 2026-07-03 01:13:53 +02:00
Edouard Vanbelle 29bcf48eb7 feat(drive): move UI to {created,updated}_by 2026-07-03 00:31:36 +02:00
Edouard Vanbelle 206a780494 feat(drive): stop writing in {file,folder}.user_id
plan:

    ```
    What step 5 is actually doing

    Goal: stop writing to storage.files.user_id / storage.folders.user_id on new INSERTs. This is a prerequisite for step 6 (dropping the column entirely). The column has existed since the pre-D0 single-owner era; every read that used to key on it has already been migrated to drive-membership grants over the last N days.

    What has to change together for this to be safe:

    ┌──────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬───────────────────────────────────────────────────────────────────────────────────────────────────────┐
    │    Piece     │                                                          What changes                                                           │                                                  Why                                                  │
    ├──────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤
    │ Migration    │ Swap storage.files uniqueness indexes from (folder_id, name, user_id) to (drive_id, folder_id, name)                            │ Otherwise, two new rows with user_id = NULL would both be allowed (PG treats NULLs as distinct) —     │
    │ (a)          │                                                                                                                                 │ uniqueness silently breaks                                                                            │
    ├──────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤
    │ Migration    │ ALTER user_id DROP NOT NULL on both tables                                                                                      │ Otherwise, dropping the INSERT bind violates NOT NULL and every write 500s                            │
    │ (b)          │                                                                                                                                 │                                                                                                       │
    ├──────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤
    │ Migration    │ Drop dead user_id-leading indexes                                                                                               │ Cheap cleanup — nothing scans them anymore                                                            │
    │ (c)          │                                                                                                                                 │                                                                                                       │
    ├──────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤
    │ PL/pgSQL (d) │ Rewrite storage.copy_folder_tree without user_id in the INSERT column list                                                      │ Cross-drive copy runs entirely in SQL, needs the same treatment                                       │
    ├──────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤
    │ Rust (e)     │ ~12 INSERT column-list drops across folder_db_repository, file_blob_write_repository, drive_pg_repository, dedup_service,       │ Actual write path                                                                                     │
    │              │ folder_service, load-seed.rs                                                                                                    │                                                                                                       │
    ├──────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼───────────────────────────────────────────────────────────────────────────────────────────────────────┤
    │ Rust (f)     │ Simplify folder_db_repository::create_folder's parent lookup to only fetch drive_id (was fetching (user_id, drive_id))          │ It's fetching a value it no longer needs                                                              │
    └──────────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴───────────────────────────────────────────────────────────────────────────────────────────────────────┘
    ```
2026-07-03 00:23:35 +02:00
Edouard Vanbelle 25dcab8e85 feat(drive): dedup service move user_id to authz 2026-07-02 21:10:12 +02:00
Edouard Vanbelle a0e5c34950 feat(webdav): impl if header RFC 4918 §10.4
this fix an issue raised by webdav litmus test
2026-07-02 20:59:18 +02:00
Edouard Vanbelle 91435e6be1 feat(drive): webdav handler based on drive
and add authz
2026-07-02 20:41:33 +02:00
Edouard Vanbelle f5f5b1167f feat(drive): remove _for_owner() and use authz
remove related IDOR protection as Hurl tests are covering this surface
2026-07-02 01:14:02 +02:00
Edouard Vanbelle 09790644f3 feat(drive): repl user_id by caller has read access
repl user_id by caller has read access in readonly functions
    using CALLER_CAN_READ_DRIVE constant

    ensure webdav preview is using the permission handler
2026-07-02 01:03:39 +02:00
Edouard Vanbelle 79bc60899b feat(drive): improvepermission check and simplify functions 2026-07-02 00:29:33 +02:00
Edouard Vanbelle 858139ef3b feat(drive): prepare removal of user_id
this commit changes GET /api/<resources> to return resource caller has access to
    this is not anymmore resources users is owner of
2026-07-02 00:01:20 +02:00
Edouard Vanbelle 09339ea63f feat(drive): UI: show policiesto drive's members
and add tests
2026-07-01 22:35:08 +02:00
Edouard Vanbelle 01ff7dab0b feat(drive): impl policy photo + music policies
add `include_in_photo_index` and `include_in_music_index` policies
    both true for default personal drive

    photo is implemented
    music is not yet implemented
2026-07-01 21:57:37 +02:00
Edouard Vanbelle 20e5ef0ef2 feat(drive): personal drive are photo + music indexed by default 2026-07-01 21:28:00 +02:00
Edouard Vanbelle 473c126291 doc(drive.md): face recognition cluster per drive 2026-07-01 21:09:56 +02:00
Dionisio Pozo e7e7218e9b Merge pull request #540 from EdouardVanbelle/chore/git-hash-in-docker-build 2026-07-01 07:53:36 +02:00
Dionisio Pozo fba7b67a1f Merge pull request #539 from EdouardVanbelle/feat/metadata-binded-to-resource-id 2026-07-01 07:53:19 +02:00
Edouard Vanbelle 0567082ad5 chore(docker): add git branch in docker build 2026-07-01 00:35:40 +02:00
Edouard Vanbelle d134fc889d doc(metadata): bride dead props to API metadata
what about exposing dead props into rest API

    let user to store preferences, labels on resources

    | Use case | What it looks like | Why dead-props help |
    |---|---|---|
    | Photo annotations | captions, ratings (1-5), notes per photo | already keyed by `file_id`; round-trips via WebDAV without re-implementing |
    | Web-UI tags / labels | `oxi:user:tag/project=alpha`, color flags, "archived" markers | per-resource user metadata without new tables |
    | Folder UI preferences | default sort, default view mode, "favourite" flag | persistent per-folder, shared across users on shared drives |
    | Cross-protocol bridge | Thunderbird sets `oxi:lastsync=...` via PROPPATCH → web UI reads it via REST | one store, two surfaces — visibility goes both ways |
    | Workflow / approval state | `reviewed_by=alice`, `due=2026-09-15` | ad-hoc state per resource without schema sprawl |
    | Third-party integrations | external apps store scratch space per resource | lower barrier than implementing WebDAV |
2026-07-01 00:29:33 +02:00
Dionisio Pozo 962fd42c99 Merge pull request #537 from EdouardVanbelle/feat/webdav-dead-properties 2026-07-01 00:00:27 +02:00
Edouard Vanbelle d8adae3572 feat(dead-props): ensure replication on copy 2026-06-30 23:48:44 +02:00
Edouard Vanbelle cb7b653a15 feat(webdav): bind dead prop to res. id rather path 2026-06-30 23:35:25 +02:00
Edouard Vanbelle f2dc567bcd chore(justfile): api-test: add litmus webdav
play listmus webdav test only if found locally
2026-06-30 23:21:28 +02:00
Edouard Vanbelle 743fcc1075 chore(test): ignore tests/webdav/storage-litmus 2026-06-30 22:58:13 +02:00
Edouard Vanbelle cf1479d113 test(webdav): cover nested folder move
this test is a duplicated with the move in litmus test suite
    it has been added because not everybody do have litmus installed
    and no clue if litmus will be kept in the future
2026-06-30 22:55:49 +02:00
Edouard Vanbelle 2942b9b01b chore(test): rfc4918_proppatch is covered by Hurl
this but manifestonly with lookup by path, which is why hurl
    tests on API did not see it
2026-06-30 22:51:04 +02:00
Edouard Vanbelle 125eb66098 fix(drive): move correct cascade of lpath 2026-06-30 22:47:52 +02:00
Edouard Vanbelle d52c1a2397 fix(webdav): partial fix: remove dead props on del
ensure that dead properties are correctly deleted on resource deletion

    **IMPORTANT**: this is a partial fix:
    dead properties are not deleted if resource is deleted from API !
    code need to be reviewed to attach property directly to resource + use on delete cascade
2026-06-30 21:00:02 +02:00
Edouard Vanbelle 21ac3a178f test(webdav): cover the dead properties 2026-06-30 20:32:16 +02:00
Edouard Vanbelle 85bc6c51de fix(test): fix quota test (race condition in test) 2026-06-30 20:27:15 +02:00
Edouard Vanbelle 1e2882973b fix(test): correct due to commit 43cf4a2bg
- MKCOL is now better protected
    - Webdav now handle 201 (created) 204 (overritten)
2026-06-30 20:18:19 +02:00
Edouard Vanbelle 5631b7e062 fix(sql macro): permit code to compile 2026-06-30 19:46:19 +02:00
Dionisio Pozo 08f2175455 Merge pull request #535 from swissiety/webdav-litmus-compliance
[QA] integrate litmus (WebDAV server protocol compliance test suite) into ci workflow and fix uncovered compliance issues
2026-06-30 17:16:13 +02:00
M.Schmidt 6ca6649e50 fix(webdav): achieve 100% litmus compliance (59/59 tests)
Complete RFC 4918 litmus test suite compliance (basic 16/16,
copymove 13/13, props 30/30) by fixing six categories of failures:

- PropPatchOp: parse PROPPATCH in document order (RFC 4918 §9.2)
  so that remove-then-set and set-then-remove yield different results
- Null namespace: resolve_name now correctly maps xmlns="" to empty-ns
  QualifiedName instead of falling through to DAV: namespace
- Unicode chars: handle quick-xml 0.39's Event::GeneralRef for character
  references (&#65536;) — the parser emits these as GeneralRef, not Text
- MOVE preserves dead props: call rename_resource on MOVE, clearing
  stale destination data even when source has no registered properties
- Malformed PROPFIND: return 400 when body lacks a complete <propfind>
  element (test 2: bare <foo>, test 3: invalid xmlns:prefix="" binding)
- PROPPATCH document order: process ops via Vec<PropPatchOp> instead of
  separate (sets, removes) to honour interleaved remove/set sequences
2026-06-30 08:58:13 +02:00
Dionisio Pozo 3a7ca6722c Merge pull request #534 from EdouardVanbelle/feat/drive 2026-06-29 23:47:34 +02:00
Edouard Vanbelle 934d6b4af0 feat(drive): NC chunked upload respect drive's quota
personal drive are based on user's quota
2026-06-29 23:21:17 +02:00
Edouard Vanbelle 583af517c2 fix(drive): fix drive_id on copy to other drive
- fix alsot drive_id exposition
2026-06-29 23:21:17 +02:00
Edouard Vanbelle e81b297f68 feat(drive): can move|copy to other drives 2026-06-29 23:21:13 +02:00
M.Schmidt 43cf4a2b2b fix(webdav): RFC 4918 handler compliance (COPY/MOVE/MKCOL/PROPFIND/PROPPATCH)
- COPY: return 403 on self-copy, 409 when destination parent missing,
  409 (not 500) when overwriting a locked or conflicting resource
- MOVE: same parent-missing and conflict handling as COPY
- MKCOL: return 405 when collection already exists, 409 when parent
  is missing (no auto-creation of ancestors)
- PUT: return 201 Created for new resources, 204 No Content for overwrites
- PROPFIND: use client-facing URI path (not internal home-folder path)
  for DAV:href values so responses match the request URI
- PROPFIND: include dead properties from DeadPropertyStore in responses
- PROPPATCH: persist set/remove operations to DeadPropertyStore
2026-06-29 22:33:09 +02:00
Edouard Vanbelle ee92d365b9 feat(drive): ensure drive_id updated on file|folder moved to another drive 2026-06-29 21:11:40 +02:00
Edouard Vanbelle acf2311cea test(oidc): ensure that static-dist is built to validate tests 2026-06-29 21:10:26 +02:00
Dionisio Pozo bfb1751f17 Merge pull request #532 from EdouardVanbelle/test/oidc
test(OIDC): sanity check with OIDC
2026-06-29 08:44:12 +02:00
M.Schmidt 1cf48b0dfa fix(webdav): RFC 4918 PROPFIND adapter compliance
- Return unknown properties in a separate 404 propstat (RFC 4918 §9.2)
  via folder_prop_is_known/file_prop_is_known classifiers
- Detect unclosed <propfind> element and return 400 Bad Request
- Add write_folder/file_entry_with_dead_props to include stored dead
  properties in PROPFIND responses
- Change write_folder/file_requested_props to accept &[&QualifiedName]
  to avoid clone overhead when using partition output
2026-06-28 23:51:38 +02:00
Edouard Vanbelle ada4b021bf test(oidc): test OIDC login and refresh flow
- ensure Oxicloud s correctly functional with OIDC login
    - refresh token works
    - givenname, familyname, picture are imported in users' informations
    - test relogin (server is not using same path)
    - test email verified
    - test admin group provided from IdP
2026-06-28 23:22:37 +02:00
Edouard Vanbelle 324fcd486f fix(oidc): fix user's picture copy when OIDC login 2026-06-28 23:20:02 +02:00
Dionisio Pozo 8ed8fe8a20 Merge pull request #527 from EdouardVanbelle/feat/drive 2026-06-26 22:44:56 +02:00
M.Schmidt b5afa1a855 feat(webdav): implement RFC 4918 dead property store
Add an in-memory DeadPropertyStore backed by RwLock<HashMap> that
stores arbitrary client-supplied XML properties per resource path.
Wire it into AppState so PROPPATCH can persist dead props and PROPFIND
can retrieve them across requests.
2026-06-26 21:19:03 +02:00
Edouard Vanbelle 9697c63210 deps(security): bump pdf-extract → 0.12.0 to pull lopdf 0.42.0
lopdf <0.42.0 has an unbounded-recursion stack overflow on deeply
nested PDF objects (advisory 2026-06-21). The vector through OxiCloud
is the search-index text extractor — anyone who can upload a file can
ship a malicious PDF, and the existing catch_unwind in
text_extractor::extract_pdf does not save us: a stack overflow aborts
the process, it is not a panic.

pdf-extract 0.12.0 requires lopdf ^0.42 which adds the depth bound;
the only consumer call (`extract_text_from_mem`) is API-compatible,
no source changes needed.
2026-06-26 18:57:44 +02:00