Finished the reset of the major rewrite

This commit is contained in:
unknown 2014-03-20 17:57:22 +01:00
parent b90f0fbd9f
commit c7cf109425
18 changed files with 824 additions and 933 deletions

View File

@ -48,7 +48,9 @@ jar.archive.disabled=${jnlp.enabled}
jar.compress=false
jar.index=${jnlp.enabled}
javac.classpath=\
${libs.Bukkit.classpath}
${libs.Bukkit.classpath}:\
${libs.Log4J-core.classpath}:\
${libs.Log4J-api.classpath}
# Space-separated list of extra javac options
javac.compilerargs=-Xlint:unchecked
javac.deprecation=false

View File

@ -1,513 +0,0 @@
package me.StevenLawson.BukkitTelnet;
import me.StevenLawson.BukkitTelnet.api.TelnetPreLoginEvent;
import me.StevenLawson.BukkitTelnet.api.TelnetCommandEvent;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
import org.bukkit.event.server.RemoteServerCommandEvent;
import org.bukkit.scheduler.BukkitRunnable;
public final class BT_ClientSession extends Thread
{
public enum FilterMode
{
FULL, NONCHAT_ONLY, CHAT_ONLY
}
private static final Pattern NONASCII_FILTER = Pattern.compile("[^\\x20-\\x7E]");
private static final Pattern AUTH_INPUT_FILTER = Pattern.compile("[^a-zA-Z0-9]");
private static final Pattern COMMAND_INPUT_FILTER = Pattern.compile("^[^a-zA-Z0-9/\\?!\\.]+");
//
private final Socket clientSocket;
private final String clientAddress;
//
public static FilterMode filter_mode = FilterMode.FULL;
private SessionLogHandler sessionLogHandler;
private SessionCommandSender sessionCommandSender;
private BufferedWriter writer;
private BufferedReader reader;
private String userName;
private boolean hasTerminated = false;
public BT_ClientSession(Socket clientSocket)
{
this.clientSocket = clientSocket;
this.clientAddress = this.clientSocket.getInetAddress().getHostAddress();
this.userName = this.clientAddress;
BT_Log.info("Client connected: " + this.clientAddress);
}
public boolean isConnected()
{
synchronized (this.clientSocket)
{
return !this.clientSocket.isClosed();
}
}
public void terminateSession()
{
if (this.hasTerminated)
{
return;
}
this.hasTerminated = true;
BT_Log.info("Closing connection: " + this.clientAddress);
if (this.sessionLogHandler != null)
{
BT_Log.getLogger(true).removeHandler(this.sessionLogHandler);
}
synchronized (this.clientSocket)
{
if (this.clientSocket != null)
{
try
{
writeOutFormatted("Closing connection.", true);
this.clientSocket.close();
}
catch (Exception ex)
{
}
}
}
}
public String getUserName()
{
return this.userName;
}
public void writeOut(String message)
{
if (this.writer != null && this.isConnected())
{
try
{
this.writer.write(ChatColor.stripColor(message));
this.writer.flush();
}
catch (IOException ex)
{
}
}
}
public void writeOutFormatted(String message, boolean newLine)
{
writeOut("[BukkitTelnet (Console)]: " + message + (newLine ? "\r\n:" : ""));
}
public void flush()
{
if (this.writer != null && this.isConnected())
{
try
{
this.writer.flush();
}
catch (IOException ex)
{
}
}
}
public void sendBukkitCommand(final String command)
{
final CommandSender sender = getCommandSender();
try
{
new BukkitRunnable()
{
@Override
public void run()
{
final Server server = Bukkit.getServer();
final TelnetCommandEvent telnetEvent = new TelnetCommandEvent(sender, command);
server.getPluginManager().callEvent(telnetEvent);
if (telnetEvent.isCancelled())
{
return;
}
// Deprecated
final RemoteServerCommandEvent serverEvent = new RemoteServerCommandEvent(telnetEvent.getSender(), telnetEvent.getCommand());
server.getPluginManager().callEvent(serverEvent);
final String command = serverEvent.getCommand();
if (command != null && !command.isEmpty())
{
server.dispatchCommand(sender, command);
}
}
}.runTask(BukkitTelnet.plugin);
}
catch (Exception ex)
{
BT_Log.severe(ex);
}
}
public CommandSender getCommandSender()
{
if (this.sessionCommandSender == null)
{
this.sessionCommandSender = new SessionCommandSender(this);
}
return this.sessionCommandSender;
}
@Override
public void run()
{
try
{
synchronized (this.clientSocket)
{
this.reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
this.writer = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
}
}
catch (IOException ex)
{
BT_Log.severe(ex);
}
if (this.reader == null || this.writer == null)
{
terminateSession();
return;
}
writeOut(":");
writeOutFormatted("Session Started.", true);
if (authenticateSession())
{
sessionMainLoop();
}
else
{
writeOutFormatted("Authentication failed.", true);
}
terminateSession();
}
private boolean authenticateSession()
{
if (this.hasTerminated)
{
return false;
}
try
{
boolean isPreAuthenticated = false;
if (this.clientAddress != null)
{
final Iterator<Map.Entry<String, List<String>>> it = BT_Config.getInstance().getConfigEntries().getAdmins().entrySet().iterator();
adminMapLoop:
while (it.hasNext())
{
final Map.Entry<String, List<String>> entry = it.next();
final List<String> adminIPs = entry.getValue();
if (adminIPs != null)
{
for (final String ip : adminIPs)
{
if (fuzzyIpMatch(ip, this.clientAddress, 3))
{
isPreAuthenticated = true;
this.userName = entry.getKey();
break adminMapLoop;
}
}
}
}
}
final TelnetPreLoginEvent event = new TelnetPreLoginEvent(this.clientAddress, isPreAuthenticated ? this.userName : null, isPreAuthenticated);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled())
{
return false;
}
if (event.canBypassPassword())
{
this.userName = event.getName();
return true;
}
else
{
boolean gotValidUsername = false;
int tries = 0;
while (tries++ < 3)
{
try
{
writeOutFormatted("Username: ", false);
String _userName = reader.readLine();
writeOut(":");
if (_userName != null && !_userName.isEmpty())
{
_userName = AUTH_INPUT_FILTER.matcher(_userName).replaceAll("").trim();
}
if (_userName != null && !_userName.isEmpty())
{
this.userName = _userName;
gotValidUsername = true;
break;
}
else
{
writeOutFormatted("Invalid username.", true);
}
}
catch (IOException ex)
{
}
}
if (!gotValidUsername)
{
return false;
}
tries = 0;
while (tries++ < 3)
{
try
{
writeOutFormatted("Password: ", false);
String _password = reader.readLine();
writeOut(":");
if (_password != null && !_password.isEmpty())
{
_password = AUTH_INPUT_FILTER.matcher(_password).replaceAll("").trim();
}
if (_password != null && !_password.isEmpty() && BT_TelnetServer.getInstance().getPassword().equals(_password))
{
return true;
}
else
{
writeOutFormatted("Invalid password.", true);
Thread.sleep(2000);
}
}
catch (IOException ex)
{
}
}
}
}
catch (Exception ex)
{
BT_Log.severe(ex);
}
return false;
}
private void sessionMainLoop()
{
if (this.hasTerminated)
{
return;
}
try
{
writeOutFormatted("Logged in as " + this.userName + ".", true);
BT_Log.info(this.clientAddress + " logged in as \"" + this.userName + "\".");
BT_Log.getLogger(true).addHandler(this.sessionLogHandler = new SessionLogHandler(this));
while (this.isConnected())
{
String command = null;
try
{
command = this.reader.readLine();
}
catch (IOException ex)
{
}
writeOut(":");
if (command != null)
{
command = COMMAND_INPUT_FILTER.matcher(NONASCII_FILTER.matcher(command).replaceAll("")).replaceFirst("").trim();
if (!command.isEmpty())
{
if (command.toLowerCase().startsWith("telnet"))
{
if (command.equalsIgnoreCase("telnet.help"))
{
writeOut("Telnet commands:\r\n");
writeOut("telnet.help - See all of the telnet commands.\r\n");
writeOut("telnet.stopserver - Shutdown the server.\r\n");
writeOut("telnet.log - Change your logging settings.\r\n");
writeOut("telnet.exit - Quit the telnet session.");
}
else if (command.equalsIgnoreCase("telnet.stopserver"))
{
writeOut("Shutting down the server...\r\n");
BT_Log.warning(this.userName + " has shutdown the server.");
System.exit(0);
}
else if (command.equalsIgnoreCase("telnet.log"))
{
if (filter_mode == FilterMode.CHAT_ONLY)
{
filter_mode = FilterMode.FULL;
writeOut("Showing full console log.\r\n");
}
else
{
filter_mode = FilterMode.CHAT_ONLY;
writeOut("Showing chat log only.\r\n");
}
}
else if (command.equalsIgnoreCase("telnet.exit"))
{
terminateSession();
}
}
else
{
sendBukkitCommand(command);
}
}
}
}
}
catch (Exception ex)
{
BT_Log.severe(ex);
}
}
private static boolean fuzzyIpMatch(String a, String b, int octets)
{
boolean match = true;
String[] aParts = a.split("\\.");
String[] bParts = b.split("\\.");
if (aParts.length != 4 || bParts.length != 4)
{
return false;
}
if (octets > 4)
{
octets = 4;
}
else if (octets < 1)
{
octets = 1;
}
for (int i = 0; i < octets && i < 4; i++)
{
if (aParts[i].equals("*") || bParts[i].equals("*"))
{
continue;
}
if (!aParts[i].equals(bParts[i]))
{
match = false;
break;
}
}
return match;
}
private static class SessionLogHandler extends BT_Handler
{
private final BT_ClientSession session;
public SessionLogHandler(BT_ClientSession session)
{
this.session = session;
}
@Override
public void writeOut(String string)
{
this.session.writeOut(string);
}
@Override
public void flush()
{
this.session.flush();
}
@Override
public void close() throws SecurityException
{
this.session.terminateSession();
}
}
private static class SessionCommandSender extends BT_CommandSender
{
private final BT_ClientSession session;
public SessionCommandSender(BT_ClientSession session)
{
this.session = session;
}
@Override
public void sendMessage(String message)
{
if (this.session.sessionLogHandler != null)
{
this.session.sessionLogHandler.writeOut(message + "\r\n:");
}
}
@Override
public String getName()
{
return this.session.getUserName();
}
}
}

