# Whois Hostname Cloaking

## Problem

When users connect to their soju bouncer, `/whois` shows the raw ingress IP
(e.g., `~josie@193.176.244.127`) instead of a meaningful hostname. Free tier
users should see `<bouncer-name>.irc.now`; pro tier users should eventually
see their custom domain.

## Scope

Soju bouncer itself only. Upstream network hostnames (Libera Chat, OFTC, etc.)
are controlled by reverse DNS and network cloaks -- separate concerns documented
under Next Steps.

## Approach: Fork Soju with Hostname Cloak Patch

### Soju Patch

Add a `hostname-cloak` config directive to soju. When set, all downstream
connections use this value as their displayed host instead of extracting from
`remoteAddr`.

Patch point: `newDownstreamConn()` in `downstream.go`. After the existing
hostname extraction from `net.SplitHostPort(remoteAddr)`, check if
`hostname-cloak` is configured. If so, override `dc.hostname` with the
configured value.

Config parser: add `hostname-cloak` case alongside existing `hostname` parsing.

Fallback: when `hostname-cloak` is absent, current behavior (IP from socket)
is preserved.

### Custom Soju Container Image

- Containerfile at `crates/soju-operator/soju/Containerfile`
- Multi-stage build: Go builder clones soju from `git.sr.ht/~emersion/soju`,
  applies patch via `.patch` file + `git apply`, builds binary
- Runtime stage: `ubi9-minimal`
- OCP BuildConfig for the custom image, built with `--from-dir`

### Operator Changes

**CRD (types.rs):** Add `hostname_cloak: Option<String>` to the spec. Separate
from `hostname` for future flexibility (pro custom domains).

**ConfigMap (configmap.rs):** When `hostname_cloak` is set, emit
`hostname-cloak <value>` in the generated soju.conf.

**Deployment (deployment.rs):** Change the soju image from
`codeberg.org/emersion/soju:latest` to the custom image in the internal
registry.

**web-api (routes/bouncer.rs):** When creating a bouncer CR, set
`hostname_cloak` to `{name}.irc.now`.

## Next Steps (Not In Scope)

### Upstream Network Hostnames

The whois hostname on upstream networks (Libera Chat, OFTC, etc.) is controlled
by the upstream network's reverse DNS resolution of the cluster's egress IP, or
by network-specific cloaks. Options:

- Set up rDNS on the cluster egress IP (193.176.244.127) to resolve to
  `irc.now` or a subdomain
- Register for project cloaks on networks that support them (e.g., Libera Chat)
- Both are DNS/network admin tasks, not code changes

### Pro Tier Custom Domains

When pro tier adds custom domain support in the portal:

- Add a "custom hostname" field in the portal (my.irc.now)
- Validate ownership via CNAME check before accepting
- Update the bouncer CR's `hostname_cloak` to the user's chosen domain

### Upstream Contribution

Submit the `hostname-cloak` directive to soju upstream
(todo.sr.ht/~emersion/soju) to reduce fork maintenance burden.
