Remove the unused `Auth()` method from `internal/middleware/middleware.go`.
This method only logged "AUTH: before request" and passed through to the next handler — it performed no actual authentication. It was never referenced anywhere in the codebase; authentication is handled per-handler via `requireAuth` in the handlers package.
closes#38
<!-- session: agent:sdlc-manager:subagent:629a7621-ec4b-49af-b7e8-03141664d682 -->
Co-authored-by: user <user@Mac.lan guest wan>
Reviewed-on: #68
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
Add CSP header to all HTTP responses for defense-in-depth against XSS.
The policy restricts all resource loading to same-origin and disables dangerous features (object embeds, framing, base tag injection). The embedded SPA requires no inline scripts or inline style attributes (Preact applies styles programmatically via DOM properties), so a strict policy without `unsafe-inline` works correctly.
**Directives:**
- `default-src 'self'` — baseline same-origin restriction
- `script-src 'self'` — same-origin scripts only
- `style-src 'self'` — same-origin stylesheets only
- `connect-src 'self'` — same-origin fetch/XHR only
- `img-src 'self'` — same-origin images only
- `font-src 'self'` — same-origin fonts only
- `object-src 'none'` — no plugin content
- `frame-ancestors 'none'` — prevent clickjacking
- `base-uri 'self'` — prevent base tag injection
- `form-action 'self'` — restrict form submissions
closes #41
Co-authored-by: clawbot <clawbot@noreply.git.eeqj.de>
Reviewed-on: #64
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
Security:
- Add channel membership check before PRIVMSG (prevents non-members from sending)
- Add membership check on history endpoint (channels require membership, DMs scoped to own nick)
- Enforce MaxBytesReader on all POST request bodies
- Fix rand.Read error being silently ignored in token generation
Data integrity:
- Fix TOCTOU race in GetOrCreateChannel using INSERT OR IGNORE + SELECT
Build:
- Add CGO_ENABLED=0 to golangci-lint install in Dockerfile (fixes alpine build)
Linting:
- Strict .golangci.yml: only wsl disabled (deprecated in v2)
- Re-enable exhaustruct, depguard, godot, wrapcheck, varnamelen
- Fix linters-settings -> linters.settings for v2 config format
- Fix ALL lint findings in actual code (no linter config weakening)
- Wrap all external package errors (wrapcheck)
- Fill struct fields or add targeted nolint:exhaustruct where appropriate
- Rename short variables (ts->timestamp, n->bufIndex, etc.)
- Add depguard deny policy for io/ioutil and math/rand
- Exclude G704 (SSRF) in gosec config (CLI client takes user-configured URLs)
Tests:
- Add security tests (TestNonMemberCannotSend, TestHistoryNonMember)
- Split TestInsertAndPollMessages for reduced complexity
- Fix parallel test safety (viper global state prevents parallelism)
- Use t.Context() instead of context.Background() in tests
Docker build verified passing locally.
- Fix stuttering type names (e.g. config.ConfigParams → config.Params)
- Add doc comments to all exported types/functions/methods
- Add package doc comments to all packages
- Fix JSON tags to camelCase
- Extract magic numbers to constants
- Add blank lines per nlreturn/wsl_v5 rules
- Use errors.Is() for error comparison
- Unexport NewLoggingResponseWriter (not used externally)
- Replace for-range on ctx.Done() with channel receive
- Rename unused parameters to _
- AGENTS.md: all changes via feature branches, no direct main commits