View File

@ -1,82 +0,0 @@
package me.StevenLawson.BukkitTelnet;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.LogRecord;
import me.StevenLawson.BukkitTelnet.BT_ClientSession.FilterMode;
import org.bukkit.ChatColor;
public abstract class BT_Handler extends Handler
{
private Formatter formatter;
public abstract void writeOut(String string);
@Override
public final void publish(LogRecord record)
{
if (record == null)
{
return;
}
String message = record.getMessage();
if (this.formatter == null)
{
this.formatter = getFormatter();
}
if (this.formatter != null)
{
message = this.formatter.formatMessage(record);
}
message = ChatColor.stripColor(message);
if (BT_ClientSession.filter_mode == FilterMode.CHAT_ONLY)
{
if (message.startsWith("<") || message.startsWith("[Server:") || message.startsWith("[CONSOLE]<") || message.startsWith("[TotalFreedomMod] [ADMIN]"))
{
writeOut(message + "\r\n:");
}
}
else if (BT_ClientSession.filter_mode == FilterMode.NONCHAT_ONLY)
{
if (!(message.startsWith("<") || message.startsWith("[Server:") || message.startsWith("[CONSOLE]<") || message.startsWith("[TotalFreedomMod] [ADMIN]")))
{
writeOut(message + "\r\n:");
}
}
else
{
writeOut(message + "\r\n:");
}
}
@Override
public final Formatter getFormatter()
{
if (this.formatter == null)
{
this.formatter = super.getFormatter();
Handler[] handlers = org.bukkit.Bukkit.getLogger().getHandlers();
for (Handler handler : handlers)
{
if (handler.getClass().getName().startsWith("org.bukkit.craftbukkit"))
{
Formatter _formatter = handler.getFormatter();
if (_formatter != null)
{
this.formatter = _formatter;
break;
}
}
}
}
return this.formatter;
}
}

