commit ed8876859c30b8e0f63ba5732b10ecbf254ef755
parent 484c79547fc721aab4727d6fdbc07ed4a0316734
Author: David Eisinger <[email protected]>
Date: Mon, 6 Oct 2025 23:06:14 -0400
Update README
Diffstat:
| M | README.md | | | 67 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- |
1 file changed, 60 insertions(+), 7 deletions(-)
diff --git a/README.md b/README.md
@@ -24,12 +24,43 @@ A simple web API for bookmarking websites, written in Go. It stores bookmarks in
- The database file is created automatically at `~/.marky/bookmarks.sql` and migrations are applied on startup.
- Open the web UI at: `http://localhost:8080/`
+## Authentication
+
+Marky supports session cookies (for the web UI) and API tokens (for scripts, feeds, and tools).
+
+- Session cookies: set after signup or login in the UI or via endpoints
+ - POST `/signup` { username, password }
+ - POST `/login` { username, password }
+ - POST `/logout`
+ - GET `/me` returns `{ username }` when authenticated
+
+- API tokens: per-user credential used with HTTP Basic, header, or query param
+ - GET `/api/token` → `{ present: true|false }`
+ - GET `/api/token?reveal=1` → `{ present: true, api_token: "..." }` when set
+ - POST `/api/token` → `{ api_token: "..." }` (generate/regenerate)
+
+Use API tokens with requests:
+- Basic: `curl -u 'username:API_TOKEN' http://localhost:8080/bookmarks`
+- Header: `curl -H 'X-API-Token: API_TOKEN' http://localhost:8080/bookmarks`
+- Query: `curl 'http://localhost:8080/bookmarks?token=API_TOKEN'`
+
+Notes:
+- API tokens are unique (partial unique index) and can be regenerated.
+- Session cookies and tokens are both accepted; if both are present, either suffices.
+
## API
### POST /bookmarks
Create a new bookmark.
+- Auth: required (session cookie or API token)
+ - Session: set via `/login` or `/signup`
+ - API token: provide via one of
+ - Basic: `-u 'username:API_TOKEN'`
+ - Header: `X-API-Token: API_TOKEN`
+ - Query: `?token=API_TOKEN`
+
- Request headers:
- `Content-Type: application/json`
- Request body:
@@ -69,6 +100,7 @@ curl -i -X POST http://localhost:8080/bookmarks \
List bookmarks in reverse chronological order, or search with full-text. When `q` is provided, results include an `excerpt` with highlighted matches. The endpoint can return JSON (default) or RSS.
+- Auth: required to see private bookmarks (session cookie or API token). If unauthenticated, only public bookmarks are returned.
- Query params:
- `limit` (optional, default 50, max 200)
- `offset` (optional, default 0)
@@ -78,13 +110,13 @@ List bookmarks in reverse chronological order, or search with full-text. When `q
- `200 OK` with JSON array of bookmarks or RSS feed
- `400 Bad Request` for invalid `limit` or `offset`
- `500 Internal Server Error` on unexpected errors
-- curl examples:
+- curl examples (session or token required for private data):
```
-curl -s http://localhost:8080/bookmarks | jq
-curl -s 'http://localhost:8080/bookmarks?limit=20&offset=20' | jq
-curl -s 'http://localhost:8080/bookmarks?q=example' | jq
-curl -s 'http://localhost:8080/bookmarks?format=rss' | xmllint --format -
-curl -s 'http://localhost:8080/bookmarks.xml?q=example' | xmllint --format -
+curl -s -u 'username:API_TOKEN' http://localhost:8080/bookmarks | jq
+curl -s -u 'username:API_TOKEN' 'http://localhost:8080/bookmarks?limit=20&offset=20' | jq
+curl -s -u 'username:API_TOKEN' 'http://localhost:8080/bookmarks?q=example' | jq
+curl -s -u 'username:API_TOKEN' 'http://localhost:8080/bookmarks?format=rss' | xmllint --format -
+curl -s -u 'username:API_TOKEN' 'http://localhost:8080/bookmarks.xml?q=example' | xmllint --format -
```
Notes on search excerpts:
@@ -95,6 +127,7 @@ Notes on search excerpts:
Update a bookmark’s URL, title, and/or description.
+- Auth: required (session cookie or API token)
- Request headers:
- `Content-Type: application/json`
- Request body:
@@ -121,6 +154,7 @@ curl -s -X PUT http://localhost:8080/bookmarks/1 \
Delete a bookmark (and its search index entry). Archived text is removed from search index but remains in `archives` table only if you retain rows; this implementation removes the FTS entry, and the foreign key setup will cascade archives removal if configured via migrations.
+- Auth: required (session cookie or API token)
- Responses:
- `204 No Content` on success
- `404 Not Found` if the bookmark ID does not exist
@@ -130,13 +164,31 @@ Delete a bookmark (and its search index entry). Archived text is removed from se
curl -i -X DELETE http://localhost:8080/bookmarks/1
```
+### Per‑user feeds
+
+Public JSON/RSS feeds are available at `/{username}.json` and `/{username}.rss`.
+
+- Unauthenticated or non‑owner requests return only public bookmarks.
+- Owner (session, Basic auth, header, or query token) sees all bookmarks (public + private).
+
+Examples (include private when authenticated):
+- Basic: `curl -u 'dce:API_TOKEN' http://localhost:8080/dce.rss`
+- Header: `curl -H 'X-API-Token: API_TOKEN' http://localhost:8080/dce.json`
+- Query: `curl 'http://localhost:8080/dce.json?token=API_TOKEN'`
+
+### Public JSON listing
+
+- `GET /u/{username}` → JSON array of that user’s public bookmarks (always public‑only).
+
## Data Model
Table: `bookmarks`
- `id` INTEGER PRIMARY KEY AUTOINCREMENT (starts at 1)
-- `url` TEXT NOT NULL UNIQUE
+- `user_id` INTEGER NOT NULL REFERENCES `users(id)`
+- `url` TEXT NOT NULL (unique per user: `(user_id, url)`)
- `title` TEXT NOT NULL
- `description` TEXT NULL
+- `public` INTEGER NOT NULL DEFAULT 0
- `created_at` TEXT NOT NULL (RFC3339)
- `updated_at` TEXT NOT NULL (RFC3339)
@@ -148,6 +200,7 @@ An `archives` table stores the plaintext dump per bookmark and is kept in sync o
Return the archived plaintext for the given bookmark ID.
+- Auth: not required (returns plain text if the archive exists)
- Responses:
- `200 OK` with `text/plain; charset=utf-8`
- `404 Not Found` if no archive exists for the bookmark