PHEW! A lot of the conversion to bungeecord is complete, there's only one more class to complete, but I suspect there will be quite a few bugs.

This commit is contained in:
Zachery 2019-10-08 15:36:48 -05:00
parent 7618333bf3
commit 586910a75c
11 changed files with 191 additions and 51 deletions

21
pom.xml
View File

@ -72,7 +72,7 @@
<artifactId>eddsa</artifactId> <artifactId>eddsa</artifactId>
<version>0.3.0</version> <version>0.3.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.mina</groupId> <groupId>org.apache.mina</groupId>
<artifactId>mina-core</artifactId> <artifactId>mina-core</artifactId>
@ -84,7 +84,7 @@
<artifactId>slf4j-api</artifactId> <artifactId>slf4j-api</artifactId>
<version>1.7.28</version> <version>1.7.28</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId> <artifactId>slf4j-jdk14</artifactId>
@ -117,6 +117,21 @@
<version>1.10</version> <version>1.10</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>net.md-5</groupId>
<artifactId>bungeecord-bootstrap</artifactId>
<version>1.13-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
</dependency>
</dependencies> </dependencies>
<!-- Build --> <!-- Build -->
@ -156,7 +171,7 @@
</descriptorRefs> </descriptorRefs>
</configuration> </configuration>
</plugin> </plugin>
<!-- Compile plugin --> <!-- Compile plugin -->
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>

View File