View File

@ -1,168 +0,0 @@
package me.StevenLawson.BukkitTelnet;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
public class BT_TelnetServer
{
private String password;
private ServerListener serverListener = null;
private BT_TelnetServer()
{
}
public void startServer()
{
stopServer();
final BT_Config.SimpleConfigEntries configEntries = BT_Config.getInstance().getConfigEntries();
final String address = configEntries.getAddress();
final int port = configEntries.getPort();
this.password = configEntries.getPassword();
if (this.password == null)
{
BT_Log.warning("Telnet password is not defined in config file. Can't start server.");
return;
}
InetAddress hostAddress = null;
if (address != null)
{
try
{
hostAddress = InetAddress.getByName(address);
}
catch (UnknownHostException ex)
{
BT_Log.severe(ex);
}
}
ServerSocket serverSocket = null;
try
{
if (hostAddress == null)
{
serverSocket = new ServerSocket(port);
}
else
{
serverSocket = new ServerSocket(port, 50, hostAddress);
}
String hostIP = serverSocket.getInetAddress().getHostAddress();
if (hostIP.equals("0.0.0.0"))
{
hostIP = "*";
}
BT_Log.info("Server started on " + hostIP + ":" + serverSocket.getLocalPort());
}
catch (IOException ex)
{
BT_Log.severe("Cant bind to " + (hostAddress == null ? "*" : hostAddress) + ":" + port);
BT_Log.severe(ex);
}
if (serverSocket != null)
{
(this.serverListener = new ServerListener(serverSocket)).start();
}
}
public void stopServer()
{
if (this.serverListener != null)
{
this.serverListener.stopServer();
}
}
public String getPassword()
{
return this.password;
}
private static class ServerListener extends Thread
{
private final ServerSocket serverSocket;
private final List<BT_ClientSession> clientSessions = Collections.synchronizedList(new ArrayList<BT_ClientSession>());
public ServerListener(ServerSocket serverSocket)
{
this.serverSocket = serverSocket;
}
@Override
public void run()
{
try
{
while (!this.serverSocket.isClosed())
{
synchronized (clientSessions)
{
final BT_ClientSession clientSession = new BT_ClientSession(this.serverSocket.accept());
clientSessions.add(clientSession);
clientSession.start();
final Iterator<BT_ClientSession> it = clientSessions.iterator();
while (it.hasNext())
{
if (!it.next().isConnected())
{
it.remove();
}
}
}
}
}
catch (IOException ex)
{
}
}
public void stopServer()
{
try
{
this.serverSocket.close();
}
catch (IOException ex)
{
}
synchronized (clientSessions)
{
final Iterator<BT_ClientSession> it = clientSessions.iterator();
while (it.hasNext())
{
it.next().terminateSession();
it.remove();
}
}
}
}
public static BT_TelnetServer getInstance()
{
return BT_TelnetServerHolder.INSTANCE;
}
private static class BT_TelnetServerHolder
{
private static final BT_TelnetServer INSTANCE = new BT_TelnetServer();
}
}

