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.
Public links
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:
- Capability token: full-entropy random token, not a guessable ID.
- Optional password: stored as a bcrypt hash; must be provided alongside the token.
- Expiry: mandatory TTL on creation; no indefinitely-valid links.
- Max downloads: optional hard limit on the number of times the link can be used.
- Scoped presigned URL: issued only after the link is validated (token + optional password). The presigned URL is scoped to the exact key with a short TTL.
:::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 |