Files
activity-pub/README.md
2026-01-08 17:38:14 +00:00

190 lines
4.8 KiB
Markdown

# Art DAG L2 Server - ActivityPub
Ownership registry and ActivityPub federation for Art DAG.
## What it does
- **Registry**: Maintains owned assets with content hashes
- **Activities**: Creates signed ownership claims (Create activities)
- **Federation**: ActivityPub endpoints for follow/share
- **L1 Integration**: Records completed L1 runs as owned assets
- **Authentication**: User registration, login, JWT tokens
## Setup
```bash
pip install -r requirements.txt
# Configure (optional - defaults shown)
export ARTDAG_DOMAIN=artdag.rose-ash.com
export ARTDAG_USER=giles
export ARTDAG_DATA=~/.artdag/l2
export DATABASE_URL=postgresql://artdag:artdag@localhost:5432/artdag
# Generate signing keys (required for federation)
python setup_keys.py
# Start server
python server.py
```
## JWT Secret Configuration
The JWT secret is used to sign authentication tokens. **Without a persistent secret, tokens are invalidated on server restart.**
### Generate a secret
```bash
# Generate a 64-character hex secret
openssl rand -hex 32
# Or with Python
python -c "import secrets; print(secrets.token_hex(32))"
```
### Local development
```bash
export JWT_SECRET="your-generated-secret-here"
python server.py
```
### Docker Swarm (recommended for production)
Create a Docker secret:
```bash
# From a generated value
openssl rand -hex 32 | docker secret create jwt_secret -
# Or from a file
echo "your-secret-here" > jwt_secret.txt
docker secret create jwt_secret jwt_secret.txt
rm jwt_secret.txt
```
Reference in docker-compose.yml:
```yaml
services:
l2-server:
secrets:
- jwt_secret
secrets:
jwt_secret:
external: true
```
The server reads secrets from `/run/secrets/jwt_secret` automatically.
## Key Setup
ActivityPub requires RSA keys for signing activities. Generate them:
```bash
# Local
python setup_keys.py
# Or with custom paths
python setup_keys.py --data-dir /data/l2 --user giles
# In Docker, exec into container or mount volume
docker exec -it <container> python setup_keys.py
```
Keys are stored in `$ARTDAG_DATA/keys/`:
- `{username}.pem` - Private key (chmod 600, NEVER share)
- `{username}.pub` - Public key (included in actor profile)
**Important**: Private keys are gitignored. Back them up securely. Losing them invalidates all your signatures.
## Client Commands
### Upload Media
Register a media asset (image, video, audio) with a content hash:
```bash
curl -X POST http://localhost:8200/assets \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"name": "my-video",
"content_hash": "abc123...",
"asset_type": "video",
"tags": ["art", "generated"]
}'
```
### Upload Recipe
Record an L1 run as an owned asset. This fetches the run details from the L1 server and registers the output:
```bash
curl -X POST http://localhost:8200/assets/record-run \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <token>" \
-d '{
"run_id": "uuid-from-l1",
"l1_server": "https://celery-artdag.rose-ash.com",
"output_name": "my-rendered-video"
}'
```
## API Endpoints
### Server Info
| Method | Path | Description |
|--------|------|-------------|
| GET | `/` | Home page with stats |
### Assets
| Method | Path | Description |
|--------|------|-------------|
| GET | `/assets` | List all assets |
| GET | `/assets/{name}` | Get asset by name |
| POST | `/assets` | Upload media - register new asset |
| POST | `/assets/record-run` | Upload recipe - record L1 run |
### ActivityPub
| Method | Path | Description |
|--------|------|-------------|
| GET | `/.well-known/webfinger?resource=acct:user@domain` | Actor discovery |
| GET | `/users/{username}` | Actor profile |
| GET | `/users/{username}/outbox` | Published activities |
| POST | `/users/{username}/inbox` | Receive activities |
| GET | `/users/{username}/followers` | Followers list |
| GET | `/objects/{content_hash}` | Get object by hash |
| GET | `/activities/{index}` | Get activity by index |
### Authentication
| Method | Path | Description |
|--------|------|-------------|
| POST | `/auth/register` | Register new user |
| POST | `/auth/login` | Login, get JWT token |
| GET | `/auth/me` | Get current user |
## Data Storage
Data stored in PostgreSQL:
- `users` - Registered users
- `assets` - Asset registry
- `activities` - Signed activities
- `followers` - Followers list
RSA keys stored in `$ARTDAG_DATA/keys/` (files, not database).
## Architecture
```
L2 Server (port 8200)
├── POST /assets (upload media) → Register asset → Create activity → Sign
├── POST /assets/record-run (upload recipe) → Fetch L1 run → Register output
│ │
│ └── GET L1_SERVER/runs/{id}
├── GET /users/{user}/outbox → Return signed activities
└── POST /users/{user}/inbox → Receive Follow requests
```