View File

@ -14,26 +14,26 @@ public class BukkitTelnet extends JavaPlugin
plugin = this;
server = plugin.getServer();
BT_Log.setPluginLogger(plugin.getLogger());
BT_Log.setServerLogger(server.getLogger());
TelnetLogger.setPluginLogger(plugin.getLogger());
TelnetLogger.setServerLogger(server.getLogger());
}
@Override
public void onEnable()
{
BT_Config.getInstance().loadConfig();
TelnetConfig.getInstance().loadConfig();
BT_TelnetServer.getInstance().startServer();
TelnetServer.getInstance().startServer();
BT_Log.info(plugin.getName() + " v" + plugin.getDescription().getVersion() + " enabled");
TelnetLogger.info(plugin.getName() + " v" + plugin.getDescription().getVersion() + " enabled");
}
@Override
public void onDisable()
{
BT_TelnetServer.getInstance().stopServer();
TelnetServer.getInstance().stopServer();
BT_Log.info("Plugin disabled");
TelnetLogger.info("Plugin disabled.");
}
}

View File

@ -0,0 +1,79 @@
package me.StevenLawson.BukkitTelnet;
import me.StevenLawson.BukkitTelnet.session.ClientSession;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
public class SocketListener extends Thread
{
private final ServerSocket serverSocket;
private final List<ClientSession> clientSessions = new ArrayList<ClientSession>();
public SocketListener(ServerSocket serverSocket)
{
this.serverSocket = serverSocket;
}
@Override
public void run()
{
while (!serverSocket.isClosed())
{
final Socket clientSocket;
try
{
clientSocket = serverSocket.accept();
}
catch (IOException ex)
{
continue;
}
final ClientSession clientSession = new ClientSession(clientSocket);
clientSessions.add(clientSession);
clientSession.start();
removeDisconnected();
}
}
private void removeDisconnected()
{
final Iterator<ClientSession> it = clientSessions.iterator();
while (it.hasNext())
{
if (!it.next().syncIsConnected())
{
it.remove();
}
}
}
public void stopServer()
{
try
{
serverSocket.close();
}
catch (IOException ex)
{
TelnetLogger.severe(ex);
}
for (ClientSession session : clientSessions)
{
session.syncTerminateSession();
}
clientSessions.clear();
}
}

View File

@ -1,64 +0,0 @@
package me.StevenLawson.BukkitTelnet;
import org.bukkit.command.CommandSender;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
public class TelnetCommandEvent extends Event implements Cancellable
{
private static final HandlerList handlers = new HandlerList();
private boolean cancelled = false;
//
private CommandSender sender;
private String command;
public TelnetCommandEvent(CommandSender sender, String command)
{
this.sender = sender;
this.command = command;
}
@Override
public HandlerList getHandlers()
{
return handlers;
}
public static HandlerList getHandlerList()
{
return handlers;
}
@Override
public boolean isCancelled()
{
return cancelled;
}
@Override
public void setCancelled(boolean cancel)
{
cancelled = cancel;
}
public CommandSender getSender()
{
return sender;
}
public void setSender(CommandSender sender)
{
this.sender = sender;
}
public String getCommand()
{
return command;
}
public void setCommand(String command)
{
this.command = command;
}
}

