* [Server] Add match result strategy hook
Took 7 minutes
Took 18 minutes
* Rebase.
Took 2 minutes
Took 13 seconds
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
* [Network] Measure real server round-trip times
Time each command container from send to response with QElapsedTimer,
aggregate samples in a fixed-size ring buffer (last/median/p95/max),
and emit aggregated pingStatsUpdated at most once per second so the
hot path stays free of signal traffic. Stats are cleared on
disconnect. Forward the signal through ConnectionController for UI
consumers. Unit-tested in latency_tracker_test.
Took 37 minutes
Took 4 minutes
# Commit time for manual adjustment:
# Took 8 minutes
* Move params to struct, more informative debug
Took 56 seconds
Took 53 seconds
Took 2 minutes
Took 33 seconds
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
* [Server/Client/Protocol] Reporting users + moderation queue functionality
Took 6 minutes
Took 3 minutes
Took 8 seconds
Took 11 minutes
Took 12 minutes
Took 7 minutes
Took 15 seconds
Took 2 minutes
Took 1 minute
Took 30 seconds
Took 16 seconds
* CI Fix
Took 6 minutes
* CI Fix
Took 6 minutes
* [Protocol] Add moderation investigation commands
Adds the protocol layer for the moderation investigation suite:
- Command_GetUserSessions/GetUserAlts/GetModeratorLastLogins/ResetUserPassword/RemoveUserAvatar (1013-1017)
- Response extensions 1215-1219 with ServerInfo messages for sessions, alts, and staff logins
- last_login on Response_ReportUserInfo and warning_il on Response_WarnList
Took 2 minutes
* [Utility] Add warning categories parser with infraction levels
Parses the server's 'officialwarnings' setting (comma-separated, optional
'|IL' suffix) into WarningCategory structs so the client can display the
infraction level of each warning category. Includes GTest coverage.
* [Server] Add moderation investigation tools
Implements the server side of the moderation suite:
- getUserSessions/getUserAlts/getModeratorLastLogins/removeUserAvatar DB methods
- Handlers for all five new commands with audit records (PASSWORD_RESET,
REMOVE_USER_AVATAR); password resets return a generated temporary password
- cmdGetWarnList now reports per-category infraction levels from the
officialwarnings setting; cmdReportUserInfo reports last_login
- Update servatrice.ini.example with the warning taxonomy
- Password/avatar mutations report RespNameNotFound when the user does not exist
* [Client] Add moderation tab with investigate, password reset, and avatar removal
- New Moderation tab: search a user to show account info, alternate
accounts, login sessions, and staff last logins; actions to reset the
user's password (shows the generated temporary password) and remove the
user's avatar
- 'Investigate user' entry in the user context menu opens the tab pre-loaded
for that user
- Warning dialog shows the infraction level of each warning category
- Tab wired into TabSupervisor with a moderator-gated menu action, shortcut,
and tabs.ini persistence (default closed)
* [Server/Client/Protocol] Address PR #7091 review: security, bug, and perf fixes
Security:
- Promote RESET_USER_PASSWORD to admin-only dispatch (was moderator-accessible)
- Reject password reset on users with equal/higher privilege than caller
- Notify affected user via Event_NotifyUser::CUSTOM when password is reset
- Add server-side category whitelist for reports
- Drop reporter name fallback in comment/details authorization (ID-only)
- Force password change: new DB column + login enforcement + client disconnect
Bugs:
- XSS via QTextEdit::append() → insertPlainText() in report tab and utils
- allNotified initialized to true even with empty recipients list
- Warning combo box: use currentData() instead of baked-in display text
- Report resolution now records who resolved (resolved_by column + audit)
Performance:
- IP-correlation subquery: add 6-month window + LIMIT 200
- getUserSessions: clamp limit to 500
Non-blocking:
- Palette-aware colors in report_utils.cpp (dark/light mode)
- Report list pagination: offset/limit fields + total_count in response
- SessionCommand enum gap comment for reserved values 1201-1203
Schema: 36→37 (force_password_change), 37→38 (resolved_by)
Took 12 minutes
Took 16 seconds
* Fix macOs pedantry
Took 5 minutes
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
* [Game] Playmats
Took 19 seconds
Took 1 minute
* [Playmats] Add fixed override and configurable fallbacks to settings.
Took 29 minutes
Took 43 seconds
* Add main to test.
Took 1 minute
Took 29 seconds
* Move settings to own group
Took 11 minutes
* Some attempts to refresh macOS compositor
Took 2 minutes
* Try something else
Took 17 minutes
* Don't manipulate live list
Took 11 minutes
* Change things about resolution, address comments.
Took 45 minutes
Took 12 minutes
* Comments.
Took 14 minutes
Took 8 seconds
* Re-order settings menu location
Took 2 minutes
* Rename PlaymatResolution to Info and add enums
Took 8 minutes
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
cmdReplaySubmitCode dereferenced userInfo without an authentication
guard, allowing an unauthenticated connection with a valid replay code
to segfault the server. Add the same authState != PasswordRight guard
used by all other replay handlers, and gate session command dispatch on
a pre-auth whitelist so future handlers cannot be reached before login.
Took 2 minutes
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
* [CI] Remove Qt5
Took 10 minutes
Took 9 minutes
* Revert CI failure and fix up comments
Took 4 minutes
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
* [Application] Add single instance guard and mime types.
Took 2 hours 39 minutes
Took 18 minutes
Took 5 minutes
Took 12 seconds
Took 11 seconds
* Rework
Took 30 minutes
Took 50 seconds
* Only enforce single instance if launched with arguments.
Took 5 minutes
* Prototype intents
Took 53 minutes
Took 6 seconds
* Connect/disconnect and join game/room intents.
Took 3 hours 14 minutes
Took 2 seconds
Took 15 seconds
* Fix include.
Took 1 minute
Took 23 seconds
Took 2 seconds
* Mac handling.
Took 10 minutes
Took 12 seconds
Took 3 minutes
* Lint.
Took 3 minutes
* Rebase.
Took 3 minutes
Took 17 seconds
* Implement UrlSchemeEventFilter
Took 10 minutes
Took 7 seconds
* Qt Moc
Took 3 minutes
* Modern PList.
Took 21 minutes
Took 1 minute
* Debug output.
Took 6 minutes
Took 19 minutes
* Watch file:// prefix.
Took 15 minutes
Took 7 seconds
* Better handler.
Took 6 minutes
* Don't store reference in member
Took 5 minutes
* Move impl to cpp, fix lifetime issues.
Took 11 minutes
Took 2 minutes
* Better single-instance handoff, url intent harded
copy game link context-menu
Polish for installers
Took 35 minutes
Took 8 seconds
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
The getUserInfo command for a user that is not currently online returned
the full database record, including the account id, the email address
and the stored client id, to any logged-in requester. Mirror the
redaction already applied to online users via copyUserInfo(): the id and
email are only ever exposed to the account owner, and the client id only
to moderators.
The buddy/ignore add-to-list event likewise returned the target user's
email address and client id to the requester. The list entry only needs
the public profile fields, so strip the email and client id from it as
well.
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
* [Networking] Doxygen
* Lint cause my autolinter is broken lol
* Update.
* Update Doxyfile
Co-authored-by: tooomm <tooomm@users.noreply.github.com>
* Alphabetical ordering
Co-authored-by: tooomm <tooomm@users.noreply.github.com>
* Add new card art rule comment
* move filter program into doxygen folder
* [Networking] Doxygen
Took 49 seconds
* [Networking] Doxygen
Took 2 hours 0 minutes
Took 58 minutes
Took 8 seconds
Took 29 seconds
Took 4 minutes
Took 1 minute
Took 4 minutes
* [Networking] Fix Doxyfile
Took 2 hours 0 minutes
Took 58 minutes
Took 8 seconds
Took 29 seconds
Took 4 minutes
Took 1 minute
Took 6 minutes
* [Networking] Fix Doxyfile
Took 2 hours 0 minutes
Took 58 minutes
Took 8 seconds
Took 29 seconds
Took 4 minutes
Took 1 minute
Took 3 minutes
* [Networking] Fix Doxyfile again
Took 2 hours 0 minutes
Took 58 minutes
Took 8 seconds
Took 29 seconds
Took 4 minutes
Took 1 minute
Took 2 minutes
---------
Co-authored-by: Lukas Brübach <lukas.bruebach@bdosecurity.de>
Co-authored-by: tooomm <tooomm@users.noreply.github.com>
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
* Unify counter clamp arithmetic into shared addClamped() helper
- Add addClamped() in new header clamped_arithmetic.h; uses a 64-bit
intermediate so the addition cannot overflow int.
- Use it in Server_Card::incrementCounter() (clamps [0, MAX_COUNTERS_ON_CARD])
and Server_Counter::incrementCount() (clamps [INT_MIN, INT_MAX]), removing
the duplicated overflow-safe logic and its keep-in-sync TODO.
- Inline incrementCount() into server_counter.h; server_counter.cpp now holds
only the constructor and getInfo().
- Clarify the card-counter bounds comment in trice_limits.h.
* Rename MAX_COUNTERS_ON_CARD to MAX_COUNTER_VALUE
The constant caps the counter's value, not how many counters can be on the card
* Add direct unit tests for addClamped() helper
* Harden offsetCardCounter() against signed-int overflow
Replace the raw oldValue + offset sum with addClamped(), clamping to [0, MAX_COUNTER_VALUE] without overflow.
* Comment update
* Remove class names from addClamped() docstring
* [Room] Additionally show a tab for friends and ignored users instead of just all online users.
Took 21 minutes
Took 12 minutes
* [Room][UserList] Introduce style delegate for user list
- Allow users to set a card name and parameters as their background banner
- Allow mods to white/blacklist cards
- Allow toggling back to the old display style
Took 7 minutes
Took 28 seconds
Took 2 minutes
Took 2 minutes
* Right checkstate.
Took 14 minutes
Took 2 minutes
* Utility for test.
Took 9 minutes
Took 8 seconds
Took 2 seconds
* Lint.
Took 10 minutes
* Algorithm for sql schema migration
Took 13 minutes
* Use {prefix}, bound card name, return errors.
Took 27 seconds
* Convert queue to while loop.
Took 19 seconds
* Hover popup.
Took 36 minutes
Took 1 minute
* More granular signals, popup for user info.
Took 25 minutes
Took 8 seconds
Took 16 minutes
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
* [Game] [Arrows] Track creatorId, use arrowData in arrowItem, use registry, generate unique arrow id's on server side and delete-on-exist inserts.
Took 2 minutes
Took 1 minute
* Fix emitting slot instead of signal.
Took 15 minutes
* Clear arrows locally in special circumstances i.e. teardown.
Took 28 minutes
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
* [Server][Game][Arrows] Properly notify clients when deleting arrows on card move and transform into
Took 15 minutes
* Observe "not found" response
Took 18 minutes
Took 4 seconds
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
* Refactor server counter API to own overflow protection and filter no-op events
Counter modifications now clamp to int bounds server-side and return change
status, allowing command handlers to skip network broadcasts when values
don't actually change.
* Centralize MAX_COUNTERS_ON_CARD and enforce [0, 999] bounds on server
- Move MAX_COUNTERS_ON_CARD to trice_limits.h
- Server clamps values in setCounter() and incrementCounter()
- Client uses clamped comparison to allow recovery from invalid states
- Add tests for clamping behavior
* move incrementCount() implementation from header to cpp
* style: Add braces to all control flow statements
Standardize code style by adding explicit braces to all single-statement
control flow blocks (if, else, for, while) across the entire codebase.
Also documents the InsertBraces clang-format option (requires v15+) for
future automated enforcement.
* InsertBraces-check-enabled
* Fix#6659: Correct logging for bottom-of-library card moves
Cause:
- This issue happens due to logic of moving the card from the top of the
deck being reused when moving from the bottom of the deck, in a way
that makes it impossible to check if the card came from the bottom.
Resolution:
- Updated the logging logic in the client for card moves.
- Added a gRPC parameter ('is_from_bottom') for card moves.
- Updates the server logic to reverse the order of the card move if the
'is_from_bottom' parameter is true.
- Added a test to show the expected behaviour of the fix.
NOTE: While the changes in this patch seem big, this is due to changing
the loop in the moveCard function to a helper function, in order to make
the bug fix change. The only change to the loop was to pass a
variable attribution to the moveCard function because it was redundant
to be in the loop.
* chore: run format on test
* refactor: new way to check if a move is from the bottom of the deck
* refactor: change isFromBottom check to static function
* update comments
Co-authored-by: ebbit1q <ebbit1q@gmail.com>
---------
Co-authored-by: ebbit1q <ebbit1q@gmail.com>
* Add ZoneNames constants for protocol zone identifiers. Introduce a centralized ZoneNames namespace providing constexpr constants for zone identifiers used in the client-server protocol. This establishes a single source of truth for zone names like TABLE, GRAVE, EXILE, HAND, DECK, SIDEBOARD, and STACK. The protocol values remain unchanged (e.g., EXILE maps to rfg for backwards compatibility) while providing meaningful constant names.
* refactor(server): use ZoneNames constants in server game logic
Replace hardcoded zone name strings with ZoneNames:: constants in:
- server_player.cpp: zone setup, draw, shuffle, mulligan operations
- server_abstract_player.cpp: card movement and token destruction
- server_game.cpp: returning cards when players leave
No functional changes - purely mechanical string literal replacement.
* refactor(client): use ZoneNames constants in core player/zone logic
Update the foundational player and zone classes to use ZoneNames::
constants instead of string literals. Changes include:
- player.h/cpp: zone initialization and builtinZones set
- card_zone_logic.cpp: zone name translation for UI display
- table_zone.cpp: table zone operations
No functional changes - purely mechanical string literal replacement.
* refactor(client): use ZoneNames constants in player actions and events
Replace zone name strings with ZoneNames:: constants in the player
action and event handling code. player_actions.cpp contains the most
extensive changes (~90+ replacements) covering all card movement
commands.
No functional changes - purely mechanical string literal replacement.
* refactor(client): use ZoneNames constants in zone menu handlers
Update all zone-specific menu files to use ZoneNames:: constants
for QAction data values and zone targeting. This covers context menus
for cards, graveyard, hand, and exile (RFG) zones.
No functional changes - purely mechanical string literal replacement.
* refactor(client): use ZoneNames constants in game scene components
Update remaining game scene components to use ZoneNames:: constants:
- arrow_item.cpp: arrow drawing between cards
- game_scene.cpp: zone view positioning
- message_log_widget.cpp: removes duplicate local static constants
that were previously defining zone names redundantly
- phases_toolbar.cpp: phase actions (untap all)
Notable: message_log_widget.cpp previously had its own local constants
(TABLE_ZONE_NAME, GRAVE_ZONE_NAME, etc.) which are now removed in favor
of the centralized ZoneNames:: constants.
* formatting fix
* remove helpers
* create getZoneNodes method
* replace direct calls to getRoot and forEachCard
* remove more non-const uses of forEachCard
* make node getter return const lists
* one more usage
* address comment
* address comment again
* fix hash
* fix hashes (for real this time)
* [Cleanup] Unused #includes
Took 44 minutes
* [Cleanup] More unused #includes
Took 55 minutes
* [Cleanup] Include QSet
Took 4 minutes
* [Cleanup] Include QDebug in deck_list.cpp
Took 3 minutes
* [Cleanup] Include protocol stuff in servatrice_database_interface.h
Took 3 minutes
* [Cleanup] Include QDialogButtonBox
Took 8 minutes
* [Cleanup] Include QUrl
Took 8 minutes
* [Cleanup] Include QTextOption in header.
Took 3 minutes
* [Cleanup] Include QMap in user_list_manager.h
Took 8 minutes
* [Cleanup] Adjust qjson
Took 8 minutes
* [Cleanup] include button box.
Took 3 minutes
* [Cleanup] Redo fwd declarations.
* [Cleanup] Redo last removed fwd declarations.
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
* protocol changes
* servatrice changes
* add new setting
* implement client side with static 4 phases
* reading the code explains the code
* add subphases to phase.cpp
* use new subphase definition
* Fix local variable double declaration.
Took 44 seconds
* Mark functions as [[nodiscard]]
Took 31 minutes
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
* Have CardDatabase::getPreferredPrintingInfo respect card provider ID overrides (pinned printings)
Took 13 minutes
Took 37 seconds
Took 10 seconds
Took 10 seconds
# Commit time for manual adjustment:
# Took 30 seconds
Took 15 seconds
Took 8 minutes
Took 21 seconds
* Move settings cache and settings card preference provider out of libcockatrice_settings and into cockatrice
Took 52 minutes
Took 9 minutes
Took 1 minute
* Temp cache.
Took 16 minutes
* Dependency Injection for SettingsCache
* Turn SettingsCache into a QSharedPointer.
* Implement interfaces for settings that need it
Took 2 hours 38 minutes
* Adjust oracle.
Took 5 minutes
* Move abstract/noop interfaces to libcockatrice_interfaces so they can be linked against independently.
Took 52 minutes
* Clean up some links.
Took 3 minutes
* Cleanup two includes.
Took 3 minutes
* More fixes.
Took 7 minutes
* More includes that slipped past.
Took 3 minutes
* Stop mocking and start injecting for tests.
Took 15 minutes
* I don't know why remote_client was including main.
Took 4 minutes
* Include.
Took 3 minutes
* Lint.
Took 2 minutes
* Don't use Qt pointers.
Took 1 hour 7 minutes
* Make parser use CardSettingsInterface
Took 13 minutes
* Also adjust constructor lol.
Took 8 minutes
* Lint.
Took 32 minutes
* Revert "Lint."
This reverts commit ecb596c39e.
Took 3 minutes
* Test.
Took 3 minutes
---------
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
* update format.sh
add shellcheck to format.sh
add statement macros to .clang-format
add no clang format to format.sh
add changed file list to format.sh diff
rename --cf-version to --print-version in format.sh
lint files
* enable --shell on ci runs
* remove useless semicolons
removes the semicolons after empty function definitions
these semicolons are optional, they don't do anything
this will have functions be consistently formatted
if we want to keep the option to have these on the same line like they
were before we should use the option AllowShortFunctionsOnASingleLine: None
* fix script
* update echo line in lint_cpp.sh which doesn't lint cpp only at all