Add a configurable nickname ban filter, similar to the chat filter except this is defined in the properties file since it doesn't need unicode. Any user that attempts to use a nick that contains anything on this list will be denied.
Fix a bug with /kick and /ban that caused it to only work against users with entirely lower-case nicknames.
Add a check that the user's IP address hasn't changed. This probably isn't as needed now that /kick actually works against everybody.
When users connect (or reload the page), show a permalink to that session's games as well as a permalink to their entire play history, if they haven't opted out of that tracking. When a game starts, or a player/specator joins a game in progress, show a permalink to that game's rounds.
The "when a game starts" bit required removing the tracking of the 'dealing' state, as there was no other easy way to determine that a game was starting. Nothing actually used that dealing state, so it was harmless to remove. Now, a transition from lobby to playing can be detected as a game start, as opposed to a transition from round over to playing.
This takes advantage of the metrics logging, the metrics processor, and the metrics viewer to provide a permalink to a particular round, instead of requiring players to take a screenshot of the round. This will not be enabled immediately as the viewer is not quite ready for deployment, but this is all that needs done on the game server to support this, so it can just be dynamically enabled when it's ready.
First load handler needs to send those things so the client actually has it. Doesn't really need the persistent id there, but it definitely needs the sigil to avoid undefined errors.
Server startup time is included in first load response, and game creation time is included in game info. IRC bridge uses these, and perhaps a way to see them in the web client will be added too.
Trying to figure out why some people can still get in while banned. I cannot reproduce this, and it does not make sense that it is possible as the admin page lists their current IP address in the ban list... and those are all trimmed, so it can't be spaces. Weird.
Unicode characters weren't getting loaded correctly for some reason, either literally or via escape sequences. Change to specifying a class name which has a compile-coded list of shadowbanned strings. This prevents changing on the fly, but at least it works for now until a proper database can be implemented.
Update the privacy policy about chat logging due to shadowbans.
CAPS LOCK FILTER if a line is long enough and contains mostly caps.
Shadowban filter blocks messages with configurable substrings present in them. Does not permanently shadowban the user, yet, just drops the message.
Add a test that was missed in a previous commit.
* A certain amount of characters in the message must be latin-ish, if the message is longer than a certain length.
* There must be a certain number of spaces in the message, if the message is longer than a certain length.
* The same message cannot be repeated twice in the same location.
* Switched the separator between parts for the chat control config value from _ to . for the scope.
The fix for #124 apparently introduced another bug wherein logging out while playing in a game caused an NPE while ensuring that the user was also not spectating the game. Hold onto that value a little bit longer to make sure we can call that method as well, even though it shouldn't need to be called at that point (but an NPE is worse).
Split the configuration value into two. Add a tracking object to ChatFilter per user which currently contains the two different last message times. Removed the last message times from the User object. Show chat error messages only in the tab that caused them, not both tabs.
Refactored out the flood protection, empty message, and message too long errors out to the new class. This will also easily allow adding other chat protections in the future, in one location. Further refactoring should be possible to not have to hold chat-protection related information in the User object, as well.
* GameId needs to be an *int not an int so we can tell the difference between lack of value and value 0.
* Add the description strings to DisconnectReason.
* Add Sigil and IdCode to NewPlayer messages.
* Add if join/quit events are being broadcast to JavascriptConfigServlet. It works much better if they are but it should still work if they aren't.