View File

@ -1,33 +1,30 @@
package me.StevenLawson.BukkitTelnet;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.pravian.bukkitlib.YamlConfig;
public class BT_Config
public class TelnetConfig
{
private YamlConfig config = null;
private final YamlConfig config;
private final SimpleConfigEntries configEntries;
private BT_Config()
private TelnetConfig()
{
configEntries = new SimpleConfigEntries();
config = new YamlConfig(BukkitTelnet.plugin, "config.yml", true);
}
public void loadConfig()
{
if (config == null)
{
config = new YamlConfig(BukkitTelnet.plugin, "config.yml", true);
}
config.load();
configEntries.setAddress(config.getString("address"));
configEntries.setPort(config.getInt("port"));
configEntries.setPassword(config.getString("password"));
configEntries.getAdmins().clear();
configEntries.clearAdmins();
if (config.isConfigurationSection("admins"))
{
@ -39,15 +36,15 @@ public class BT_Config
continue;
}
configEntries.getAdmins().put(admin, config.getStringList("admins." + admin));
configEntries.addAdmin(admin, config.getStringList("admins." + admin));
}
}
if (configEntries.getPassword().equals(""))
if (configEntries.getPassword().isEmpty())
{
configEntries.setPassword(config.getDefaultConfig().getString("password"));
BT_Log.warning("Password set to blank in config!");
BT_Log.warning("Defaulting to " + configEntries.getPassword());
TelnetLogger.warning("Password is undefined in config!");
TelnetLogger.warning("Defaulting to " + configEntries.getPassword());
}
}
@ -100,17 +97,27 @@ public class BT_Config
public Map<String, List<String>> getAdmins()
{
return admins;
return Collections.unmodifiableMap(admins);
}
private void clearAdmins()
{
admins.clear();
}
private void addAdmin(String name, List<String> ips)
{
admins.put(name, ips);
}
}
public static BT_Config getInstance()
public static TelnetConfig getInstance()
{
return BT_ConfigHolder.INSTANCE;
}
private static class BT_ConfigHolder
{
private static final BT_Config INSTANCE = new BT_Config();
private static final TelnetConfig INSTANCE = new TelnetConfig();
}
}

View File

@ -4,13 +4,13 @@ import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.Bukkit;
public final class BT_Log
public final class TelnetLogger
{
private static final Logger FALLBACK_LOGGER = Bukkit.getLogger();
private static Logger serverLogger = null;
private static Logger pluginLogger = null;
private BT_Log()
private TelnetLogger()
{
throw new AssertionError();
}
@ -21,7 +21,7 @@ public final class BT_Log
info(message, false);
}
public static void info(String message, Boolean raw)
public static void info(String message, boolean raw)
{
log(Level.INFO, message, raw);
}
@ -37,7 +37,7 @@ public final class BT_Log
info(message, false);
}
public static void warning(String message, Boolean raw)
public static void warning(String message, boolean raw)
{
log(Level.WARNING, message, raw);
}
@ -53,7 +53,7 @@ public final class BT_Log
info(message, false);
}
public static void severe(String message, Boolean raw)
public static void severe(String message, boolean raw)
{
log(Level.SEVERE, message, raw);
}

View File

@ -1,70 +0,0 @@
package me.StevenLawson.BukkitTelnet;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
public class TelnetPreLoginEvent extends Event implements Cancellable
{
private static final HandlerList handlers = new HandlerList();
private boolean cancelled = false;
//
private String name = null;
private final String ip;
private boolean bypassPassword;
public TelnetPreLoginEvent(String ip, String name, boolean bypassPassword)
{
this.ip = ip;
this.name = name;
this.bypassPassword = bypassPassword;
}
@Override
public HandlerList getHandlers()
{
return handlers;
}
public static HandlerList getHandlerList()
{
return handlers;
}
@Override
public boolean isCancelled()
{
return cancelled;
}
@Override
public void setCancelled(boolean cancel)
{
cancelled = cancel;
}
public String getIp()
{
return ip;
}
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public boolean canBypassPassword()
{
return bypassPassword;
}
public void setBypassPassword(boolean bypassPassword)
{
this.bypassPassword = bypassPassword;
}
}

View File

