Sharing

Purpose

Sharing is the access resolution layer that spans Identity and File & Metadata. Access control is security-sensitive; keeping it in a dedicated module ensures the authz story is coherent, testable, and auditable in one place.

Data owned

Table Purpose
shares Internal grants: user/group → node, permission level
share_links Public link records: capability token, password hash, expiry, download counter
permissions Resolved permission cache (may be materialized for complex ACLs)

Internal API

Sharing.* gRPC methods:

Method Description
Sharing.GrantAccess Create an internal share grant (user or group → node)
Sharing.RevokeAccess Remove a grant
Sharing.CreateLink Create a public share link; return capability token
Sharing.RevokeLink Invalidate a public link
Sharing.ResolveAccess Check whether a principal has a given permission on a node
Sharing.ResolveLink Validate a public link token; return node + allowed operations

Share types

Internal grants

An internal grant assigns a named permission level to a specific user or group for a specific node. Grants are recursive by default: permission on a folder propagates to its children unless overridden.

A public link is a capability token — a random, high-entropy URL token — that grants access to a node without requiring an account. Public link security is defined in ADR-0037:

:::warning Public link tokens must be capability tokens with full cryptographic entropy, not guessable sequential IDs or short codes. Password hashing uses bcrypt with a sufficient cost factor — never a fast hash (MD5, SHA-1, etc.). :::

Permission levels

Level Allowed operations
view Read content, download, list folder
edit All view ops + upload, rename, move within the share root
manage All edit ops + grant/revoke access, delete, change share settings

Access check in the request path

The Gateway calls Sharing.ResolveAccess (for authenticated users) or Sharing.ResolveLink (for public links) before issuing any presigned URL or returning file content. The result may be cached in Redis with a short TTL to avoid a round-trip on every byte-range request.

Authz happens before URL issuance. Once a presigned URL is issued, it is scoped and time-limited; the object store enforces it independently.

Events emitted

Event Subject Trigger
ShareCreated share.created New internal grant or public link created
ShareRevoked share.revoked Grant or link revoked