jevb
049b58c183
fix: prevent stale "online" status for users not connected via WebSocket
...
- Remove premature UpdateUserStatus("online") from REST login handler;
the WebSocket serve.go already sets "online" on actual WS connect
- Add ResetAllUserStatuses() called at server startup to clear stale
statuses from previous runs or crashes (alongside ClearAllVoiceStates)
2026-03-15 12:21:10 +01:00
jevb
6f564c7d2f
fix: add JSON tags to Role/VoiceState, fix WebSocket error surfacing
...
Root cause: server's db.Role and db.VoiceState structs had no JSON tags,
causing Go to serialize field names as PascalCase while the C# client
expected snake_case. Every role deserialized with Id=0, crashing
ToDictionary with "duplicate key: 0".
- Add json tags to Role and VoiceState in Server/db/models.go
- Change Disconnected event to carry reason string for diagnostics
- Wire ErrorReceived in MainViewModel to show server-side WS errors
- Fix MainWindow to surface WebSocket errors on MainPage (not ConnectPage)
- Use _reconnectCts.Token for receive loop instead of caller's token
- Make ToDictionary calls safe with TryAdd to prevent future crashes
2026-03-15 12:18:19 +01:00
jevb
b4535aeea0
perf: fix O(n) allocations, freeze brushes, improve disposal and nullability
...
- Replace 5x ToList().FindIndex() with direct for-loops in MainViewModel
- UpdateUnreadCount now updates ChannelGroup in-place instead of full rebuild
- Remove redundant RebuildChannelGroups() call in OnReady
- Freeze all SolidColorBrush instances in converters for thread safety
- EmojiPicker search shows empty state instead of fallback to all categories
- MainViewModel implements IDisposable for _typingTimer cleanup
- ApiMessage.Username changed to string? to match server reality
2026-03-15 12:00:28 +01:00
jevb
7a374e0c79
fix: resolve critical TLS race, invisible messages, and 5 other review issues
...
- CRITICAL: Remove TofuHostContext AsyncLocal race — extract host from
HttpRequestMessage.RequestUri in TLS callback instead
- HIGH: OnChatMessage now calls AddMessage() so live messages appear
- HIGH: LoadMessagesForChannelAsync reports errors instead of swallowing
- HIGH: IsSystemMessage no longer false-positives on "[" prefix
- HIGH: VoiceStateInfo.ChannelId now fires PropertyChanged
- HIGH: Profile import rejects files over 1 MB
- Deleted TofuHostContext.cs (no longer needed)
2026-03-15 11:53:52 +01:00
jevb
c1c25ed26c
feat: implement full client UI from mockup — 10 phases, 331 tests
...
Client UI:
- Design system: Colors, Typography, Controls resource dictionaries
- Message actions: reply compose bar, hover edit/delete/reply buttons
- Rich content: code blocks, attachments, system messages, content parser
- Server strip: 72px sidebar with server icons, home button, add server
- Status picker: popup for changing online/idle/dnd/invisible status
- ConnectPage: server health check dots with auto-refresh
- User popup: profile card with banner, avatar, roles, member since
- Emoji picker: 6 categories, search, grid of Unicode emojis
- Settings overlay: full-screen with sidebar navigation
- Friends/DM view: sidebar + friends list with tabs (online/all/pending)
- Toast notifications: auto-dismiss after 3s with fade animation
Models & services:
- Attachment model added to Message, ApiMessage, ChatMessagePayload
- EditMessageAsync, DeleteMessageAsync, SendStatusChangeAsync APIs
- MessageContentParser (code blocks, inline code, bold, italic)
- EmojiData, ToastService, HealthStatusToBrushConverter
Server (from prior session):
- Voice room management, SFU, speaker detection
- ACME/TLS support, config improvements
- Protocol and schema updates
Tests: 331 passing (61 converter + 24 voice service + 34 voice VM +
41 parser + 9 edit/delete + existing)
2026-03-15 11:42:25 +01:00
jevb
7ee190fc3f
chore: gitignore Claude Code local config and research notes
2026-03-15 07:09:01 +01:00
jevb
6eba999233
feat: add Let's Encrypt ACME support, fix security issues, improve server UX
...
Server:
- Add Let's Encrypt (ACME) TLS mode with autocert, HTTP-01 challenges on :80,
and automatic certificate renewal (tls.mode: "acme" in config.yaml)
- Add ASCII art startup banner with server info and endpoint URLs
- Fix CSP blocking admin panel inline styles/scripts (per-route override)
- Suppress TLS handshake error noise in console output
- Fix TOCTOU race in invite consumption (atomic UPDATE with row-count check)
- Fix sendMsg mutex race condition (hold lock for entire send)
- Fix permission override formula (deny-first, allow-wins)
- Fix voice join parsing channelID before permission check
- Add session expiry check at WebSocket auth and periodic revalidation
- Add message length limit (4000 chars) and emoji length validation (32 bytes)
- Add file size enforcement in storage after io.Copy
- Add checksum URL validation in updater
- Add backup path traversal protection (BackupToSafe)
- Add self-modification guard in admin handlePatchUser
- Fix admin ownerOnlyMiddleware to use context user instead of re-auth
- Remove redundant startup log lines (banner shows same info)
- Add periodic expired session cleanup (15-min ticker)
- Add permissions package with bitfield constants and EffectivePerms
- Add rate limiter cleanup goroutine to prevent unbounded growth
- Add auth helpers (IsEffectivelyBanned, IsSessionExpired)
- Add WebSocket origin validation
Client:
- Add TOFU certificate trust service
- Add receive loop error handling
- Fix redundant else-if in OnChatMessage
2026-03-15 07:07:59 +01:00
jevb
98decace45
chore: gitignore client publish output directories
2026-03-15 00:33:07 +01:00
jevb
e33ec32afb
fix: include SavePassword/LoadPassword/DeletePassword in ICredentialService interface
2026-03-15 00:31:56 +01:00
jevb
25449eb204
feat: redesign login UI, add save-password, fix permissions, add audit logging, member_join broadcast
...
- Redesign ConnectPage with modern dark theme, profile cards with delete buttons, login/register toggle
- Add DPAPI-encrypted password saving with "Remember my password" checkbox
- Fix permission bit constants to match SCHEMA.md (Member role 0x663)
- Add migration 004 to fix existing Member role permissions
- Add comprehensive audit logging across all server packages (auth, admin, ws, setup)
- Add member_join WebSocket broadcast so new users appear in members list in real-time
- Add host URL normalization (strip scheme prefix) for reverse proxy compatibility
- Add REST API client, ChatService orchestrator, WebSocket service with reconnection
- Add model types (WsEnvelope payloads, API responses), converters, tests
2026-03-15 00:31:39 +01:00
jevb
b53098acec
chore: gitignore server runtime artifacts (binary, config, data)
2026-03-14 22:38:08 +01:00
jevb
d425dc5553
feat: add setup wizard for initial owner account creation
...
When no users exist, the admin panel shows a setup wizard instead of the
login form. Creates the first Owner account with a session token and
generates an unlimited invite code for onboarding other users. The setup
endpoint is locked out after the first user is created.
Also fixes the admin panel 404 by serving index.html directly for the
root path instead of delegating to http.FileServer.
2026-03-14 22:36:35 +01:00
jevb
80ceabc78b
fix: set default TLS cert/key paths to data/cert.pem and data/key.pem
2026-03-14 22:17:47 +01:00
jevb
da19fda9e1
chore: add .claude/settings.local.json to gitignore
2026-03-14 22:11:42 +01:00
jevb
f28a7b8342
docs: add Phase 7 distribution and updates design spec
2026-03-14 22:09:11 +01:00
jevb
69b76ada12
feat: add update notification banner to admin dashboard
2026-03-14 22:06:54 +01:00
jevb
73a621ef0f
feat: implement server auto-update API endpoints with download, verify, and restart
2026-03-14 22:05:13 +01:00
jevb
bae586907f
feat: implement client auto-update with GitHub Release checking and update dialog
2026-03-14 22:04:24 +01:00
jevb
82a9985a6a
docs: add server_restart message type and update endpoints to specs
2026-03-14 22:03:12 +01:00
jevb
27b7c000da
feat: add updater package with GitHub Release checking and checksum verification
2026-03-14 21:59:58 +01:00
jevb
7398756515
docs: add README, SECURITY, CONTRIBUTING, and setup guides
2026-03-14 21:58:53 +01:00
jevb
8ab2c93f1e
feat: add server_restart WebSocket message type for update notifications
2026-03-14 21:58:18 +01:00
jevb
aa2a1cf025
ci: add GitHub Actions CI and release workflows
...
CI runs build+test+lint for both server and client on push/PR.
Release workflow builds binaries, generates SHA256 checksums,
and creates a GitHub Release with auto-generated notes on tag push.
2026-03-14 21:58:06 +01:00
jevb
5aa216d991
fix: correct embed path (static not admin/static) and simplify audit_log migration
2026-03-14 21:37:47 +01:00
jevb
ab389764b5
feat: implement Phase 5 (voice/WebRTC signaling) and Phase 6 (admin panel)
...
Phase 5 — Voice:
- migrations/002_voice_states.sql: voice_states table with FK + index
- db/voice_queries: JoinVoiceChannel, LeaveVoiceChannel, GetVoiceState,
GetChannelVoiceStates, UpdateVoiceMute, UpdateVoiceDeafen, ClearVoiceState
- ws/voice_handlers: handleVoiceJoin (perm check, DB, broadcast existing
states), handleVoiceLeave, handleVoiceMute, handleVoiceDeafen,
handleVoiceSignal (rate-limited relay, SDP never logged),
handleSoundboard (rate-limited, USE_SOUNDBOARD perm check)
- ws/handlers: dispatch voice_join/leave/mute/deafen/offer/answer/ice/soundboard
- ws/serve: call handleVoiceLeave on disconnect; include voice states in ready payload
- ws/messages: buildVoiceState, buildVoiceLeave, buildVoiceSignalRelay
- api/voice_handler: GET /api/v1/voice/credentials — HMAC-SHA1 TURN creds
- config: VoiceConfig (TURNSecret, STUNPort, TURNPort, TURNEnabled)
Phase 6 — Admin Panel:
- migrations/003_audit_log.sql: audit_log table with indexes
- db/admin_queries: GetServerStats, ListAllUsers, UpdateUserRole,
ForceLogoutUser, AdminCreate/Update/DeleteChannel, LogAudit,
GetAuditLog, GetSetting, SetSetting, GetAllSettings, BackupTo
- admin/api: full REST API — stats, users, channels, audit log, settings,
backup; adminAuthMiddleware (ADMINISTRATOR bit), ownerOnlyMiddleware
- admin/static/index.html: single-page admin panel (dark theme, vanilla JS,
no CDN) — dashboard, users, channels, audit log, settings sections
- admin/admin.go: NewHandler wiring go:embed static files + API
Fixes: Channel struct json tags (was serializing as "ID" not "id"),
duplicate getWithToken helper renamed in voice_handler_test.go
Test coverage: admin 59.1%, api 78.2%, auth 90.9%, db 82.0%, ws 37.9%
2026-03-14 21:31:03 +01:00
jevb
36640e3051
feat: implement Phase 4 real-time chat (WebSocket hub + message REST)
...
- db: channel_queries (ListChannels, GetChannel, CRUD, permissions),
message_queries (CreateMessage, GetMessage, GetMessages paginated,
EditMessage, DeleteMessage soft, AddReaction, RemoveReaction,
GetReactions, SearchMessages FTS5, UpdateReadState)
- db: fix in-memory DB isolation — SetMaxOpenConns(1) for :memory: path
- ws/hub: replace stub with full Hub (register/unregister, broadcast to
channel/all, send to user, thread-safe, buffered broadcast channel)
- ws/client: Client with send channel, NewTestClient helpers for tests
- ws/handlers: dispatch chat_send/edit/delete, reaction_add/remove,
typing_start, presence_update — all with rate limiting and permission checks
- ws/messages: JSON builder helpers for all server→client message types
- ws/serve: ServeWS HTTP handler, WS auth handshake (10s timeout),
ready payload, writePump/readPump goroutines, graceful disconnect
- api: channel_handler — GET /channels, GET /channels/{id}/messages,
GET /search; fixed double-mount of /api/v1 route group
- api/router: mount channel routes, start hub, register /api/v1/ws
Test coverage: api 77.6%, auth 90.9%, db 84.2%, ws 26.7% (serve.go
requires live WS connection; hub/handlers/messages fully covered)
2026-03-14 21:17:09 +01:00
jevb
814653ea08
chore: add Client .gitignore, remove tracked build artifacts
2026-03-14 21:07:25 +01:00
jevb
9707c4d4af
feat: scaffold Phase 3 WPF client shell with MVVM and TDD structure
...
- WPF (.NET 8) project targeting net8.0-windows
- Models: ServerProfile (record), Channel, Message, User, Role
- ViewModels: ViewModelBase (INotifyPropertyChanged), RelayCommand<T>,
ConnectViewModel (profiles, login/register toggle, connect command),
MainViewModel (channels, messages, typing indicator, send command),
SettingsViewModel (dark theme, notifications, PTT key)
- Services: IProfileService + ProfileService (AppData JSON, immutable ops),
ICredentialService + CredentialService (DPAPI via ProtectedData),
IWebSocketService + WebSocketService (ClientWebSocket stub)
- Views: ConnectPage (server address, login/register, profile selector),
MainPage (3-column: channel list, message area, member list),
App.xaml wires converters and startup
- Converters: BoolToVisibilityConverter, IntToVisibilityConverter
- Tests: ConnectViewModelTests (11 cases), MainViewModelTests (11 cases),
ProfileServiceTests (6 cases) — ready to run once NuGet accessible
(run: dotnet restore && dotnet test OwnCord.Client.Tests/)
Build: dotnet build OwnCord.Client/ succeeds with 0 warnings
2026-03-14 21:07:07 +01:00
jevb
b7dd6eabe9
feat: implement Phase 2 auth & security with TDD
...
- auth/session: 256-bit crypto-random tokens, SHA-256 hashing for storage
- auth/password: bcrypt cost 12, strength validation (8-72 chars)
- auth/ratelimit: sliding-window RateLimiter with lockout, thread-safe
- db/models: User, Session, Invite, Role types
- db/auth_queries: full user/session/invite CRUD with in-memory test coverage
- api/middleware: AuthMiddleware (Bearer token), RequirePermission (bitfield),
RateLimitMiddleware (X-Real-IP, Retry-After header)
- api/auth_handler: POST register/login, POST logout, GET me
- Generic errors — username existence never revealed
- Rate limits: 3/min register, 5/min login, lockout after 10 failures
- api/invite_handler: create/list/revoke behind MANAGE_INVITES permission
- bluemonday sanitization on all user-supplied string fields
Test coverage: auth 90.9%, db 84.4%, api 80.9%
2026-03-14 20:52:11 +01:00
jevb
a1434ad07f
feat: implement Phase 1 server skeleton with TDD
...
- Scaffold Go module (github.com/owncord/server) with all package dirs
- config: koanf-based YAML loader with env var overrides, default generation
- db: pure-Go SQLite (modernc, no CGO), WAL mode, FK enforcement, full
15-table schema from SCHEMA.md including FTS5 and idempotent migrations
- auth/tls: ECDSA P-256 self-signed cert generation, LoadOrGenerate for
all 4 TLS modes (self_signed, acme, manual, off)
- api: chi router with request ID middleware, /health and /api/v1/info
- main: graceful shutdown (30s timeout), structured slog JSON logging
- Stubs for ws, storage, admin packages ready for Phase 2+
Test coverage: api 100%, auth 85.7%, db 82.4%, config 80.6%
Binary: chatserver.exe 12MB, GOOS=windows GOARCH=amd64
2026-03-14 20:34:37 +01:00
jevb
bcf563f36c
chore: initial commit with project specs and configuration
...
Add all specification files (CHATSERVER, PROTOCOL, SCHEMA, API, SETUP),
Claude Code config, and skill definitions for the OwnCord chat platform.
2026-03-14 19:57:39 +01:00