@ -0,0 +1,97 @@
package me.StevenLawson.BukkitTelnet;
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import me.StevenLawson.BukkitTelnet.TelnetConfig.SimpleConfigEntries;
public class TelnetServer
{
private SocketListener socketListener;
private TelnetServer()
{
}
public void startServer()
{
// If the server is running, stop it
stopServer();
final SimpleConfigEntries config = TelnetConfig.getInstance().getConfigEntries();
// Server address, optional.
final InetAddress hostAddress;
final String address = config.getAddress();
if (address != null)
{
try
{
hostAddress = InetAddress.getByName(address);
}
catch (UnknownHostException ex)
{
TelnetLogger.severe("Cannot start server - Invalid address: " + config.getAddress());
TelnetLogger.severe(ex);
return;
}
}
else
{
hostAddress = null;
}
// Server socket
ServerSocket serversocket;
try
{
if (hostAddress == null)
{
serversocket = new ServerSocket(config.getPort());
}
else
{
serversocket = new ServerSocket(config.getPort(), 50, hostAddress);
}
}
catch (IOException ex)
{
TelnetLogger.severe("Cannot start server - " + "Cant bind to " + (hostAddress == null ? "*" : hostAddress) + ":" + config.getPort());
TelnetLogger.severe(ex);
return;
}
socketListener = new SocketListener(serversocket);
socketListener.start();
final String host = serversocket.getInetAddress().getHostAddress().replace("0.0.0.0", "*");
TelnetLogger.info("Server started on " + host + ":" + serversocket.getLocalPort());
}
public void stopServer()
{
if (socketListener == null)
{
return;
}
socketListener.stopServer();
}
public static TelnetServer getInstance()
{
return BT_TelnetServerHolder.INSTANCE;
}
private static class BT_TelnetServerHolder
{
private static final TelnetServer INSTANCE = new TelnetServer();
}
}

View File

@ -0,0 +1,42 @@
package me.StevenLawson.BukkitTelnet;
public class Util
{
public static boolean fuzzyIpMatch(String a, String b, int octets)
{
boolean match = true;
String[] aParts = a.split("\\.");
String[] bParts = b.split("\\.");
if (aParts.length != 4 || bParts.length != 4)
{
return false;
}
if (octets > 4)
{
octets = 4;
}
else if (octets < 1)
{
octets = 1;
}
for (int i = 0; i < octets && i < 4; i++)
{
if (aParts[i].equals("*") || bParts[i].equals("*"))
{
continue;
}
if (!aParts[i].equals(bParts[i]))
{
match = false;
break;
}
}
return match;
}
}

View File

@ -25,11 +25,10 @@ public class TelnetCommandEvent extends Event implements Cancellable
return handlers;
}
public static HandlerList getHandlerList()
{
return handlers;
}
//public static HandlerList getHandlerList()
//{
// return handlers;
//}
@Override
public boolean isCancelled()
{
@ -59,6 +58,11 @@ public class TelnetCommandEvent extends Event implements Cancellable
public void setCommand(String command)
{
if (command == null)
{
command = "";
}
this.command = command;
}
}

View File

