Remove cans feature; harden pw_/tok_ cookie flags (pre-release fixes) (#307)
This commit was merged in pull request #307.
This commit is contained in:
1 parent
651bc0cb86
commit
c02550050f
20 files changed
+176
-1367
No files matched your search
+5
-64
@@ -18,11 +18,11 @@ The examples below use `http://localhost:8080` as a placeholder.
|
||||
|
||||
There is no user account system. Access control works through three mechanisms:
|
||||
|
||||
- Viewer cookie. Every request gets an anonymous, random viewer id in an HttpOnly `vwr` cookie. This cookie identifies the browser that created a paste or can, and authorizes browser-scoped actions such as `GET /api/mine` and creator-only deletion.
|
||||
- Viewer cookie. Every request gets an anonymous, random viewer id in an HttpOnly `vwr` cookie. This cookie identifies the browser that created a paste, and authorizes browser-scoped actions such as `GET /api/mine` and creator-only deletion.
|
||||
- Deletion token. Creating a paste returns a one-time `deletion_token`. Sending it in the `Authorization` header (Bearer or Token prefix, or the bare value) authorizes deletion of that paste. The token is deliberately not accepted as a URL query parameter, because query strings leak into access logs and browser history.
|
||||
- Admin key. The admin settings endpoints require an install-time key sent in the `X-Admin-Key` header. The key comes from `PALETTE_ADMIN_KEY` or is generated and persisted server-side at first start.
|
||||
|
||||
Password-protected pastes and cans are unlocked with the `X-Paste-Password` request header (or the browser unlock flow on the web pages). Password checks are rate limited per IP and per paste.
|
||||
Password-protected pastes are unlocked with the `X-Paste-Password` request header (or the browser unlock flow on the web pages). Password checks are rate limited per IP and per paste.
|
||||
|
||||
### Rate limiting
|
||||
|
||||
@@ -41,7 +41,6 @@ Exceeding a limit returns `429` with a `Retry-After` header and the error code `
|
||||
|
||||
- Paste content: `PALETTE_MAX_TEXT` (default 5 MB), admin tunable. Larger content is rejected with `413`.
|
||||
- Attached files: 25 MB per file, one file per paste.
|
||||
- Can items: `PALETTE_MAX_ITEM` (default 25 MB) per item.
|
||||
- The request body itself is capped server side; oversized bodies fail with `413` before handlers run.
|
||||
|
||||
### Error format
|
||||
@@ -130,13 +129,13 @@ Errors: `400` token required, `403` invalid token, `404` not found.
|
||||
|
||||
#### GET /api/mine
|
||||
|
||||
List pastes (and cans) created from this browser, via the `vwr` cookie. Query parameters: `limit` (default 50, max 100), `offset`.
|
||||
List pastes created from this browser, via the `vwr` cookie. Query parameters: `limit` (default 50, max 100), `offset`.
|
||||
|
||||
Response `200`: `{"total": n, "limit": l, "offset": o, "items": [...]}` with each item carrying `id`, `title`, `language`, `created_at`, `view_count`, `size`, `custom_slug`, `visibility`, `is_can`.
|
||||
Response `200`: `{"total": n, "limit": l, "offset": o, "items": [...]}` with each item carrying `id`, `title`, `language`, `created_at`, `view_count`, `size`, `custom_slug`, `visibility`.
|
||||
|
||||
#### GET /api/public
|
||||
|
||||
List public pastes. Query parameters: `limit` (default 25, max 100), `offset`. Same shape as `/api/mine`; items include `is_can` and `custom_slug`.
|
||||
List public pastes. Query parameters: `limit` (default 25, max 100), `offset`. Same shape as `/api/mine`; items include `custom_slug`.
|
||||
|
||||
### Files and raw content
|
||||
|
||||
@@ -162,53 +161,6 @@ Response `200`: `{"language": "go"}`. The result is a best-effort guess and may
|
||||
|
||||
Errors: `400` invalid JSON body, `429` rate limited.
|
||||
|
||||
### Cans
|
||||
|
||||
A can bundles multiple text items and files into one shareable page at `/can/{id}`. Cans appear in `/api/mine` and `/api/public` with `is_can: true`.
|
||||
|
||||
#### POST /api/pastes/can
|
||||
|
||||
Create a can. Multipart form only. Fields:
|
||||
|
||||
| Field | Type | Notes |
|
||||
|---|---|---|
|
||||
| `title` | string | optional |
|
||||
| `description` | string | optional |
|
||||
| `visibility` | string | `public` or `unlisted`; default `public` |
|
||||
| `expires_in` | string | Go duration, 1 minute to 1 year |
|
||||
| `password` | string | optional |
|
||||
| `custom_slug` | string | optional; becomes the can id |
|
||||
| `json_items` | string | JSON array of `{"title": "...", "content": "...", "language": "..."}` text items |
|
||||
| files | parts | one or more uploaded file parts |
|
||||
|
||||
A can needs at least one item (file or `json_items`); otherwise the can is deleted and `400` (`content_empty`) is returned.
|
||||
|
||||
Response `201`: `{"id": "...", "url": "/can/{id}", "items": n}`.
|
||||
|
||||
Errors: `400` (`invalid_visibility`, `expiry_invalid`, `invalid json_items`, `content_empty`), `409` slug errors (codes `slug_taken`, `slug_invalid`, `slug_reserved`), `413` item over the size cap.
|
||||
|
||||
#### GET /api/cans/{id}
|
||||
|
||||
Can metadata with an item list. Password-protected cans require `X-Paste-Password`.
|
||||
|
||||
Response `200`: `id`, `title`, `visibility`, `created_at`, and `items`, where each item has `id`, `title`, `content_type`, `size`, and `url` (the item's fetch URL).
|
||||
|
||||
Errors: `404` not found or expired, `401` password required.
|
||||
|
||||
#### GET /api/cans/{id}/items/{item}
|
||||
|
||||
Fetch one can item's content. Items inherit the can's password: send `X-Paste-Password`, or the browser's `pw_{can}` unlock cookie. Served with the same safe content-type guard as `/raw`.
|
||||
|
||||
Errors: `404` item not found or not a can item, `401` password required.
|
||||
|
||||
#### DELETE /api/cans/{id}
|
||||
|
||||
Soft delete a can. Creator browser only: the `vwr` cookie must match the can's viewer. Cans carry no deletion token.
|
||||
|
||||
Response `200`: `{"status": "soft-deleted"}`.
|
||||
|
||||
Errors: `403` deletion not authorized, `404` not found.
|
||||
|
||||
### Admin
|
||||
|
||||
#### GET /admin/api/settings and POST /admin/api/settings
|
||||
@@ -296,17 +248,6 @@ Hard delete immediately (row removed):
|
||||
curl -X DELETE -H "Authorization: Bearer TOKEN" http://localhost:8080/api/pastes/ab12cd34/redeem
|
||||
```
|
||||
|
||||
Create a can:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/api/pastes/can \
|
||||
-F "title=My bundle" \
|
||||
-F "expires_in=48h" \
|
||||
-F "custom_slug=my-bundle" \
|
||||
-F 'json_items=[{"title":"notes.txt","content":"some notes"}]' \
|
||||
-F "files=@screenshot.png"
|
||||
```
|
||||
|
||||
## Deletion and expiry behavior
|
||||
|
||||
- Expired pastes are soft-deleted by a background sweeper that runs every minute.
|
||||
|
||||
Reference in new issue
Block a user