Filespot

File storage on Cloudflare R2 with ECDSA auth, image optimization, and content-hash URLs.

CLI v1.0.1 Deploy cb35f6e 2026-04-22T11:55:41Z JSON

Install

One-line install (Node.js ≥ 18 required):

curl -sL https://filespot.42b.eu/install/setup.sh | bash

View setup.sh

Check your version:

filespot --version
# Compare against deployed version:
curl -s https://filespot.42b.eu/api/version

Quick start

# Initialize — generates ECDSA P-256 keypair, first user becomes admin
filespot init https://filespot.42b.eu

# Upload a local file (auto-optimizes images & SVGs)
filespot upload hero.png --category renders

# Upload directly from URL (worker fetches source)
filespot upload https://example.com/hero.png --category renders

# List your files
filespot ls

URL structure

Uploaded files are served at:

https://filespot.42b.eu/builder/{category}/{filename}?ch={hash}&uk={userkey}
ParamMeaning
categoryNamespace: materials, renders, templates, etc.
chFirst 5 chars of SHA-256 of the original file (version ID / cache key)
ukUser key — first 8 chars of SHA-256 of user’s ECDSA public key

Same filename + different ch = different version. Cache-Control: immutable on all served files.

CLI commands

CommandDescription
filespot init <url>Configure server, generate keypair, register
filespot upload <file|url> --category <cat>Upload local files or remote URL sources
filespot lsList your uploaded files
filespot info <key>File metadata
filespot rm <key>Delete a file
filespot download <url>Download a file
filespot whoamiShow identity & auth status
filespot --versionShow local CLI version
filespot requestsList pending access requests (admin)
filespot requests approve <fp>Approve user by fingerprint (admin)

All commands output JSON when piped (non-TTY), making them usable by Claude, Cursor, and other AI agents.

API endpoints

MethodPathAuthDescription
POST/api/registerRegister ECDSA public key (first user = admin)
POST/api/embed/sessionECDSAMint shareId + memberToken for iframe embedding
POST/api/embed/upload/{shareId}?category=&filename=BearerUpload via iframe using member token
GET/embed/drop/{shareId}?lang=en#token=...Embeddable drag-and-drop uploader
POST/api/upload?category=&filename=&ch=&uk=ECDSAUpload file bytes
GET/builder/{cat}/{file}?ch=&uk=Serve file (public, immutable cache)
GET/api/filesECDSAList files
GET/api/info?key=ECDSAFile metadata
DELETE/api/files?key=ECDSADelete file (own files only)
GET/api/whoamiECDSAUser identity
GET/api/versionDeploy version info (JSON)
GET/api/requestsAdminPending access requests
POST/api/requests/approveAdminApprove user
POST/api/requests/denyAdminDeny user

Authentication

Every authenticated request requires three headers:

X-Filespot-Key: {fingerprint}        # 8-char hex, from SHA-256 of raw public key
X-Filespot-Timestamp: {unix_seconds}  # must be within 60s of server time
X-Filespot-Signature: {base64url}     # ECDSA-P256-SHA256 sign of: METHOD\nPATH+QUERY\nTIMESTAMP

curl examples

# Register (first user gets admin)
curl -s -X POST https://filespot.42b.eu/api/register \
  -H "Content-Type: application/json" \
  -d '{"publicKey":"BASE64URL_RAW_PUBKEY","displayName":"alice"}'

# Upload a file (with auth headers)
curl -s -X POST "https://filespot.42b.eu/api/upload?category=materials&filename=logo.svg&ch=a1b2c&uk=fa73dcf4" \
  -H "X-Filespot-Key: fa73dcf4" \
  -H "X-Filespot-Timestamp: 1711670400" \
  -H "X-Filespot-Signature: BASE64URL_SIG" \
  -H "Content-Type: image/svg+xml" \
  --data-binary @logo.svg

# Mint embed session (ECDSA auth) and upload with member token
EMBED_JSON=$(curl -s -X POST "https://filespot.42b.eu/api/embed/session" \
  -H "X-Filespot-Key: fa73dcf4" \
  -H "X-Filespot-Timestamp: 1711670400" \
  -H "X-Filespot-Signature: BASE64URL_SIG" \
  -H "Content-Type: application/json" \
  -d '{"ttlSeconds":86400}')

SHARE_ID=$(printf '%s' "$EMBED_JSON" | jq -r '.shareId')
MEMBER_TOKEN=$(printf '%s' "$EMBED_JSON" | jq -r '.memberToken')

curl -s -X POST "https://filespot.42b.eu/api/embed/upload/${SHARE_ID}?category=drop&filename=drop.txt" \
  -H "Authorization: Bearer ${MEMBER_TOKEN}" \
  -H "Content-Type: text/plain" \
  --data-binary "hello from embed flow"

# Fetch uploaded file (public, no auth needed)
curl -s "https://filespot.42b.eu/builder/materials/logo.svg?ch=a1b2c&uk=fa73dcf4"

Embed the upload drop target

Paste this iframe into any page (replace SHARE_ID and MEMBER_TOKEN):

<iframe
  src="https://filespot.42b.eu/embed/drop/SHARE_ID?lang=en#token=MEMBER_TOKEN"
  style="margin: 5%; border: none; border-radius: 16px;"
  loading="lazy"
></iframe>

You can customize language, colors, and layout via query parameters (e.g. ?lang=sv&bg=%23f9fafb&border=%23bfdbfe&text=%23111827&accent=%233b82f6) and by adding inline style on the iframe in your own page.

Image optimization

The CLI auto-optimizes uploads:

Threshold: ≥2% or ≥2KB savings. Skip with --no-optimize.

Powered by Cloudflare Workers + R2 + D1