@ -0,0 +1,461 @@
package me.StevenLawson.BukkitTelnet.session;
import me.StevenLawson.BukkitTelnet.api.TelnetPreLoginEvent;
import me.StevenLawson.BukkitTelnet.api.TelnetCommandEvent;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import me.StevenLawson.BukkitTelnet.BukkitTelnet;
import me.StevenLawson.BukkitTelnet.TelnetConfig;
import me.StevenLawson.BukkitTelnet.TelnetLogger;
import me.StevenLawson.BukkitTelnet.Util;
import org.apache.logging.log4j.LogManager;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Server;
import org.bukkit.scheduler.BukkitRunnable;
import org.apache.logging.log4j.core.Logger;
public final class ClientSession extends Thread
{
public static final Pattern NONASCII_FILTER = Pattern.compile("[^\\x20-\\x7E]");
public static final Pattern AUTH_INPUT_FILTER = Pattern.compile("[^a-zA-Z0-9]");
public static final Pattern COMMAND_INPUT_FILTER = Pattern.compile("^[^a-zA-Z0-9/\\?!\\.]+");
//
private final Socket clientSocket;
private final String clientAddress;
//
private final SessionCommandSender commandSender;
private final SessionLogAppender logAppender;
private FilterMode filterMode = FilterMode.FULL;
//
private BufferedWriter writer;
private BufferedReader reader;
private String username;
private boolean hasTerminated;
public ClientSession(Socket clientSocket)
{
this.clientSocket = clientSocket;
this.clientAddress = clientSocket.getInetAddress().getHostAddress();
this.username = "";
this.commandSender = new SessionCommandSender(this);
this.logAppender = new SessionLogAppender(this);
this.hasTerminated = false;
TelnetLogger.info("Client connected: " + clientAddress);
}
@Override
public void run()
{
try
{
synchronized (clientSocket)
{
reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
writer = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
}
}
catch (IOException ex)
{
TelnetLogger.severe(ex);
syncTerminateSession();
return;
}
printRaw(":");
println("Session Started.");
if (!authenticate())
{
println("Authentication failed.");
syncTerminateSession();
}
mainLoop();
syncTerminateSession();
}
public boolean syncIsConnected()
{
synchronized (clientSocket)
{
return !clientSocket.isClosed();
}
}
private Logger getLogger()
{
return (Logger) LogManager.getRootLogger();
}
public synchronized void syncTerminateSession()
{
if (hasTerminated)
{
return;
}
hasTerminated = true;
TelnetLogger.info("Closing connection: " + clientAddress + (username.isEmpty() ? "" : "(" + username + ")"));
getLogger().removeAppender(logAppender);
synchronized (clientSocket)
{
if (clientSocket == null)
{
return;
}
println("Closing connection...");
try
{
clientSocket.close();
}
catch (IOException ex)
{
}
}
}
public String getUserName()
{
return username;
}
public SessionCommandSender getCommandSender()
{
return commandSender;
}
public SessionLogAppender getAppender()
{
return logAppender;
}
public FilterMode getFilterMode()
{
return filterMode;
}
public void setFilterMode(FilterMode filterMode)
{
this.filterMode = filterMode;
}
public void printRaw(String message)
{
if (writer == null || !syncIsConnected())
{
return;
}
try
{
writer.write(ChatColor.stripColor(message));
writer.flush();
}
catch (IOException ex)
{
}
}
public void printRawln(String message)
{
printRaw(message + "\r\n:");
}
public void print(String message)
{
printRaw("[" + (username.isEmpty() ? "" : username + "@") + "BukkitTelnet]$ " + message);
}
public void println(String message)
{
print(message + "\r\n:");
}
public void flush()
{
if (writer == null || !syncIsConnected())
{
return;
}
try
{
writer.flush();
}
catch (IOException ex)
{
}
}
public void syncExecuteCommand(final String command)
{
new BukkitRunnable()
{
@Override
public void run()
{
final Server server = Bukkit.getServer();
final TelnetCommandEvent event = new TelnetCommandEvent(commandSender, command);
server.getPluginManager().callEvent(event);
if (event.isCancelled())
{
return;
}
if (event.getCommand().isEmpty())
{
return;
}
server.dispatchCommand(event.getSender(), event.getCommand());
}
}.runTask(BukkitTelnet.plugin);
}
private boolean authenticate()
{
if (hasTerminated)
{
return false;
}
boolean authenticated = false;
// Pre-authenticate IP addresses
if (clientAddress != null)
{
final Map<String, List<String>> admins = TelnetConfig.getInstance().getConfigEntries().getAdmins();
// For every admin
for (String name : admins.keySet())
{
// For every IP of each admin
for (String ip : admins.get(name))
{
if (Util.fuzzyIpMatch(ip, clientAddress, 3))
{
authenticated = true;
this.username = name;
break;
}
}
}
}
// Send TelnetPreLoginEvent
final TelnetPreLoginEvent event = new TelnetPreLoginEvent(clientAddress, username, authenticated);
Bukkit.getServer().getPluginManager().callEvent(event);
if (event.isCancelled())
{
return false;
}
if (event.canBypassPassword())
{
this.username = event.getName();
return true;
}
// Username / password authentication
boolean validUsername = false;
int tries = 0;
while (tries++ < 3)
{
print("Username: ");
String input;
try
{
input = reader.readLine();
}
catch (IOException ex)
{
continue;
}
printRaw(":");
if (input == null || input.isEmpty()) // End of stream
{
continue;
}
input = AUTH_INPUT_FILTER.matcher(input).replaceAll("").trim();
if (input.isEmpty())
{
println("Invalid username.");
continue;
}
this.username = input;
validUsername = true;
break;
}
if (!validUsername)
{
return false;
}
tries = 0;
while (tries++ < 3)
{
print("Password: ");
String input;
try
{
input = reader.readLine();
}
catch (IOException ex)
{
continue;
}
printRaw(":");
if (input == null || input.isEmpty()) // End of stream
{
continue;
}
input = AUTH_INPUT_FILTER.matcher(input).replaceAll("").trim();
if (TelnetConfig.getInstance().getConfigEntries().getPassword().equals(input))
{
return true;
}
println("Invalid password.");
try
{
Thread.sleep(2000);
}
catch (InterruptedException ex)
{
}
}
return false;
}
private void mainLoop()
{
if (hasTerminated)
{
return;
}
println("Logged in as " + username + ".");
TelnetLogger.info(clientAddress + " logged in as \"" + username + "\".");
// Start feeding data to the client.
getLogger().addAppender(logAppender);
while (syncIsConnected())
{
// Read a command
String command;
try
{
command = reader.readLine();
}
catch (IOException ex)
{
continue;
}
printRaw(":");
if (command == null || command.isEmpty()) // End of stream
{
continue;
}
command = COMMAND_INPUT_FILTER.matcher(NONASCII_FILTER.matcher(command).replaceAll("")).replaceFirst("").trim();
if (command.isEmpty())
{
continue;
}
if (command.toLowerCase().startsWith("telnet"))
{
executeTelnetCommand(command);
continue;
}
syncExecuteCommand(command);
}
}
private void executeTelnetCommand(String command)
{
if (command.equalsIgnoreCase("telnet.help"))
{
println("--- Telnet commands ---");
println("telnet.help - See all of the telnet commands.");
println("telnet.stop - Shut the server down.");
println("telnet.log - Change your logging settings.");
println("telnet.exit - Quit the telnet session.");
return;
}
if (command.equalsIgnoreCase("telnet.stop"))
{
println("Shutting down the server...");
TelnetLogger.warning(username + ": Shutting down the server...");
System.exit(0);
return;
}
if (command.equalsIgnoreCase("telnet.log"))
{
if (filterMode == FilterMode.FULL)
{
filterMode = FilterMode.CHAT_ONLY;
println("Showing only chat logs.");
return;
}
if (filterMode == FilterMode.CHAT_ONLY)
{
filterMode = FilterMode.NONCHAT_ONLY;
println("Showing only non-chat logs.");
return;
}
if (filterMode == FilterMode.NONCHAT_ONLY)
{
filterMode = FilterMode.FULL;
println("Showing all logs.");
}
return;
}
if (command.equalsIgnoreCase("telnet.exit"))
{
syncTerminateSession();
}
}
}

