diff --git a/docs.json b/docs.json index 80d9c2d..63ea46f 100644 --- a/docs.json +++ b/docs.json @@ -264,6 +264,7 @@ "reference/networks-and-endpoints", "reference/authentication-matrix", "reference/product-and-sdk-map", + "reference/vfs-public-files", "reference/glossary" ] }, diff --git a/reference/vfs-public-files.mdx b/reference/vfs-public-files.mdx new file mode 100644 index 0000000..eee3bfc --- /dev/null +++ b/reference/vfs-public-files.mdx @@ -0,0 +1,235 @@ +--- +title: "VFS public files and folders" +description: "Publish files or folders from the IXO Virtual File System so anyone can download the decrypted content over plain HTTPS — no UCAN required." +--- + +The IXO Virtual File System (VFS) supports **publishing** files and folders. An explicitly-published item's decrypted content is downloadable by anyone over plain HTTPS with no `Authorization` header — a lightweight "share link" surface on top of the normal namespace + UCAN model. + +Use publishing when you want to: + +- Share a single file (report, PDF, image) with recipients who don't hold a UCAN. +- Expose a subtree as a static-site-shaped share (a whole folder becomes publicly downloadable). +- Offer a whole folder as a one-shot ZIP download. +- Let third parties browse what a namespace has chosen to publish. + +## Publishing rules + +- **Private by default.** Nothing is public unless it — or an ancestor folder — has been explicitly published. There is no naming convention that publishes anything implicitly. +- **A public folder publishes its whole subtree.** New uploads into a published folder inherit the flag. An item is *effectively public* when it, or any ancestor folder, is public. +- **Public overrides hidden.** Publishing means anyone can download the content, hidden or not. The `hidden` flag continues to gate the *authenticated* surfaces (where an `nb.hidden` reveal is still required), but never blocks public serving. Publishing a folder therefore also exposes its dotfiles. +- **Writes stay gated.** Publishing and unpublishing always require an `fs/write` UCAN — only *reading* is anonymous. Every change is audited, and anonymous reads land in the access log too. +- **Set, not toggle.** Every publish endpoint requires an explicit `true` or `false` value; omitting it returns `400`. + +## The three public URL forms + +All three routes live at the origin root (not under `/api/fs`), require no auth, stream the decrypted bytes, and return a uniform `404` for anything not servable (private, hidden-but-not-public, trashed, purged, or nonexistent). + +| URL | Semantics | Survives rename/move | Survives content edit | +| --- | --- | --- | --- | +| `GET /public/id/:id` | Canonical share link — this item, wherever it goes. | Yes | Yes | +| `GET /public/cid/:cid` | Immutable — exactly these bytes (plaintext IPFS CID). | Yes | No (new content = new CID) | +| `GET /public/:namespace/:path` | Mutable — the latest content at this location. | No | Yes | + +`` is the storage namespace verbatim: `user:` or `entity:`. + +``` +https://vfs.example/public/user:ixo1abc.../reports/q1.pdf +``` + +File metadata (`GET /api/fs/files/:id`) advertises the canonical link as `publicUrl` (relative — prepend the service origin) whenever the file is actually servable. + +### Response headers + +Public downloads stream with: + +- The file's original `Content-Type`. +- `Content-Disposition: attachment` and `X-Content-Type-Options: nosniff` — uploaded HTML never executes at the service origin; ``/`