# Contributing to VoidChat

There are three ways to contribute: code, bug reports, and — most importantly — **running a community Worker relay node**.

---

## 🛰 Run a community Worker relay node

This is the easiest and most impactful way to contribute.

VoidChat users can opt in to route their WebSocket traffic through community-operated Cloudflare Workers. These Workers act as **privacy proxies** — they forward traffic to Nostr relays while hiding the user's IP. They never see plaintext (content is encrypted with ML-KEM-768 hybrid before it ever hits the Worker).

### Why contribute a node?

- **More nodes = better privacy** — traffic is distributed, harder to correlate
- **Decentralization** — no single operator (including the VoidChat authors) controls the network
- **Cheap** — Cloudflare Workers free tier gives you 100,000 requests/day. For a small community that's effectively unlimited.
- **Zero risk** — you cannot read content even if you wanted to

### Prerequisites

- A free Cloudflare account ([signup](https://dash.cloudflare.com/sign-up))
- Node.js 18+ (for `wrangler`)
- 10 minutes

### Step-by-step deploy

```bash
# 1. Clone the repo
git clone https://github.com/your-org/voidchat.git
cd voidchat

# 2. Install wrangler (one time)
npm install -g wrangler

# 3. Log in to your Cloudflare account
wrangler login

# 4. Give your worker a unique name (edit wrangler.toml)
#    Change:  name = "voidchat-relay"
#    To:      name = "voidchat-relay-YOURNAME"
#
#    This becomes your URL: voidchat-relay-YOURNAME.YOUR-SUBDOMAIN.workers.dev
nano wrangler.toml

# 5. Deploy
wrangler deploy

# You'll see:
#   ✨ Deployed voidchat-relay-YOURNAME to:
#     https://voidchat-relay-YOURNAME.YOUR-SUBDOMAIN.workers.dev
```

### Verify your deployment

```bash
# Health check — should return JSON with ok: true
curl https://voidchat-relay-YOURNAME.YOUR-SUBDOMAIN.workers.dev/health
# Expected: {"ok":true,"version":"1","ts":1234567890}
```

### Add your URL to the community list

```bash
# Edit js/transport/worker-relay.js
# Find: const COMMUNITY_NODES = [
# Add your URL to the array:

const COMMUNITY_NODES = [
    'wss://voidchat-relay-YOURNAME.YOUR-SUBDOMAIN.workers.dev',
];
```

Submit a pull request with that one change. That's it — your node is live for the community.

### Test it yourself

```bash
# Open the VoidChat site with your own worker:
https://your-voidchat-instance.pages.dev/?wproxy=wss://voidchat-relay-YOURNAME.YOUR-SUBDOMAIN.workers.dev

# Or toggle "Worker Proxy" in Settings → paste your URL → Save
```

### Optional: harden your node

Edit `wrangler.toml` before deploying:

```toml
[vars]
# Restrict to your own Pages domain (prevents abuse from other origins)
ALLOWED_ORIGIN = "https://your-voidchat.pages.dev"

# Restrict which Nostr relays can be proxied (default: whole damus/nostr.band/etc list)
ALLOWED_RELAYS = "wss://relay.damus.io,wss://nos.lol"
```

Then redeploy: `wrangler deploy`

### Operator responsibilities

By running a node, you agree to:

- **Not log or store** traffic beyond what Cloudflare provides by default
- **Keep the node up** reasonably — occasional downtime is fine, the client health-checks and rotates
- **Not modify** the worker to inject, censor, or surveil traffic
- **Respect Cloudflare's ToS** — Workers are for relaying encrypted chat, not for abuse

If you want to stop running your node, open a PR removing your URL or comment it out.

### Free tier limits

| Resource | Free tier | Realistic usage |
|----------|-----------|-----------------|
| Requests | 100,000 / day | Each WebSocket session = 1 request. 100k/day = ~1000 concurrent users |
| CPU time | 10 ms / request | WebSocket proxying is I/O bound; CPU time is minimal |
| Bandwidth | Unlimited on free tier | — |

If your node becomes popular enough to hit the limit, either upgrade to the $5/month paid tier or add more nodes.

---

## 🐛 Report bugs

- **Security bugs:** open an issue with the `security` label, or email the maintainer privately
- **Non-security bugs:** open a GitHub issue with reproduction steps
- **Feature requests:** open an issue and explain the use case

When filing a bug, include:
- Browser + version
- Whether you were in Ghost / VoidID / Named mode
- Which transport was active (WebSocket / HTTP / Yjs / WebRTC) — check the room header badge
- Console errors (F12 → Console)

**Do not include:** seed phrases, room names with passwords, or any content from rooms. These leak privacy.

---

## 💻 Code contributions

### Before you start

1. Read [SECURITY.md](./SECURITY.md) — understand the threat model
2. Open an issue first for anything larger than a typo fix
3. No new CDN crypto dependencies — everything cryptographic must be bundled locally under `js/vendor/`

### Style

- Vanilla JavaScript, no frameworks (we like zero build steps)
- TailwindCSS for styling (already loaded via CDN for the UI only)
- Comments in English, code comments explain *why* not *what*
- No `console.log` spam — use `console.log('[Module]', ...)` pattern

### Testing

There's no automated test suite (yet). Before submitting a PR:

1. Open `index.html` in two browser profiles
2. Create a room in one, join from the other
3. Verify messages flow both ways
4. Check the transport badge shows the expected layer
5. Toggle Ghost / VoidID / Named and verify the banner updates

### Pull request checklist

- [ ] No new CDN dependencies
- [ ] No new unencrypted localStorage writes
- [ ] Threat model updated in SECURITY.md if behavior changed
- [ ] README updated if user-facing behavior changed
- [ ] Manually tested across at least two browser profiles

---

## 🔐 Cryptography changes

Changes to `js/crypto.js`, `js/pq-crypto.js`, `js/nostr-crypto.js`, `js/ratchet.js`, or `js/identity.js` require **extra scrutiny**:

- Open an issue first and wait for discussion
- Never weaken a primitive (e.g. swapping ML-KEM-768 for ML-KEM-512 is a no)
- Never remove the hybrid design (classical + PQ)
- Never change Argon2id parameters without explaining the trade-off
- New primitives must come from `@noble/*` or equivalent audited libraries
- Bundles must be built locally and committed (not pulled from CDN)

---

## 📜 License

By contributing you agree your work is licensed under MIT.

---

Thanks for helping keep private communication private.
