Social Annotations in the Atmosphere
15
fork

Configure Feed

Select the types of activity you want to include in your feed.

README.md

Seams Web Proxy#

A client-side web proxy using wabac.js for annotating any webpage without installing an extension.

Architecture#

This approach uses:

  1. CORS Proxy (cors-proxy/) - Node.js server that adds CORS headers with SSRF protection
  2. wabac.js Service Worker - Intercepts requests in the browser and routes through CORS proxy
  3. Script Injection - seams-client.js is injected into proxied pages

The user's browser does all the heavy lifting - the server just adds CORS headers.

Setup#

# Install dependencies
npm install

# Also install cors-proxy dependencies
cd cors-proxy && npm install && cd ..

Development#

# Start both servers (cors-proxy on 8082 via Caddy, static on 8081)
npm run dev

Then visit: http://localhost:8081/#https://example.com

How It Works#

  1. User visits http://localhost:8081/#https://example.com
  2. loadwabac.js registers the wabac.js service worker
  3. Service worker intercepts requests to /w/liveproxy/mp_/https://example.com
  4. Requests are routed through http://localhost:8082/proxy/https://example.com
  5. CORS proxy fetches the page and adds necessary headers
  6. seams-client.js is injected into the page for annotation functionality

Directory Structure#

proxy/
├── cors-proxy/
│   ├── index.ts          # Hono-based CORS proxy server
│   ├── package.json
│   └── tsconfig.json
│
├── src/
│   ├── index.html        # Main page with iframe
│   ├── loadwabac.js      # Initialize wabac.js service worker
│   └── client-metadata.json  # OAuth metadata (for production use)
│
├── html/
│   ├── seams-shell.html  # Shell with sidebar (built by vite)
│   └── oauth-callback.html  # OAuth callback handler
│
├── Caddyfile
├── package.json
└── README.md

Ports#

  • 8081 - Static site (main page with iframe) via Caddy
  • 8082 - CORS proxy (Caddy reverse proxies to Node on 8083)
  • 8083 - CORS proxy Node.js server (internal)

Environment Variables#

The CORS proxy supports these environment variables:

Variable Default Description
CORS_ALLOWED_ORIGINS http://127.0.0.1:8081 Comma-separated allowed origins
CORS_PROXY_PORT 8083 Port for Node.js server
CORS_PROXY_MAX_BODY_SIZE 10485760 (10MB) Max request body size
CORS_PROXY_TIMEOUT_MS 30000 Request timeout in ms
CORS_PROXY_RATE_WINDOW_MS 60000 Rate limit window in ms
CORS_PROXY_RATE_LIMIT 100 Max requests per window
CORS_PROXY_RATE_MAX_CLIENTS 10000 Max tracked clients (memory bound)

CORS Proxy Details#

The CORS proxy handles:

  • Redirects: Returns 200 with x-redirect-status, x-orig-location headers
  • Cookies: Proxies via x-proxy-cookie and x-proxy-set-cookie headers
  • Referer: Accepts x-proxy-referer header
  • User-Agent: Accepts x-proxy-user-agent header

Security Features#

  • SSRF Protection: Blocks private IPs, cloud metadata endpoints
  • DNS Rebinding Mitigation: Validates resolved IPs before fetch (see note below)
  • Rate Limiting: Configurable per-origin request limits with bounded memory
  • Origin Validation: Requires Origin header (no Referer fallback)
  • Audit Logging: Logs all proxy requests with request IDs

DNS Rebinding Limitation#

The DNS validation provides defense-in-depth but cannot fully prevent DNS rebinding attacks due to TOCTOU (time-of-check-time-of-use) - fetch() does its own DNS resolution after our validation. For full protection in production, deploy behind a network-level firewall that blocks outbound connections to private IP ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 169.254.0.0/16).

Next Steps#

  1. Deploy CORS proxy to Cloudflare Workers or similar edge runtime
  2. Deploy static site to CDN