Skip to content

feat(sharings): Effective recipients endpoints - #4885

Open
taratatach wants to merge 3 commits into
masterfrom
feat/add-effective-recipients-endpoints-for-nested-shared-folders
Open

feat(sharings): Effective recipients endpoints#4885
taratatach wants to merge 3 commits into
masterfrom
feat/add-effective-recipients-endpoints-for-nested-shared-folders

Conversation

@taratatach

Copy link
Copy Markdown
Contributor

Closes #4840

What

Two new read-only endpoints returning the combined list of people who can
access a file or folder, including access inherited from parent shared
folders:

  • GET /sharings/recipients/:file-id
  • GET /sharings/drives/:id/recipients/:file-id

How

  • AccessResolver.applicableSharings (extracted from scopesFor) resolves
    every active additive scope applying to the target — its own share plus
    shares inherited from ancestor folders — with no membership filtering.
  • EffectiveRecipients collects the direct members of every applicable
    io.cozy.sharings doc (revoked members excluded), deduplicates by
    instance with an email fallback, lets read-write win over read-only,
    and keeps the most advanced status.
  • Each recipient exposes its sources (sharing_id, root_id,
    root_name, kind, member_index, read_only, manageable) and a
    can_edit_here flag (true when at least one source is the target's own
    share).
  • JSON-API response, with the target file_id in meta.

Security / authorization

  • Classic endpoint: the caller needs at least read access to the file.
  • Drive endpoint: the caller must be a member of the drive (active drive)
    and the target must belong to that drive.
  • Public share tokens (share-by-link, share preview) are rejected: a link
    holder must not be able to enumerate sharing members.

No mutation: these are read-only endpoints, no inherited member is copied
into child sharings.

Tests

  • model/sharing/effective_recipients_test.go: deduplication
    (instance/email/bridge between the two), read-only/status merging,
    revoked exclusion, manageable.
  • web/sharings/effective_recipients_test.go: both endpoints, inheritance
    from ancestors, public token rejection, error cases (target outside the
    drive, inactive drive, non-member).

  Factor the resolution of sharings applying to a target out of
  `scopesFor`, without the membership filter, so the effective
  recipients computation can reuse it. The root info now carries the
  root name, and sharing IDs are sorted to keep a deterministic order
  between identical calls.
@taratatach taratatach self-assigned this Jul 28, 2026
@shepilov

Copy link
Copy Markdown
Member

why do we need 2 apis? why not only sharings/drives/:id/recipients/:file-id ?

@shepilov

shepilov commented Jul 29, 2026

Copy link
Copy Markdown
Member

why do we need 2 apis? why not only sharings/drives/:id/recipients/:file-id ?

ok, I got it, but then we need to proxy call to an owner instance and check the permission on the owner side

and maybe it's also time to have only one API insted of two, especially if we don't need to support legacy ones and to have somehting like GET /sharings/recipients/:file-id?drive_id=:drive-id

@taratatach

Copy link
Copy Markdown
Contributor Author

why do we need 2 apis? why not only sharings/drives/:id/recipients/:file-id ?

and maybe it's also time to have only one API insted of two, especially if we don't need to support legacy ones and to have somehting like GET /sharings/recipients/:file-id?drive_id=:drive-id

It is part of the spec and it seemed reasonable since we have separate routes for everything related to drives at the moment.
I'd suggest keeping it that way until we refactor that to use regular files routes.

@taratatach
taratatach force-pushed the feat/add-effective-recipients-endpoints-for-nested-shared-folders branch from 4049a67 to f7b0947 Compare July 30, 2026 17:18
}

func (a *apiEffectiveRecipient) ID() string { return a.id }
func (a *apiEffectiveRecipient) Rev() string { return "" }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need all these fields in this model? links, relationships, rev? we don't have them, actually

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's the JSON-API interface.

@taratatach
taratatach force-pushed the feat/add-effective-recipients-endpoints-for-nested-shared-folders branch 3 times, most recently from 377e1d6 to 54132bd Compare July 31, 2026 12:14
  Add a read-only view combining the people who can access a file or
  folder through its own share and through inherited ancestor shares.
  Recipients are deduplicated by instance with an email fallback,
  read-write wins over read-only, the most advanced status is kept via
  `statusRank`, and each recipient exposes the sources through which
  the access is granted. No sharing document is mutated.
  Expose `GET /sharings/recipients/:file-id` and `GET
  /sharings/drives/:id/recipients/:file-id` returning the effective
  recipients of a file or folder as JSON-API. Public share tokens
  (share-by-link, share preview) are rejected: a link holder must not
  enumerate sharing members. The response meta carries the target
  `file_id`.

  The drive route goes through the shared-drive `proxy()`: on a
  recipient instance the request is forwarded to the owner with the
  drive token, so the access check and the recipients resolution run
  where every sharing applying to the target is known. Membership is
  enforced owner-side by the `share-interact` permission.
@taratatach
taratatach force-pushed the feat/add-effective-recipients-endpoints-for-nested-shared-folders branch from 54132bd to 939b537 Compare July 31, 2026 15:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Effective recipients endpoints for nested shared folders

2 participants