Commit Graph
17 Commits
Author SHA1 Message Date
jevb 4bdc83a368 fix: resolve 15 post-review issues across server and client
Server fixes:
- Move ATTACH_FILES permission check before CreateMessage to prevent
  orphaned messages on permission denial
- Fix hardcoded /api/files/ URL to /api/v1/files/ per spec
- Add error logging for GetAttachmentsByMessageIDs failure
- Set 1MB WebSocket read limit to match client-side limit
- Extract requireChannelPerm helper, replacing 8 repeated patterns

Client fixes:
- Wire onUnauthorized callback to clear auth on 401 responses
- Store auth token in authStore before WS connect
- Reset WS state to disconnected when Tauri APIs unavailable
- Add connectivity guard and 200ms send debounce on message send
- Add toast container to MainPage with error feedback on 5 API failures
- Clear voice currentChannelId on server-driven voice_leave for current user
- Apply stored theme/font/compact preferences at app startup
- Fix infinite scroll throttle to use store subscription instead of fixed timer

Tests:
- Add TestChatSend_AttachmentsDeniedNoMessageCreated
- Add attachments table to handler test schema
2026-03-17 01:59:34 +01:00
jevb 01387dc033 feat: fix all E2E failures, add credentials/window-state, wire QuickSwitcher + SettingsOverlay
- Fix 80 E2E test failures across 6 root causes (channel auto-select,
  settings overlay wiring, QuickSwitcher Ctrl+K, voice widget visibility,
  member list rendering, status dot positioning)
- Add Tauri credential storage (Rust + TS bridge) and window-state persistence
- Add ConnectedOverlay component and settings-overlay/window-state unit tests
- Expand profiles and rate-limiter with comprehensive test coverage
- Add CODE_REVIEW.md documenting 4 Critical + 3 High server-side issues
- Add Playwright E2E suite (135 tests across 14 spec files)
- All 586 tests passing (451 unit/integration + 135 E2E)
2026-03-16 16:43:46 +01:00
jevb 3d022b68e4 test: add test helpers and integration tests for dispatcher + stores
- Create mock-ws helper with simulateMessage/simulateStateChange
- Create fixture factories for messages, members, channels, reactions
- Create resetAllStores utility for clean test isolation
- Add 16 integration tests covering:
  - Ready payload hydration (channels, members, voice)
  - Chat message flow with unread tracking
  - Message edit and delete
  - Reaction add/remove via reaction_update
  - Chat send confirmation via chat_send_ok
  - Typing indicator updates
  - Member ban handling
  - Voice config and speakers state

385 tests passing across 22 test files.
2026-03-15 20:46:38 +01:00
jevb e07a1abede feat: align UI to mockup, wire WS handlers, fix 5 HIGH review issues
- Fix CSS classes across 8 components to match ui-mockup.html
  (ReactionBar, VoiceChannel, EmojiPicker, DmSidebar, Toast,
  ServerBanner, MessageActionsBar, MessageList)
- Rewrite MainPage to compose standalone components instead of
  inline builders, with reactive channel switching
- Wire all outbound WS handlers: chat send/edit/delete, typing,
  reactions, voice mute/deafen/disconnect
- Wire REST message loading with infinite scroll and abort on
  channel switch
- Wire reconnect banner to WS state and server_restart events
- Add reaction_update, chat_send_ok, member_ban, voice_config,
  voice_speakers dispatcher handlers
- Add updateReaction action in messages store
- Fix MessageList double-render bug when no code blocks present
- Fix membersStore subscription to skip re-render on typing events
- Add scroll-top debounce to prevent duplicate API calls
- Replace dead More button with functional Delete button
- Clear unread count on channel switch in channels store
- Add midnight theme, connectionStatus, error fields to UI store
- Add voiceConfigs state and setSpeakers action to voice store
- Update tests: 369 passing across 21 test files
2026-03-15 20:43:13 +01:00
jevb 77626e136b feat: add Tauri v2 desktop client with full chat UI and security hardening
Complete Tauri v2 client implementation migrated from WPF/.NET 8:
- Rust backend: WS proxy with TLS cert bypass for self-signed servers,
  settings storage, system tray, global hotkeys
- TypeScript frontend: login/register, chat messaging, channel sidebar,
  member list, voice channel UI, settings overlay with log viewer,
  server profiles, quick switcher, emoji picker, file uploads
- 21 test suites (364 tests) covering stores, services, and components
- Security: bounded WS channel, wss:// URL validation, TLS signature
  verification, profile import validation, token redaction, HTTPS-only
  HTTP scope

Also updates CLAUDE.md to correct API path rule (/api/v1/) and adds
Tauri client CI workflow.
2026-03-15 19:44:02 +01:00
jevb b7d63dd443 chore: update .gitignore to exclude local tooling, build artifacts, and internal docs
Remove Claude Code configs, skills, publish artifacts, HTML mockups,
and internal planning docs from git tracking. Files remain local.
2026-03-15 16:54:55 +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 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 bae586907f feat: implement client auto-update with GitHub Release checking and update dialog 2026-03-14 22:04:24 +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