View File

@ -0,0 +1,6 @@
package me.StevenLawson.BukkitTelnet.session;
public enum FilterMode
{
FULL, NONCHAT_ONLY, CHAT_ONLY
}

View File

@ -1,4 +1,4 @@
package me.StevenLawson.BukkitTelnet;
package me.StevenLawson.BukkitTelnet.session;
import java.util.Set;
import org.bukkit.Bukkit;
@ -9,8 +9,27 @@ import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin;
public abstract class BT_CommandSender implements CommandSender
public class SessionCommandSender implements CommandSender
{
private final ClientSession session;
protected SessionCommandSender(ClientSession session)
{
this.session = session;
}
@Override
public void sendMessage(String message)
{
session.printRaw(message + "\r\n:");
}
@Override
public String getName()
{
return this.session.getUserName();
}
@Override
public void sendMessage(String[] messages)
{

View File

@ -0,0 +1,71 @@
package me.StevenLawson.BukkitTelnet.session;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AbstractAppender;
public class SessionLogAppender extends AbstractAppender
{
private final ClientSession session;
private final SimpleDateFormat dateFormat;
public SessionLogAppender(ClientSession session)
{
super("BukkitTelnet", null, null);
this.session = session;
this.dateFormat = new SimpleDateFormat("HH:mm:ss");
start();
}
@Override
public void append(LogEvent event)
{
final String message = event.getMessage().getFormattedMessage();
if (session.getFilterMode() == FilterMode.CHAT_ONLY)
{
if (!(message.startsWith("<")
|| message.startsWith("[Server")
|| message.startsWith("[CONSOLE") || message.startsWith("[TotalFreedomMod] [ADMIN]")))
{
return;
}
}
if (session.getFilterMode() == FilterMode.NONCHAT_ONLY)
{
if (message.startsWith("<") || message.startsWith("[Server") || message.startsWith("[CONSOLE") || message.startsWith("[TotalFreedomMod] [ADMIN]"))
{
return;
}
}
session.printRawln(formatMessage(message, event));
}
private String formatMessage(String message, LogEvent event)
{
final StringBuilder builder = new StringBuilder();
final Throwable ex = event.getThrown();
builder.append("[");
builder.append(dateFormat.format(event.getMillis()));
builder.append(" ");
builder.append(event.getLevel().name().toUpperCase());
builder.append("]: ");
builder.append(message);
if (ex != null)
{
StringWriter writer = new StringWriter();
ex.printStackTrace(new PrintWriter(writer));
builder.append(writer);
}
return builder.toString();
}
}