@ -19,8 +19,8 @@ public class ConfigPasswordAuthenticator implements PasswordAuthenticator {
public boolean authenticate(String username, String password, ServerSession ss) public boolean authenticate(String username, String password, ServerSession ss)
{ {
// Depending on our hash type, we have to try and figure out what we're doing. // Depending on our hash type, we have to try and figure out what we're doing.
String HashType = SshdPlugin.instance.getConfig().getString("PasswordType"); String HashType = SshdPlugin.instance.configuration.getString("PasswordType");
String ConfigHash = SshdPlugin.instance.getConfig().getString("Credentials." + username.trim()); String ConfigHash = SshdPlugin.instance.configuration.getString("Credentials." + username.trim());
if (ConfigHash == null) if (ConfigHash == null)
SshdPlugin.instance.getLogger().warning("Config has no such user: " + username); SshdPlugin.instance.getLogger().warning("Config has no such user: " + username);
@ -70,7 +70,7 @@ public class ConfigPasswordAuthenticator implements PasswordAuthenticator {
} }
SshdPlugin.instance.getLogger().info("Failed login for " + username + " using " + HashType + "-based password authentication."); SshdPlugin.instance.getLogger().info("Failed login for " + username + " using " + HashType + "-based password authentication.");
Integer tries = SshdPlugin.instance.getConfig().getInt("LoginRetries"); Integer tries = SshdPlugin.instance.configuration.getInt("LoginRetries");
try try
{ {

View File

@ -5,15 +5,18 @@ package com.ryanmichela.sshd;
*/ */
import jline.console.completer.Completer; import jline.console.completer.Completer;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandMap;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
public class ConsoleCommandCompleter implements Completer {
// This class *may* not be needed.
// If it is needed, the only class that uses it is ConsoleShellFactory on line 96
public class ConsoleCommandCompleter /*implements Completer*/ {
/*
public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) { public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
Waitable<List<String>> waitable = new Waitable<List<String>>() { Waitable<List<String>> waitable = new Waitable<List<String>>() {
@Override @Override
@ -22,7 +25,7 @@ public class ConsoleCommandCompleter implements Completer {
return commandMap.tabComplete(Bukkit.getServer().getConsoleSender(), buffer); return commandMap.tabComplete(Bukkit.getServer().getConsoleSender(), buffer);
} }
}; };
Bukkit.getScheduler().runTask(SshdPlugin.instance, waitable); SshdPlugin.instance.getProxy().getScheduler().runAsync(SshdPlugin.instance, waitable);
try { try {
List<String> offers = waitable.get(); List<String> offers = waitable.get();
if (offers == null) { if (offers == null) {
@ -43,5 +46,6 @@ public class ConsoleCommandCompleter implements Completer {
} }
return cursor; return cursor;
} }
*/
} }

View File

@ -55,12 +55,19 @@ public class ConsoleCommandFactory implements CommandFactory {
try { try {
SshdPlugin.instance.getLogger() SshdPlugin.instance.getLogger()
.info("[U: " + environment.getEnv().get(Environment.ENV_USER) + "] " + command); .info("[U: " + environment.getEnv().get(Environment.ENV_USER) + "] " + command);
SshdPlugin.instance.getProxy().getPluginManager().dispatchCommand(SshdPlugin.instance.getProxy().getConsoleSender().getInstance(), command); SshdPlugin.instance.getProxy().getPluginManager().dispatchCommand(SshdPlugin.instance.getProxy().getConsole(), command);
// getConsoleSender() doesn't exist in bungee, and is replaced with getConsole() from my understanding.
//SshdPlugin.instance.getProxy().getPluginManager().dispatchCommand(SshdPlugin.instance.getProxy().getConsoleSender().getInstance(), command);
//Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command); //Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command);
} catch (Exception e) { }
catch (Exception e)
{
SshdPlugin.instance.getLogger().severe("Error processing command from SSH -" + e.getMessage()); SshdPlugin.instance.getLogger().severe("Error processing command from SSH -" + e.getMessage());
} finally { }
finally
{
callback.onExit(0); callback.onExit(0);
} }
} }

View File

@ -4,7 +4,7 @@ package com.ryanmichela.sshd;
* Copyright 2013 Ryan Michela * Copyright 2013 Ryan Michela
*/ */
import org.bukkit.ChatColor; import net.md_5.bungee.api.ChatColor;
import org.fusesource.jansi.Ansi; import org.fusesource.jansi.Ansi;
import java.io.PrintWriter; import java.io.PrintWriter;

View File

@ -10,6 +10,7 @@ import com.ryanmichela.sshd.StreamHandlerAppender;
import com.ryanmichela.sshd.implementations.SSHDCommandSender; import com.ryanmichela.sshd.implementations.SSHDCommandSender;
import com.ryanmichela.sshd.ConsoleLogFormatter; import com.ryanmichela.sshd.ConsoleLogFormatter;
import jline.console.ConsoleReader; import jline.console.ConsoleReader;
import net.md_5.bungee.api.config.ServerInfo;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Logger; import org.apache.logging.log4j.core.Logger;
import org.apache.sshd.common.Factory; import org.apache.sshd.common.Factory;
@ -18,7 +19,6 @@ import org.apache.sshd.server.command.Command;
import org.apache.sshd.server.channel.ChannelSession; import org.apache.sshd.server.channel.ChannelSession;
import org.apache.sshd.server.Environment; import org.apache.sshd.server.Environment;
import org.apache.sshd.server.ExitCallback; import org.apache.sshd.server.ExitCallback;
import org.bukkit.Bukkit;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@ -32,6 +32,8 @@ import java.util.StringTokenizer;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.StreamHandler; import java.util.logging.StreamHandler;
import static com.ryanmichela.sshd.SshdPlugin.instance;
public class ConsoleShellFactory implements ShellFactory { public class ConsoleShellFactory implements ShellFactory {
public Command createShell(ChannelSession cs) { public Command createShell(ChannelSession cs) {
@ -91,7 +93,7 @@ public class ConsoleShellFactory implements ShellFactory {
{ {
this.ConsoleReader = new ConsoleReader(in, new FlushyOutputStream(out), new SshTerminal()); this.ConsoleReader = new ConsoleReader(in, new FlushyOutputStream(out), new SshTerminal());
this.ConsoleReader.setExpandEvents(true); this.ConsoleReader.setExpandEvents(true);
this.ConsoleReader.addCompleter(new ConsoleCommandCompleter()); //this.ConsoleReader.addCompleter(new ConsoleCommandCompleter());
StreamHandler streamHandler = new FlushyStreamHandler(out, new ConsoleLogFormatter(), this.ConsoleReader); StreamHandler streamHandler = new FlushyStreamHandler(out, new ConsoleLogFormatter(), this.ConsoleReader);
this.streamHandlerAppender = new StreamHandlerAppender(streamHandler); this.streamHandlerAppender = new StreamHandlerAppender(streamHandler);
@ -118,7 +120,7 @@ public class ConsoleShellFactory implements ShellFactory {
{ {
try try
{ {
if (!SshdPlugin.instance.getConfig().getString("Mode").equals("RPC")) if (!instance.configuration.getString("Mode").equals("RPC"))
printPreamble(this.ConsoleReader); printPreamble(this.ConsoleReader);
while (true) while (true)
{ {
@ -141,22 +143,22 @@ public class ConsoleShellFactory implements ShellFactory {
// Hide the mkpasswd command input from other users. // Hide the mkpasswd command input from other users.
Boolean mkpasswd = command.split(" ")[0].equals("mkpasswd"); Boolean mkpasswd = command.split(" ")[0].equals("mkpasswd");
Bukkit.getScheduler().runTask( instance.getProxy().getScheduler().runAsync(
SshdPlugin.instance, () -> instance, () ->
{ {
if (SshdPlugin.instance.getConfig().getString("Mode").equals("RPC") && command.startsWith("rpc")) if (instance.configuration.getString("Mode").equals("RPC") && command.startsWith("rpc"))
{ {
// NO ECHO NO PREAMBLE AND SHIT // NO ECHO NO PREAMBLE AND SHIT
String cmd = command.substring("rpc".length() + 1, command.length()); String cmd = command.substring("rpc".length() + 1, command.length());
SshdPlugin.instance.getProxy().getPluginManager().dispatchCommand(this.SshdCommandSender, cmd); instance.getProxy().getPluginManager().dispatchCommand(this.SshdCommandSender, cmd);
//Bukkit.dispatchCommand(this.SshdCommandSender, cmd); //Bukkit.dispatchCommand(this.SshdCommandSender, cmd);
} }
else else
{ {
if (!mkpasswd) if (!mkpasswd)
SshdPlugin.instance.getLogger().info("<" + this.Username + "> " + command); instance.getLogger().info("<" + this.Username + "> " + command);
SshdPlugin.instance.getProxy().getPluginManager().dispatchCommand(SshdPlugin.instance.getProxy().getConsoleSender().getInstance(), command); instance.getProxy().getPluginManager().dispatchCommand(instance.getProxy().getConsole(), command);
//Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command); //Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command);
} }
}); });
@ -164,18 +166,18 @@ public class ConsoleShellFactory implements ShellFactory {
} }
catch (IOException e) catch (IOException e)
{ {
SshdPlugin.instance.getLogger().log(Level.SEVERE, "Error processing command from SSH", e); instance.getLogger().log(Level.SEVERE, "Error processing command from SSH", e);
} }
finally finally
{ {
SshdPlugin.instance.getLogger().log(Level.INFO, this.Username + " disconnected from SSH."); instance.getLogger().log(Level.INFO, this.Username + " disconnected from SSH.");
callback.onExit(0); callback.onExit(0);
} }
} }
private void printPreamble(ConsoleReader cr) throws IOException private void printPreamble(ConsoleReader cr) throws IOException
{ {
File f = new File(SshdPlugin.instance.getDataFolder(), "motd.txt"); File f = new File(instance.getDataFolder(), "motd.txt");
try try
{ {
BufferedReader br = new BufferedReader(new FileReader(f)); BufferedReader br = new BufferedReader(new FileReader(f));
@ -186,16 +188,18 @@ public class ConsoleShellFactory implements ShellFactory {
} }
catch (FileNotFoundException e) catch (FileNotFoundException e)
{ {
SshdPlugin.instance.getLogger().log(Level.WARNING, "Could not open " + f + ": File does not exist."); instance.getLogger().log(Level.WARNING, "Could not open " + f + ": File does not exist.");
// Not showing the SSH motd is not a fatal failure, let the session continue. // Not showing the SSH motd is not a fatal failure, let the session continue.
} }
// Doesn't really guarantee our actual system hostname but // Doesn't really guarantee our actual system hostname but
// it's better than not having one at all. // it's better than not having one at all.
cr.println("Connected to: " + InetAddress.getLocalHost().getHostName() + " (BungeeCord)\r"); cr.println("Connected to: " + InetAddress.getLocalHost().getHostName() + " (BungeeCord)\r");
cr.println(ConsoleLogFormatter.ColorizeString(DO SOMETHING HERE).replaceAll("\n", "\r\n")); // Since BungeeCord is stupid, we have to parse the config file and the the MOTD from it that way...
// If you try to use the method getMotd() it returns that it can't be referenced from a non-static context, which is stupid.
cr.println(ConsoleLogFormatter.ColorizeString(instance.configuration.getString("motd")).replaceAll("\n", "\r\n"));
cr.println("\r"); cr.println("\r");
cr.println("Type 'exit' to exit the shell." + "\r"); cr.println("Type 'exit' or press Ctrl+D exit the shell." + "\r");
cr.println("===============================================" + "\r"); cr.println("===============================================" + "\r");
} }
} }

View File

@ -1,15 +1,67 @@
package com.ryanmichela.sshd; package com.ryanmichela.sshd;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.command.Command;
import org.bukkit.entity.Player;
import java.util.Arrays; import java.util.Arrays;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Command;
import com.ryanmichela.sshd.Cryptography; import com.ryanmichela.sshd.Cryptography;
import com.ryanmichela.sshd.SshdPlugin; import com.ryanmichela.sshd.SshdPlugin;
public class MkpasswdCommand extends Command
{
public MkpasswdCommand()
{
super("mkpasswd");
}
@Override
public void execute(CommandSender sender, String[] args)
{
ProxiedPlayer player = (ProxiedPlayer) sender;
String algoritm, password;
algoritm = args[0];
password = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
try
{
// Stupid bukkit, we have to concatenate the arguments together if they're using
// spaces in their passwords otherwise it won't be as strong as it should be.
}
catch (ArrayIndexOutOfBoundsException e)
{
// ignore it.
}
// If they're console, allow regardless.
try
{
if (player.hasPermission("sshd.mkpasswd"))
{
// Dumb but whatever. Some people are really dense.
if (algoritm.equalsIgnoreCase("PLAIN"))
sender.sendMessage(password);
else if (algoritm.equalsIgnoreCase("pbkdf2"))
sender.sendMessage(Cryptography.PBKDF2_HashPassword(password));
else if (algoritm.equalsIgnoreCase("bcrypt"))
sender.sendMessage(Cryptography.BCrypt_HashPassword(password));
else if (algoritm.equalsIgnoreCase("sha256"))
sender.sendMessage(Cryptography.SHA256_HashPassword(password));
}
}
catch (Exception e)
{
// since this is a player, send a failure message
sender.sendMessage("An error occured, please check console.");
e.printStackTrace();
}
}
}
/*
class MkpasswdCommand implements CommandExecutor class MkpasswdCommand implements CommandExecutor
{ {
@Override @Override
@ -96,4 +148,4 @@ class MkpasswdCommand implements CommandExecutor
} }
return false; return false;
} }
} }*/

View File

@ -1,5 +1,6 @@
package com.ryanmichela.sshd; package com.ryanmichela.sshd;
import net.md_5.bungee.config.Configuration;
import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.ArrayUtils;
import org.apache.sshd.common.config.keys.AuthorizedKeyEntry; import org.apache.sshd.common.config.keys.AuthorizedKeyEntry;
import org.apache.sshd.common.config.keys.PublicKeyEntryResolver; import org.apache.sshd.common.config.keys.PublicKeyEntryResolver;
@ -20,14 +21,13 @@ public class PublicKeyAuthenticator implements PublickeyAuthenticator
{ {
private File authorizedKeysDir; private File authorizedKeysDir;
private Map<String, Integer> FailCounts = new HashMap<String, Integer>(); private Map<String, Integer> FailCounts = new HashMap<String, Integer>();
public PublicKeyAuthenticator(File authorizedKeysDir) { this.authorizedKeysDir = authorizedKeysDir; } public PublicKeyAuthenticator(File authorizedKeysDir) { this.authorizedKeysDir = authorizedKeysDir; }
@Override public boolean authenticate(String username, PublicKey key, ServerSession session) @Override public boolean authenticate(String username, PublicKey key, ServerSession session)
{ {
byte[] keyBytes = key.getEncoded(); byte[] keyBytes = key.getEncoded();
File keyFile = new File(authorizedKeysDir, username); File keyFile = new File(authorizedKeysDir, username);
Integer tries = SshdPlugin.instance.getConfig().getInt("LoginRetries"); Integer tries = SshdPlugin.instance.configuration.getInt("LoginRetries");
if (keyFile.exists()) if (keyFile.exists())
{ {

View File

@ -1,11 +1,15 @@
package com.ryanmichela.sshd; package com.ryanmichela.sshd;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.config.Configuration;
import net.md_5.bungee.config.ConfigurationProvider;
import net.md_5.bungee.config.YamlConfiguration;
import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory; import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory;
import org.apache.sshd.server.SshServer; import org.apache.sshd.server.SshServer;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider; import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.apache.sshd.server.subsystem.sftp.SftpSubsystemFactory; import org.apache.sshd.server.subsystem.sftp.SftpSubsystemFactory;
import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.config.Configuration; import net.md_5.bungee.api.config.*;
import com.ryanmichela.sshd.ConsoleShellFactory; import com.ryanmichela.sshd.ConsoleShellFactory;
import com.ryanmichela.sshd.MkpasswdCommand; import com.ryanmichela.sshd.MkpasswdCommand;
@ -25,10 +29,14 @@ public final class SshdPlugin extends Plugin
{ {
private SshServer sshd; private SshServer sshd;
public static SshdPlugin instance; public static SshdPlugin instance;
private File file;
public Configuration configuration;
@Override public void onLoad() @Override public void onLoad()
{ {
saveDefaultConfig(); file = new File(ProxyServer.getInstance().getPluginsFolder()+ "/config.yml");
File authorizedKeys = new File(getDataFolder(), "authorized_keys"); File authorizedKeys = new File(getDataFolder(), "authorized_keys");
if (!authorizedKeys.exists()) if (!authorizedKeys.exists())
authorizedKeys.mkdirs(); authorizedKeys.mkdirs();
@ -47,10 +55,32 @@ public final class SshdPlugin extends Plugin
e.printStackTrace(); e.printStackTrace();
} }
try
{
if (!file.exists())
{
file.createNewFile();
}
configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(file);
// more testing
configuration.set("test", "This configuration file works!");
ConfigurationProvider.getProvider(YamlConfiguration.class).save(configuration,file);
}
catch (IOException e)
{
e.printStackTrace();
}
// Don't go any lower than INFO or SSHD will cause a stack overflow exception. // Don't go any lower than INFO or SSHD will cause a stack overflow exception.
// SSHD will log that it wrote bites to the output stream, which writes // SSHD will log that it wrote bites to the output stream, which writes
// bytes to the output stream - ad nauseaum. // bytes to the output stream - ad nauseaum.
getLogger().setLevel(Level.INFO); getLogger().setLevel(Level.INFO);
// config testing
String printout = configuration.getString("test");
getLogger().info(printout);
} }
@Override public void onEnable() @Override public void onEnable()
@ -58,8 +88,8 @@ public final class SshdPlugin extends Plugin
instance = this; instance = this;
sshd = SshServer.setUpDefaultServer(); sshd = SshServer.setUpDefaultServer();
sshd.setPort(getConfig().getInt("Port", 1025)); sshd.setPort(configuration.getInt("Port", 1025));
String host = getConfig().getString("ListenAddress", "all"); String host = configuration.getString("ListenAddress", "all");
sshd.setHost(host.equals("all") ? null : host); sshd.setHost(host.equals("all") ? null : host);
File hostKey = new File(getDataFolder(), "hostkey"); File hostKey = new File(getDataFolder(), "hostkey");
@ -70,14 +100,15 @@ public final class SshdPlugin extends Plugin
sshd.setPasswordAuthenticator(new ConfigPasswordAuthenticator()); sshd.setPasswordAuthenticator(new ConfigPasswordAuthenticator());
sshd.setPublickeyAuthenticator(new PublicKeyAuthenticator(authorizedKeys)); sshd.setPublickeyAuthenticator(new PublicKeyAuthenticator(authorizedKeys));
if (getConfig().getBoolean("EnableSFTP")) if (configuration.getBoolean("EnableSFTP"))
{ {
sshd.setSubsystemFactories(Collections.singletonList(new SftpSubsystemFactory())); sshd.setSubsystemFactories(Collections.singletonList(new SftpSubsystemFactory()));
sshd.setFileSystemFactory( sshd.setFileSystemFactory(
new VirtualFileSystemFactory(FileSystems.getDefault().getPath(getDataFolder().getAbsolutePath()).getParent().getParent())); new VirtualFileSystemFactory(FileSystems.getDefault().getPath(getDataFolder().getAbsolutePath()).getParent().getParent()));
} }
this.getCommand("mkpasswd").setExecutor(new MkpasswdCommand()); getProxy().getPluginManager().registerCommand(this, new MkpasswdCommand());
//this.getCommand("mkpasswd").setExecutor(new MkpasswdCommand());
sshd.setCommandFactory(new ConsoleCommandFactory()); sshd.setCommandFactory(new ConsoleCommandFactory());
try try
@ -101,4 +132,12 @@ public final class SshdPlugin extends Plugin
// do nothing // do nothing
} }
} }
public static SshdPlugin getInstance() {
return instance;
}
private static void setInstance(SshdPlugin instance) {
SshdPlugin.instance = instance;
}
} }

View File

@ -1,7 +1,9 @@
package com.ryanmichela.sshd.implementations; package com.ryanmichela.sshd.implementations;
import com.ryanmichela.sshd.SshdPlugin; import com.ryanmichela.sshd.SshdPlugin;
import net.md_5.bungee.command.ConsoleCommandSender; import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ProxyServer;
@ -26,14 +28,15 @@ import com.ryanmichela.sshd.ConsoleShellFactory;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.Set; import java.util.Collection;
import java.util.Collections;
import java.util.logging.Level; import java.util.logging.Level;
@NoArgsConstructor(access = AccessLevel.PRIVATE) @NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class SSHDConsoleCommandSender implements CommandSender public final class SSHDCommandSender implements CommandSender {
{ private static final SSHDCommandSender instance = new SSHDCommandSender();
@Getter
private static final SSHDConsoleCommandSender instance = new SSHDConsoleCommandSender(); public ConsoleShellFactory.ConsoleShell console;
@Override @Override
public void sendMessage(String message) { public void sendMessage(String message) {

View File

@ -0,0 +1,16 @@
package com.ryanmichela.sshd.sshd1;
import net.md_5.bungee.api.plugin.Plugin;
public final class SshdPlugin extends Plugin {
@Override
public void onEnable() {
// Plugin startup logic
}
@Override
public void onDisable() {
// Plugin shutdown logic
}
}