The original code attempted to parse the JavaScript as it went along,
counting open and close brackets. Unfortunately, this doesn't
take comments and string literals into consideration, so it would very
likely have failed with more complicated filters.
Instead, we'll let the JavaScript compiler handle all the complexity
and simply see if the code compiles. If it doesn't, but the error
occured in the last line, we assume it can be recovered by adding a
new line.
The filter command allows users with sufficient permission (or OPs) to
execute arbitrary JavaScript (no sandboxing). This is fine for a
debug and testing, but could potentially be exploited in a
production environment.
Instead, we disable this command by default and force users to enable it
specifically in the configuration file (not through commands). If
someone has access to the config.yml file, they probably also have
access to the plugins/ folder and thus the ability to install plugins
with arbitrary code execution as well.
Should ensure that packet listeners recieve the most up-to-date player
instance, regardless of whether or not the main thread is blocked in the
player listener. No more temporary players.
This is because multiple plugins depend on us, and are not properly
notified after ProtocolLib has been reloaded.
The only possible solution is to reload every dependent plugin after
ProtocolLib has been reloaded, but unfortunately, I ran into
LinkageErrors when I tried it. So it's probably not possible with the
current architecture to support reloaders.
Instead, we'll simply print a BIG BOLD warning telling any users of
these plugins that ProtocolLib cannot be reloaded except through the
built in "/reload" command.
Previously, we have used a BlockingHashMap to simply lock the packet
read thread until we have had a chance to intercept the
NetLoginHandler/PendingConnection and store InputStream ->
PlayerInjector -> TemporaryPlayer.
Problem is, this could potentially cause problems if, for some reason, a
packet is intercepted after the player has logged out and the player
injector has been removed from the lookup map. In that case, the read
thread would wait until it reaches the default timeout of 2 seconds.
Locking threads is fairly inefficient in general, and waiting for the
server connection thread to update the NetLoginHandler list could take a
while.
Instead, ProtocolLib will now intercept any Socket accepted in the
server's main ServerSocket, and record any calls to getInputStream().
That way, we can get a InputStream -> Socket mapping before the server
thread ever creates the read and write threads in NetLoginHandler ->
NetworkManager.
Unfortunately, it's not trivial to swap out the ServerSocket in the
DedicatedServerConnectionThread - we actually have to trigger the
accept() thread and move through a cycle of the loop before our custom
ServerSocket is used. To do this, we will actually connect to the server
and read its MOTD manually, hopefully getting to it before any other
players.
This creates a slight overhead of a couple of threads per server start,
but it's probably much better than locking the read thread. More testing
is needed though before this can be confirmed.