a8f3aa6f7e
test: add comprehensive test suite (44 → 169 tests) and v1.1 plan
...
Add 125 new test functions across 10 new test files, covering:
- CSRF middleware (8 tests): double-submit cookie validation
- Auth middleware (12 tests): SessionLoader, RequireAdmin, context helpers
- API handlers (28 tests): auth, faves CRUD, tags, users, export/import
- Web handlers (41 tests): signup, login, password reset, fave CRUD,
admin panel, feeds, import/export, profiles, settings
- Config (8 tests): env parsing, defaults, trusted proxies, normalization
- Database (6 tests): migrations, PRAGMAs, idempotency, seeding
- Image processing (10 tests): JPEG/PNG, resize, EXIF strip, path traversal
- Render (6 tests): page/error/partial rendering, template functions
- Settings store (3 tests): CRUD operations
- Regression tests for display name fallback and CSP-safe autocomplete
Also adds CSRF middleware to testServer chain for end-to-end CSRF
verification, TESTPLAN.md documenting coverage, and PLANS-v1.1.md
with implementation plans for notes+OG, PWA, editing UX, and admin.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 00:18:01 +02:00
3a3b526a95
test: add comprehensive test suite (44 tests across 3 packages)
...
Store tests (21 tests):
- Session: create, validate, delete, delete-all, expiry
- Signup requests: create, duplicate, list pending, approve
(creates user with must-reset), reject, double-approve/reject
- Existing: user CRUD, auth, fave CRUD, tags, pagination
Middleware tests (9 tests):
- Real IP extraction from trusted/untrusted proxies
- Base path stripping (with prefix, empty prefix)
- Rate limiter (per-IP, exhaustion, different IPs)
- Panic recovery (returns 500)
- Security headers (CSP, X-Frame-Options, etc.)
- RequireLogin redirect
- MustResetPasswordGuard (static path passthrough)
Handler integration tests (14 tests):
- Health endpoint
- Login page rendering, successful login, wrong password
- Fave list requires auth, works when authenticated
- Private fave hidden from other users, visible to owner
- Admin panel requires admin role, works for admin
- Tag search endpoint
- Global Atom feed
- Public profile with display name
- Limited profile hides bio
Also fixes template bugs: profile.html and fave_detail.html used
$.IsOwner which fails inside {{with}} blocks ($ = root PageData,
not .Data map). Fixed with $d variable capture pattern.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 16:47:32 +02:00
aa5ab6b415
fix: address code review findings for Phase 7-8
...
Bugs fixed:
- Renderer.Error set WriteHeader before Content-Type, causing
the header to be silently dropped. Now sets Content-Type first.
- truncate template function operated on bytes, not runes — could
split multi-byte UTF-8 characters (Norwegian æøå). Now uses
[]rune for correct Unicode handling.
Performance:
- Skip session DB lookup (2 queries) on /static/ and /uploads/
requests — these never use user context.
UX consistency:
- Replace all http.NotFound and http.Error("Forbidden") in
handler layer with styled error pages via Renderer.Error.
- Add notFound/forbidden helper methods on Handler.
Deployment fixes:
- Remove false libc6/glibc deps from nfpm.yaml (binary is
statically linked with CGO_ENABLED=0).
- Add CGO_ENABLED=0 to Makefile build target for consistency.
- Add .dockerignore to exclude .git, dist/, data/ from build
context.
- Remove phantom 'lint' from Makefile .PHONY.
- Document ProtectSystem=strict constraint in systemd service.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 16:39:10 +02:00
1fc42bf1b2
feat: add packaging, deployment, error pages, and project docs
...
Phase 7 — Polish:
- Error page template with styled 404/403/500 pages
- Error rendering helper on Renderer
Phase 8 — Packaging & Deployment:
- Containerfile: multi-stage build, non-root user, health check,
OCI labels with build date and git revision
- Makefile: build, test, cross-compile, deb, rpm, container,
tarballs, checksums targets
- nfpm.yaml: .deb and .rpm package config
- systemd service: hardened with NoNewPrivileges, ProtectSystem,
ProtectHome, PrivateTmp, RestrictSUIDSGID
- Default environment file with commented examples
- postinstall/preremove scripts (shellcheck validated)
- compose.yaml: example Podman/Docker Compose
- Caddyfile.example: subdomain, subpath, and remote proxy configs
- CHANGELOG.md for release notes
- CLAUDE.md with architecture, conventions, and quick reference
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 16:34:32 +02:00
2cbbb20278
feat: add profiles, public views, settings, and code quality fixes
...
Phase 3 — Profiles & Public Views:
- Public profile page (/u/{username}) with OG meta tags
- User settings page (display name, bio, visibility, default privacy)
- Avatar upload with image processing
- Password change from settings (verifies current password)
- Home page shows public fave feed for logged-in users
- Must-reset-password guard redirects to /reset-password
- Profile visibility: public (full) or limited (username only)
Code quality improvements from /simplify review:
- Fix signup request persistence bug (was silently discarding data)
- Fix health check to use configured listen address, not hardcoded :8080
- Add rate limiter cleanup goroutine (was leaking memory)
- Extract shared helpers: ClearSessionCookie, IsSecureRequest, scanTags,
scanUserFrom (scanner interface), SignupRequestStore
- Replace hand-rolled joinPlaceholders with strings.Join
- Remove dead _method hidden field, redundant devMode field
- Simplify rate-limited route registration (remove double-mux)
- Log previously-swallowed errors (session delete, image delete)
- Stop leaking internal error messages to users in image upload
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 16:01:41 +02:00
fc1f7259c5
feat: implement Phase 1 (auth) and Phase 2 (faves CRUD) foundation
...
Go backend with server-rendered HTML/HTMX frontend, SQLite database,
and filesystem image storage. Self-hostable single-binary architecture.
Phase 1 — Authentication & project foundation:
- Argon2id password hashing with timing-attack prevention
- Session management with cookie-based auth and periodic cleanup
- Login, signup (open/requests/closed modes), logout, forced password reset
- CSRF double-submit cookie pattern with HTMX auto-inclusion
- Proxy-aware real IP extraction (WireGuard/Tailscale support)
- Configurable base path for subdomain and subpath deployment
- Rate limiting on auth endpoints with background cleanup
- Security headers (CSP, X-Frame-Options, Referrer-Policy)
- Structured logging with slog, graceful shutdown
- Pico CSS + HTMX vendored and embedded via go:embed
Phase 2 — Faves CRUD with tags and images:
- Full CRUD for favorites with ownership checks
- Image upload with EXIF stripping, resize to 1920px, UUID filenames
- Tag system with HTMX autocomplete (prefix search, popularity-sorted)
- Privacy controls (public/private per fave, user-configurable default)
- Tag browsing, pagination, batch tag loading (avoids N+1)
- OpenGraph meta tags on public fave detail pages
Includes code quality pass: extracted shared helpers, fixed signup
request persistence bug, plugged rate limiter memory leak, removed
dead code, and logged previously-swallowed errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 15:55:22 +02:00