Well. It compiles. Can't say much.
Code overhaul for the sponge API which is vastly different from bungeecord port. This still requires lots of work though.
This commit is contained in:
parent
67aa5c63ea
commit
41b561a88c
180
pom.xml
180
pom.xml
@ -25,108 +25,116 @@
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.sshd</groupId>
|
||||
<artifactId>sshd-core</artifactId>
|
||||
<version>2.3.0</version>
|
||||
</dependency>
|
||||
|
||||
<!--Just include a *few* things.-->
|
||||
<dependency>
|
||||
<groupId>org.apache.sshd</groupId>
|
||||
<artifactId>sshd-core</artifactId>
|
||||
<version>2.3.0</version>
|
||||
<scope>compile</scope>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.sshd</groupId>
|
||||
<artifactId>sshd-mina</artifactId>
|
||||
<version>2.3.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.sshd</groupId>
|
||||
<artifactId>sshd-mina</artifactId>
|
||||
<version>2.3.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.sshd</groupId>
|
||||
<artifactId>sshd-common</artifactId>
|
||||
<version>2.3.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.sshd</groupId>
|
||||
<artifactId>sshd-common</artifactId>
|
||||
<version>2.3.0</version>
|
||||
<scope>compile</scope>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.sshd</groupId>
|
||||
<artifactId>sshd-sftp</artifactId>
|
||||
<version>2.3.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.sshd</groupId>
|
||||
<artifactId>sshd-sftp</artifactId>
|
||||
<version>2.3.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.i2p.crypto</groupId>
|
||||
<artifactId>eddsa</artifactId>
|
||||
<version>0.3.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.i2p.crypto</groupId>
|
||||
<artifactId>eddsa</artifactId>
|
||||
<version>0.3.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.mina</groupId>
|
||||
<artifactId>mina-core</artifactId>
|
||||
<version>2.1.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.mina</groupId>
|
||||
<artifactId>mina-core</artifactId>
|
||||
<version>2.1.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.28</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-jdk14</artifactId>
|
||||
<version>1.7.28</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.28</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jline</groupId>
|
||||
<artifactId>jline</artifactId>
|
||||
<version>2.12.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-jdk14</artifactId>
|
||||
<version>1.7.28</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>2.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jline</groupId>
|
||||
<artifactId>jline</artifactId>
|
||||
<version>2.12.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>2.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>2.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>1.10</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- include Sponge API -->
|
||||
<dependency>
|
||||
<groupId>org.spongepowered</groupId>
|
||||
<artifactId>spongeapi</artifactId>
|
||||
<version>7.1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Used for getting the git hash -->
|
||||
<dependency>
|
||||
<groupId>pl.project13.maven</groupId>
|
||||
<artifactId>git-commit-id-plugin</artifactId>
|
||||
<version>3.0.1</version>
|
||||
<type>maven-plugin</type>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>2.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>1.10</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<version>2.6</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.4</version>
|
||||
</dependency>
|
||||
<!-- include Sponge API -->
|
||||
<dependency>
|
||||
<groupId>org.spongepowered</groupId>
|
||||
<artifactId>spongeapi</artifactId>
|
||||
<version>7.1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<!-- Set our default goal to be clean and build a package -->
|
||||
<defaultGoal>clean package</defaultGoal>
|
||||
<!-- Include our git hash in the final name -->
|
||||
<finalName>${project.name}-${project.version}-${git.commit.id.abbrev}</finalName>
|
||||
<finalName>${project.name}-${project.version}</finalName>
|
||||
|
||||
<resources>
|
||||
<resource>
|
||||
<targetPath>.</targetPath>
|
||||
<filtering>true</filtering>
|
||||
<directory>${basedir}/src/main/resources</directory>
|
||||
<includes>
|
||||
<include>motd.txt</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<!-- Plugins -->
|
||||
<plugins>
|
||||
|
@ -19,11 +19,11 @@ public class ConfigPasswordAuthenticator implements PasswordAuthenticator {
|
||||
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.
|
||||
String HashType = SshdPlugin.instance.getConfig().getString("PasswordType");
|
||||
String ConfigHash = SshdPlugin.instance.getConfig().getString("Credentials." + username.trim());
|
||||
String HashType = SshdPlugin.GetInstance().PasswordType;
|
||||
String ConfigHash = SshdPlugin.GetInstance().config.configNode.getNode("Credentials", username.trim(), "password").getString();
|
||||
|
||||
if (ConfigHash == null)
|
||||
SshdPlugin.instance.getLogger().warning("Config has no such user: " + username);
|
||||
SshdPlugin.GetLogger().warn("Config has no such user: " + username);
|
||||
else
|
||||
{
|
||||
try
|
||||
@ -69,8 +69,8 @@ public class ConfigPasswordAuthenticator implements PasswordAuthenticator {
|
||||
}
|
||||
}
|
||||
|
||||
SshdPlugin.instance.getLogger().info("Failed login for " + username + " using " + HashType + "-based password authentication.");
|
||||
Integer tries = SshdPlugin.instance.getConfig().getInt("LoginRetries");
|
||||
SshdPlugin.GetLogger().info("Failed login for " + username + " using " + HashType + "-based password authentication.");
|
||||
Integer tries = SshdPlugin.GetInstance().LoginRetries;
|
||||
|
||||
try
|
||||
{
|
||||
@ -83,7 +83,7 @@ public class ConfigPasswordAuthenticator implements PasswordAuthenticator {
|
||||
if (this.FailCounts.get(username) >= tries)
|
||||
{
|
||||
this.FailCounts.put(username, 0);
|
||||
SshdPlugin.instance.getLogger().info("Too many failures for " + username + ", disconnecting.");
|
||||
SshdPlugin.GetLogger().info("Too many failures for " + username + ", disconnecting.");
|
||||
ss.close(true);
|
||||
}
|
||||
}
|
||||
|
@ -5,43 +5,56 @@ package com.ryanmichela.sshd;
|
||||
*/
|
||||
|
||||
import jline.console.completer.Completer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandMap;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class ConsoleCommandCompleter implements Completer {
|
||||
|
||||
public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
|
||||
Waitable<List<String>> waitable = new Waitable<List<String>>() {
|
||||
public class ConsoleCommandCompleter //implements Completer
|
||||
{
|
||||
/*
|
||||
public int complete(final String buffer, final int cursor, final List<CharSequence> candidates)
|
||||
{
|
||||
Waitable<List<String>> waitable = new Waitable<List<String>>()
|
||||
{
|
||||
@Override
|
||||
protected List<String> evaluate() {
|
||||
protected List<String> evaluate()
|
||||
{
|
||||
CommandMap commandMap = ReflectionUtil.getProtectedValue(Bukkit.getServer(), "commandMap");
|
||||
return commandMap.tabComplete(Bukkit.getServer().getConsoleSender(), buffer);
|
||||
}
|
||||
};
|
||||
|
||||
Bukkit.getScheduler().runTask(SshdPlugin.instance, waitable);
|
||||
try {
|
||||
try
|
||||
{
|
||||
List<String> offers = waitable.get();
|
||||
if (offers == null) {
|
||||
if (offers == null)
|
||||
{
|
||||
return cursor;
|
||||
}
|
||||
candidates.addAll(offers);
|
||||
|
||||
final int lastSpace = buffer.lastIndexOf(' ');
|
||||
if (lastSpace == -1) {
|
||||
if (lastSpace == -1)
|
||||
{
|
||||
return cursor - buffer.length();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return cursor - (buffer.length() - lastSpace - 1);
|
||||
}
|
||||
} catch (ExecutionException e) {
|
||||
}
|
||||
catch (ExecutionException e)
|
||||
{
|
||||
SshdPlugin.instance.getLogger().log(Level.WARNING, "Unhandled exception when tab completing", e);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
return cursor;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ import org.apache.sshd.server.command.CommandFactory;
|
||||
import org.apache.sshd.server.channel.ChannelSession;
|
||||
import org.apache.sshd.server.Environment;
|
||||
import org.apache.sshd.server.ExitCallback;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.spongepowered.api.Sponge;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@ -51,14 +51,21 @@ public class ConsoleCommandFactory implements CommandFactory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start(ChannelSession cs, Environment environment) throws IOException {
|
||||
try {
|
||||
SshdPlugin.instance.getLogger()
|
||||
public void start(ChannelSession cs, Environment environment) throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
SshdPlugin.GetLogger()
|
||||
.info("[U: " + environment.getEnv().get(Environment.ENV_USER) + "] " + command);
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command);
|
||||
} catch (Exception e) {
|
||||
SshdPlugin.instance.getLogger().severe("Error processing command from SSH -" + e.getMessage());
|
||||
} finally {
|
||||
|
||||
Sponge.getCommandManager().process(Sponge.getServer().getConsole(), command);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
SshdPlugin.GetLogger().error("Error processing command from SSH -" + e.getMessage());
|
||||
}
|
||||
finally
|
||||
{
|
||||
callback.onExit(0);
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ package com.ryanmichela.sshd;
|
||||
* Copyright 2013 Ryan Michela
|
||||
*/
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import com.ryanmichela.sshd.ChatColor;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
@ -18,7 +18,12 @@ import org.apache.sshd.server.command.Command;
|
||||
import org.apache.sshd.server.channel.ChannelSession;
|
||||
import org.apache.sshd.server.Environment;
|
||||
import org.apache.sshd.server.ExitCallback;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.spongepowered.api.MinecraftVersion;
|
||||
import org.spongepowered.api.Platform;
|
||||
import org.spongepowered.api.Sponge;
|
||||
import org.spongepowered.api.command.CommandManager;
|
||||
import org.spongepowered.api.plugin.PluginContainer;
|
||||
import org.spongepowered.api.scheduler.SpongeExecutorService;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
@ -29,6 +34,7 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.InetAddress;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.StreamHandler;
|
||||
|
||||
@ -91,7 +97,7 @@ public class ConsoleShellFactory implements ShellFactory {
|
||||
{
|
||||
this.ConsoleReader = new ConsoleReader(in, new FlushyOutputStream(out), new SshTerminal());
|
||||
this.ConsoleReader.setExpandEvents(true);
|
||||
this.ConsoleReader.addCompleter(new ConsoleCommandCompleter());
|
||||
//this.ConsoleReader.addCompleter(new ConsoleCommandCompleter());
|
||||
|
||||
StreamHandler streamHandler = new FlushyStreamHandler(out, new ConsoleLogFormatter(), this.ConsoleReader);
|
||||
this.streamHandlerAppender = new StreamHandlerAppender(streamHandler);
|
||||
@ -118,7 +124,11 @@ public class ConsoleShellFactory implements ShellFactory {
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!SshdPlugin.instance.getConfig().getString("Mode").equals("RPC"))
|
||||
// Get the sponge command manager so we can execute commands.
|
||||
CommandManager CmdManager = Sponge.getCommandManager();
|
||||
SpongeExecutorService MinecraftExecutor = Sponge.getScheduler().createSyncExecutor(SshdPlugin.GetInstance());
|
||||
// Print the SSHD motd.
|
||||
if (!SshdPlugin.GetInstance().Mode.equals("RPC"))
|
||||
printPreamble(this.ConsoleReader);
|
||||
while (true)
|
||||
{
|
||||
@ -143,14 +153,13 @@ public class ConsoleShellFactory implements ShellFactory {
|
||||
// Hide the mkpasswd command input from other users.
|
||||
Boolean mkpasswd = command.split(" ")[0].equals("mkpasswd");
|
||||
|
||||
Bukkit.getScheduler().runTask(
|
||||
SshdPlugin.instance, () ->
|
||||
MinecraftExecutor.schedule(() ->
|
||||
{
|
||||
if (SshdPlugin.instance.getConfig().getString("Mode").equals("RPC") && command.startsWith("rpc"))
|
||||
if (SshdPlugin.GetInstance().Mode.equals("RPC") && command.startsWith("rpc"))
|
||||
{
|
||||
// NO ECHO NO PREAMBLE AND SHIT
|
||||
String cmd = command.substring("rpc".length() + 1, command.length());
|
||||
Bukkit.dispatchCommand(this.SshdCommandSender, cmd);
|
||||
CmdManager.process(this.SshdCommandSender, cmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -159,31 +168,31 @@ public class ConsoleShellFactory implements ShellFactory {
|
||||
// our plugin and the connected client.
|
||||
if (!mkpasswd)
|
||||
{
|
||||
SshdPlugin.instance.getLogger().info("<" + this.Username + "> " + command);
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command);
|
||||
SshdPlugin.GetLogger().info("<" + this.Username + "> " + command);
|
||||
CmdManager.process(Sponge.getServer().getConsole(), command);
|
||||
}
|
||||
else
|
||||
{
|
||||
Bukkit.dispatchCommand(this.SshdCommandSender, command);
|
||||
CmdManager.process(this.SshdCommandSender, command);
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 0, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
SshdPlugin.instance.getLogger().log(Level.SEVERE, "Error processing command from SSH", e);
|
||||
SshdPlugin.GetLogger().error("Error processing command from SSH", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
SshdPlugin.instance.getLogger().log(Level.INFO, this.Username + " disconnected from SSH.");
|
||||
SshdPlugin.GetLogger().info(this.Username + " disconnected from SSH.");
|
||||
callback.onExit(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void printPreamble(ConsoleReader cr) throws IOException
|
||||
{
|
||||
File f = new File(SshdPlugin.instance.getDataFolder(), "motd.txt");
|
||||
File f = new File(SshdPlugin.GetInstance().ConfigDir.toFile(), "motd.txt");
|
||||
try
|
||||
{
|
||||
BufferedReader br = new BufferedReader(new FileReader(f));
|
||||
@ -194,14 +203,24 @@ public class ConsoleShellFactory implements ShellFactory {
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
SshdPlugin.instance.getLogger().log(Level.WARNING, "Could not open " + f + ": File does not exist.");
|
||||
SshdPlugin.GetLogger().warn("Could not open " + f + ": File does not exist.");
|
||||
// Not showing the SSH motd is not a fatal failure, let the session continue.
|
||||
}
|
||||
|
||||
// Doesn't really guarantee our actual system hostname but
|
||||
// it's better than not having one at all.
|
||||
cr.println("Connected to: " + InetAddress.getLocalHost().getHostName() + " (" + Bukkit.getServer().getName() + ")\r");
|
||||
cr.println(ConsoleLogFormatter.ColorizeString(Bukkit.getServer().getMotd()).replaceAll("\n", "\r\n"));
|
||||
Platform p = Sponge.getPlatform();
|
||||
MinecraftVersion mv = p.getMinecraftVersion();
|
||||
PluginContainer pc = p.getContainer(Platform.Component.API);
|
||||
String str = String.format(
|
||||
"Connected to: %s -- Minecraft %s (%s %s)",
|
||||
InetAddress.getLocalHost().getHostName(),
|
||||
mv.getName(),
|
||||
pc.getName(),
|
||||
pc.getVersion().orElse("<Unknown>"));
|
||||
|
||||
cr.println(str + "\r");
|
||||
cr.println(ConsoleLogFormatter.ColorizeString(Sponge.getServer().getMotd().toPlain()).replaceAll("\n", "\r\n"));
|
||||
cr.println("\r");
|
||||
cr.println("Type 'exit' to exit the shell." + "\r");
|
||||
cr.println("===============================================" + "\r");
|
||||
|
@ -10,99 +10,123 @@ import java.util.Arrays;
|
||||
|
||||
import com.ryanmichela.sshd.Cryptography;
|
||||
import com.ryanmichela.sshd.SshdPlugin;
|
||||
|
||||
import org.spongepowered.api.Sponge;
|
||||
import org.spongepowered.api.command.CommandException;
|
||||
import org.spongepowered.api.command.CommandResult;
|
||||
import org.spongepowered.api.command.CommandSource;
|
||||
import org.spongepowered.api.command.args.CommandContext;
|
||||
import org.spongepowered.api.command.args.GenericArguments;
|
||||
import org.spongepowered.api.command.spec.CommandExecutor;
|
||||
import org.spongepowered.api.command.spec.CommandSpec;
|
||||
import org.spongepowered.api.entity.living.player.Player;
|
||||
import org.spongepowered.api.event.command.TabCompleteEvent;
|
||||
import org.spongepowered.api.text.Text;
|
||||
|
||||
class MkpasswdCommand implements CommandExecutor
|
||||
public class MkpasswdCommand implements CommandExecutor
|
||||
{
|
||||
// Because Spigot's failed syntax API is really less than ideal (you should be required to add a
|
||||
// SendSyntax function override), we're just always going to return true even for syntax failures
|
||||
// as we will handle the syntax message internally. This also lets us send the messages more
|
||||
// securely to the client without people knowing we're using the command. This prevents password
|
||||
// or hash leakages from the user to other connected users. Plus this syntax will show how
|
||||
// to both use the command and what hashes we support which is important for people who don't
|
||||
// know how to RTFM. - Justin
|
||||
private void SendSyntax(CommandSource sender, boolean invalid)
|
||||
private static CommandSpec cmdspec;
|
||||
public static void BuildCommand()
|
||||
{
|
||||
if (invalid)
|
||||
// So, to send a message in sponge, you must use "Text.of()" for some reason.
|
||||
sender.sendMessage(Text.of("\u00A7cInvalid Syntax\u00A7r"));
|
||||
sender.sendMessage(Text.of("\u00A7a/mkpasswd <help|hash> <password>\u00A7r"));
|
||||
sender.sendMessage(Text.of("\u00A79Supported Hashes: SHA256, PBKDF2, BCRYPT, PLAIN\u00A7r"));
|
||||
}
|
||||
CommandSpec pbkdf2 = CommandSpec.builder()
|
||||
.description(Text.of("PBKDF2 hashed password"))
|
||||
.permission("sshd.mkpasswd.pbkdf2")
|
||||
.arguments(GenericArguments.remainingJoinedStrings(Text.of("password")))
|
||||
.executor((CommandSource source, CommandContext args) -> {
|
||||
try
|
||||
{
|
||||
source.sendMessage(Text.of("\u00A79Your Hash: " + Cryptography.PBKDF2_HashPassword(args.<String>getOne("message").get())));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
return CommandResult.success();
|
||||
})
|
||||
.build();
|
||||
|
||||
public boolean onCommand(CommandSource sender, TabCompleteEvent.Command command, String label, String[] args)
|
||||
{
|
||||
// If we're not mkpasswd, just fuck off.
|
||||
if (!label.equalsIgnoreCase("mkpasswd"))
|
||||
return false;
|
||||
CommandSpec bcrypt = CommandSpec.builder()
|
||||
.description(Text.of("BCrypt hashed password"))
|
||||
.permission("sshd.mkpasswd.bcrypt")
|
||||
.arguments(GenericArguments.remainingJoinedStrings(Text.of("password")))
|
||||
.executor((CommandSource source, CommandContext args) -> {
|
||||
try
|
||||
{
|
||||
source.sendMessage(Text.of("\u00A79Your Hash: " + Cryptography.BCrypt_HashPassword(args.<String>getOne("message").get())));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
return CommandResult.success();
|
||||
})
|
||||
.build();
|
||||
|
||||
String algoritm, password;
|
||||
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.
|
||||
algoritm = args[0];
|
||||
password = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
|
||||
if (password.trim().isEmpty()) // Shortcut to the catch statement below.
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
catch (ArrayIndexOutOfBoundsException e)
|
||||
{
|
||||
// ignore it.
|
||||
this.SendSyntax(sender, true);
|
||||
return true;
|
||||
}
|
||||
CommandSpec sha256 = CommandSpec.builder()
|
||||
.description(Text.of("SHA256 hashed password"))
|
||||
.permission("sshd.mkpasswd.sha256")
|
||||
.arguments(GenericArguments.remainingJoinedStrings(Text.of("password")))
|
||||
.executor((CommandSource source, CommandContext args) -> {
|
||||
try
|
||||
{
|
||||
source.sendMessage(Text.of("\u00A79Your Hash: " + Cryptography.SHA256_HashPassword(args.<String>getOne("message").get())));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
return CommandResult.success();
|
||||
})
|
||||
.build();
|
||||
|
||||
boolean hasperm = (!(sender instanceof Player)) || ((Player) sender).hasPermission("sshd.mkpasswd");
|
||||
// The plain text encryption method
|
||||
CommandSpec plain = CommandSpec.builder()
|
||||
.description(Text.of("Plain text password (insecure)"))
|
||||
.permission("sshd.mkpasswd.plain")
|
||||
.executor((CommandSource source, CommandContext args) -> {
|
||||
source.sendMessage(Text.of("Bro... It's literally your unhashed password."));
|
||||
return CommandResult.success();
|
||||
})
|
||||
.build();
|
||||
|
||||
if (hasperm)
|
||||
{
|
||||
try
|
||||
{
|
||||
String hash = "";
|
||||
// Dumb but whatever. Some people are really dense.
|
||||
if (algoritm.equalsIgnoreCase("PLAIN"))
|
||||
{
|
||||
// I mean c'mon...
|
||||
sender.sendMessage(Text.of("Bro really? it's literally your unencrypted password..."));
|
||||
return true;
|
||||
}
|
||||
else if (algoritm.equalsIgnoreCase("pbkdf2"))
|
||||
hash = Cryptography.PBKDF2_HashPassword(password);
|
||||
else if (algoritm.equalsIgnoreCase("bcrypt"))
|
||||
hash = Cryptography.BCrypt_HashPassword(password);
|
||||
else if (algoritm.equalsIgnoreCase("sha256"))
|
||||
hash = Cryptography.SHA256_HashPassword(password);
|
||||
else
|
||||
{
|
||||
this.SendSyntax(sender, !algoritm.equalsIgnoreCase("help"));
|
||||
return true;
|
||||
}
|
||||
// The "help" command to show syntax usage
|
||||
CommandSpec helpcmd = CommandSpec.builder()
|
||||
.description(Text.of("Display's mkpasswd help"))
|
||||
.permission("sshd.mkpasswd.help")
|
||||
.executor((CommandSource source, CommandContext args) -> {
|
||||
source.sendMessage(Text.of("\u00A7a/mkpasswd <help|hash> <password>\u00A7r"));
|
||||
source.sendMessage(Text.of("\u00A79Supported Hashes: SHA256, PBKDF2, BCRYPT, PLAIN\u00A7r"));
|
||||
return CommandResult.success();
|
||||
})
|
||||
.build();
|
||||
|
||||
sender.sendMessage(Text.of("\u00A79Your Hash: " + hash + "\u00A7r"));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// We're console, just print the stack trace.
|
||||
e.printStackTrace();
|
||||
sender.sendMessage(Text.of("\u00A7cAn error occured. Please check console for details.\u00A7r"));
|
||||
}
|
||||
}
|
||||
// the root "mkpasswd" command
|
||||
cmdspec = CommandSpec.builder()
|
||||
.description(Text.of("Create an SSHd password using hashes"))
|
||||
.extendedDescription(Text.of("Supported Hashes: SHA256, PBKDF2, BCRYPT, PLAIN"))
|
||||
.permission("sshd.mkpasswd")
|
||||
.child(helpcmd, "help", "h")
|
||||
.child(plain, "plain")
|
||||
.child(sha256, "sha256")
|
||||
.child(bcrypt, "bcrypt")
|
||||
.child(pbkdf2, "pbkdf2")
|
||||
.executor(new MkpasswdCommand())
|
||||
.build();
|
||||
|
||||
return true;
|
||||
// Register our command with Sponge.
|
||||
Sponge.getCommandManager().register(SshdPlugin.GetInstance(), cmdspec, "mkpasswd");
|
||||
}
|
||||
|
||||
// so sponge needed this, still figuring out the sponge API ~ Zach
|
||||
@Override
|
||||
public CommandResult execute(CommandSource src, CommandContext args) throws CommandException
|
||||
{
|
||||
return null;
|
||||
// This command doesn't do anything.
|
||||
src.sendMessage(Text.of("\u00A7a/mkpasswd <help|hash> <password>\u00A7r"));
|
||||
src.sendMessage(Text.of("\u00A79Supported Hashes: SHA256, PBKDF2, BCRYPT, PLAIN\u00A7r"));
|
||||
return CommandResult.success();
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@ public class PublicKeyAuthenticator implements PublickeyAuthenticator
|
||||
{
|
||||
byte[] keyBytes = key.getEncoded();
|
||||
File keyFile = new File(authorizedKeysDir, username);
|
||||
Integer tries = SshdPlugin.instance.LoginRetries;
|
||||
Integer tries = SshdPlugin.GetInstance().LoginRetries;
|
||||
|
||||
if (keyFile.exists())
|
||||
{
|
||||
@ -46,7 +46,7 @@ public class PublicKeyAuthenticator implements PublickeyAuthenticator
|
||||
}
|
||||
else
|
||||
{
|
||||
SshdPlugin.instance.getLogger().info(
|
||||
SshdPlugin.GetLogger().info(
|
||||
username + " failed authentication via SSH session using key file " + keyFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
@ -59,7 +59,7 @@ public class PublicKeyAuthenticator implements PublickeyAuthenticator
|
||||
if (this.FailCounts.get(username) >= tries)
|
||||
{
|
||||
this.FailCounts.put(username, 0);
|
||||
SshdPlugin.instance.getLogger().info("Too many failures for " + username + ", disconnecting.");
|
||||
SshdPlugin.GetLogger().info("Too many failures for " + username + ", disconnecting.");
|
||||
session.close(true);
|
||||
}
|
||||
|
||||
@ -67,12 +67,12 @@ public class PublicKeyAuthenticator implements PublickeyAuthenticator
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
SshdPlugin.instance.getLogger().error("Failed to process public key " + keyFile.getAbsolutePath() + " " + e.getMessage());
|
||||
SshdPlugin.GetLogger().error("Failed to process public key " + keyFile.getAbsolutePath() + " " + e.getMessage());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SshdPlugin.instance.getLogger().error("Could not locate public key for " + username
|
||||
SshdPlugin.GetLogger().error("Could not locate public key for " + username
|
||||
+ ". Make sure the user's key is named the same as their user name "
|
||||
+ "without a file extension.");
|
||||
}
|
||||
|
@ -3,6 +3,8 @@ package com.ryanmichela.sshd;
|
||||
import com.ryanmichela.sshd.utils.Config;
|
||||
import org.spongepowered.api.Sponge;
|
||||
import org.spongepowered.api.command.spec.CommandSpec;
|
||||
import org.spongepowered.api.config.DefaultConfig;
|
||||
import org.spongepowered.api.config.ConfigDir;
|
||||
import org.spongepowered.api.plugin.Plugin;
|
||||
import org.spongepowered.api.event.Listener;
|
||||
import org.spongepowered.api.event.game.state.GameStartedServerEvent;
|
||||
@ -20,6 +22,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.logging.Level;
|
||||
|
||||
@ -27,7 +30,13 @@ import com.google.inject.Inject;
|
||||
import org.slf4j.Logger;
|
||||
import org.spongepowered.api.text.Text;
|
||||
|
||||
@Plugin(id = "spongesshd", name = "Sponge-SSHD", version = "1.3.7", description = "Sponge port for Minecraft-SSHD. SSH for your minecraft server!")
|
||||
@Plugin(
|
||||
id = "sshd",
|
||||
name = "Minecraft-SSHD",
|
||||
version = "1.3.7",
|
||||
description = "Sponge port for Minecraft-SSHD. SSH for your minecraft server!",
|
||||
authors={"Justin Crawford", "Zachery Coleman"}
|
||||
)
|
||||
public class SshdPlugin
|
||||
{
|
||||
String ListenAddress = "";
|
||||
@ -38,31 +47,29 @@ public class SshdPlugin
|
||||
String PasswordType = "";
|
||||
// Credentials
|
||||
|
||||
private File modConfigFolder;
|
||||
CommandSpec MkpasswdCommand = CommandSpec.builder()
|
||||
.description(Text.of("Make a SSHD password hash"))
|
||||
.permission("sshd.mkpasswd")
|
||||
.build();
|
||||
|
||||
public File getDataFolder()
|
||||
{
|
||||
return modConfigFolder;
|
||||
}
|
||||
|
||||
private SshServer sshd;
|
||||
public static SshdPlugin instance;
|
||||
private static SshdPlugin instance;
|
||||
|
||||
@Inject
|
||||
public Logger logger;
|
||||
public static Logger logger;
|
||||
|
||||
@Inject
|
||||
@DefaultConfig(sharedRoot = false)
|
||||
public Path DefaultConfig;
|
||||
|
||||
@Inject
|
||||
@ConfigDir(sharedRoot = false)
|
||||
public Path ConfigDir;
|
||||
|
||||
public Config config;
|
||||
|
||||
@Listener
|
||||
public void onServerStart(GameStartedServerEvent event)
|
||||
{
|
||||
instance = this;
|
||||
// Parse our config
|
||||
config = new Config();
|
||||
config.setup();
|
||||
config.setup();
|
||||
|
||||
// Now include it in our dealio here
|
||||
this.Mode = config.configNode.getNode("Mode").getString();
|
||||
@ -70,33 +77,43 @@ public class SshdPlugin
|
||||
this.ListenAddress = config.configNode.getNode("ListenAddress").getString();
|
||||
this.Port = config.configNode.getNode("Port").getInt();
|
||||
this.LoginRetries = config.configNode.getNode("LoginRetries").getInt();
|
||||
this.EnableSFTP = config.configNode.getNode("EnableSFTP").getBoolean();
|
||||
this.EnableSFTP = config.configNode.getNode("EnableSFTP").getBoolean();
|
||||
|
||||
try
|
||||
{
|
||||
File motd = new File(this.ConfigDir.toFile(), "motd.txt");
|
||||
if (!motd.exists())
|
||||
{
|
||||
InputStream link = (getClass().getResourceAsStream("/motd.txt"));
|
||||
Files.copy(link, motd.getAbsoluteFile().toPath());
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
sshd = SshServer.setUpDefaultServer();
|
||||
sshd.setPort(this.Port);
|
||||
String host = this.ListenAddress;
|
||||
sshd.setHost(host.equals("all") ? null : host);
|
||||
sshd.setHost(this.ListenAddress.equals("all") ? null : this.ListenAddress);
|
||||
|
||||
File hostKey = new File(getDataFolder(), "hostkey");
|
||||
File authorizedKeys = new File(getDataFolder(), "authorized_keys");
|
||||
File hostKey = new File(this.ConfigDir.toFile(), "hostkey");
|
||||
File authorizedKeys = new File(this.ConfigDir.toFile(), "authorized_keys");
|
||||
|
||||
sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(hostKey.toPath()));
|
||||
sshd.setShellFactory(new ConsoleShellFactory());
|
||||
sshd.setPasswordAuthenticator(new ConfigPasswordAuthenticator());
|
||||
sshd.setPublickeyAuthenticator(new PublicKeyAuthenticator(authorizedKeys));
|
||||
|
||||
|
||||
|
||||
if (this.EnableSFTP)
|
||||
{
|
||||
sshd.setSubsystemFactories(Collections.singletonList(new SftpSubsystemFactory()));
|
||||
sshd.setFileSystemFactory(
|
||||
new VirtualFileSystemFactory(FileSystems.getDefault().getPath(getDataFolder().getAbsolutePath()).getParent().getParent()));
|
||||
new VirtualFileSystemFactory(this.ConfigDir.getParent().getParent()));
|
||||
}
|
||||
|
||||
Sponge.getCommandManager().register(instance, MkpasswdCommand, "mkpasswd");
|
||||
//this.getCommand("mkpasswd").setExecutor(new MkpasswdCommand());
|
||||
MkpasswdCommand.BuildCommand();
|
||||
|
||||
sshd.setCommandFactory(new ConsoleCommandFactory());
|
||||
try
|
||||
@ -105,13 +122,18 @@ public class SshdPlugin
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
getLogger().error("Failed to start SSH server! ", e);
|
||||
logger.error("Failed to start SSH server! ", e);
|
||||
}
|
||||
|
||||
logger.info("Successfully running ExamplePlugin!!!");
|
||||
logger.info("Loaded Minecraft-SSHD.");
|
||||
}
|
||||
|
||||
public Logger getLogger()
|
||||
public static SshdPlugin GetInstance()
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static Logger GetLogger()
|
||||
{
|
||||
return logger;
|
||||
}
|
||||
|
@ -3,21 +3,39 @@ package com.ryanmichela.sshd.implementations;
|
||||
import com.ryanmichela.sshd.SshdPlugin;
|
||||
import com.ryanmichela.sshd.ConsoleShellFactory;
|
||||
import com.ryanmichela.sshd.ConsoleLogFormatter;
|
||||
import org.spongepowered.api.command.source.ConsoleSource;
|
||||
import org.spongepowered.api.command.CommandSource;
|
||||
import org.spongepowered.api.text.Text;
|
||||
import org.spongepowered.api.text.channel.MessageChannel;
|
||||
import org.spongepowered.api.service.permission.Subject;
|
||||
import org.spongepowered.api.service.permission.SubjectCollection;
|
||||
import org.spongepowered.api.service.permission.SubjectData;
|
||||
import org.spongepowered.api.service.permission.SubjectReference;
|
||||
import org.spongepowered.api.service.context.Context;
|
||||
import org.spongepowered.api.util.Tristate;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.Optional;
|
||||
import java.util.List;
|
||||
|
||||
// This is gonna be a mess.
|
||||
public class SSHDCommandSender implements ConsoleCommandSender, CommandSource
|
||||
public class SSHDCommandSender implements ConsoleSource
|
||||
{
|
||||
private final PermissibleBase perm = new PermissibleBase(this);
|
||||
private final SSHDConversationTracker conversationTracker = new SSHDConversationTracker();
|
||||
private MessageChannel mc = MessageChannel.TO_CONSOLE;
|
||||
private Subject subjectDelegate;
|
||||
// Set by the upstream allocating function
|
||||
public ConsoleShellFactory.ConsoleShell console;
|
||||
|
||||
// This is an override for Sponge to work with the SSH consoles.
|
||||
public void sendMessage(Text message)
|
||||
{
|
||||
this.sendRawMessage(message.toPlain() + "\r");
|
||||
}
|
||||
|
||||
// Back port from Spigot/BungeeCord-style API calls.
|
||||
public void sendMessage(String message)
|
||||
{
|
||||
this.sendRawMessage(message + "\r");
|
||||
@ -45,96 +63,98 @@ public class SSHDCommandSender implements ConsoleCommandSender, CommandSource
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
SshdPlugin.instance.getLogger().log(Level.SEVERE, "Error sending message to SSHDCommandSender", e);
|
||||
SshdPlugin.GetLogger().error("Error sending message to SSHDCommandSender", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMessage(String[] messages) {
|
||||
public void sendMessage(String[] messages)
|
||||
{
|
||||
Arrays.asList(messages).forEach(this::sendMessage);
|
||||
}
|
||||
|
||||
public MessageChannel getMessageChannel()
|
||||
{
|
||||
return mc;
|
||||
}
|
||||
|
||||
public void setMessageChannel(MessageChannel channel)
|
||||
{
|
||||
mc = channel;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return "SSHD Console";
|
||||
}
|
||||
|
||||
public boolean isOp() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setOp(boolean value) {
|
||||
throw new UnsupportedOperationException("Cannot change operator status of server console");
|
||||
}
|
||||
|
||||
public boolean beginConversation(Conversation conversation) {
|
||||
return this.conversationTracker.beginConversation(conversation);
|
||||
}
|
||||
|
||||
public void abandonConversation(Conversation conversation) {
|
||||
this.conversationTracker.abandonConversation(conversation, new ConversationAbandonedEvent(conversation, new ManuallyAbandonedConversationCanceller()));
|
||||
}
|
||||
|
||||
public void abandonConversation(Conversation conversation, ConversationAbandonedEvent details) {
|
||||
this.conversationTracker.abandonConversation(conversation, details);
|
||||
}
|
||||
|
||||
public void acceptConversationInput(String input) {
|
||||
this.conversationTracker.acceptConversationInput(input);
|
||||
}
|
||||
|
||||
public boolean isConversing() {
|
||||
return this.conversationTracker.isConversing();
|
||||
}
|
||||
|
||||
public boolean isPermissionSet(String name) {
|
||||
return this.perm.isPermissionSet(name);
|
||||
}
|
||||
|
||||
public boolean isPermissionSet(Permission perm) {
|
||||
return this.perm.isPermissionSet(perm);
|
||||
}
|
||||
|
||||
public boolean hasPermission(String name) {
|
||||
return this.perm.hasPermission(name);
|
||||
}
|
||||
|
||||
public boolean hasPermission(Permission perm) {
|
||||
return this.perm.hasPermission(perm);
|
||||
}
|
||||
|
||||
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) {
|
||||
return this.perm.addAttachment(plugin, name, value);
|
||||
}
|
||||
|
||||
public PermissionAttachment addAttachment(Plugin plugin) {
|
||||
return this.perm.addAttachment(plugin);
|
||||
}
|
||||
|
||||
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) {
|
||||
return this.perm.addAttachment(plugin, name, value, ticks);
|
||||
}
|
||||
|
||||
public PermissionAttachment addAttachment(Plugin plugin, int ticks) {
|
||||
return this.perm.addAttachment(plugin, ticks);
|
||||
}
|
||||
|
||||
public void removeAttachment(PermissionAttachment attachment) {
|
||||
this.perm.removeAttachment(attachment);
|
||||
}
|
||||
|
||||
public void recalculatePermissions() {
|
||||
this.perm.recalculatePermissions();
|
||||
}
|
||||
|
||||
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
|
||||
return this.perm.getEffectivePermissions();
|
||||
}
|
||||
|
||||
public boolean isPlayer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Server getServer() {
|
||||
return Bukkit.getServer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Context> getActiveContexts() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSubjectDataPersisted() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChildOf(Set<Context> contexts, SubjectReference parent) {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubjectData getTransientSubjectData() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubjectData getSubjectData() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tristate getPermissionValue(Set<Context> contexts, String permission) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SubjectReference> getParents(Set<Context> contexts) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getOption(Set<Context> contexts, String key) {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubjectCollection getContainingCollection() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<CommandSource> getCommandSource() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubjectReference asSubjectReference() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -1,78 +0,0 @@
|
||||
package com.ryanmichela.sshd.implementations;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.conversations.Conversation;
|
||||
import org.bukkit.conversations.ConversationAbandonedEvent;
|
||||
import org.bukkit.conversations.ManuallyAbandonedConversationCanceller;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class SSHDConversationTracker {
|
||||
private LinkedList<Conversation> conversationQueue = new LinkedList<>();
|
||||
|
||||
synchronized boolean beginConversation(Conversation conversation) {
|
||||
if (!this.conversationQueue.contains(conversation)) {
|
||||
this.conversationQueue.addLast(conversation);
|
||||
if (this.conversationQueue.getFirst() == conversation) {
|
||||
conversation.begin();
|
||||
conversation.outputNextPrompt();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
synchronized void abandonConversation(Conversation conversation, ConversationAbandonedEvent details) {
|
||||
if (!this.conversationQueue.isEmpty()) {
|
||||
if (this.conversationQueue.getFirst() == conversation) {
|
||||
conversation.abandon(details);
|
||||
}
|
||||
|
||||
if (this.conversationQueue.contains(conversation)) {
|
||||
this.conversationQueue.remove(conversation);
|
||||
}
|
||||
|
||||
if (!this.conversationQueue.isEmpty()) {
|
||||
this.conversationQueue.getFirst().outputNextPrompt();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public synchronized void abandonAllConversations() {
|
||||
LinkedList<Conversation> oldQueue = this.conversationQueue;
|
||||
this.conversationQueue = new LinkedList<>();
|
||||
|
||||
for (Conversation conversation : oldQueue) {
|
||||
try {
|
||||
conversation.abandon(new ConversationAbandonedEvent(conversation, new ManuallyAbandonedConversationCanceller()));
|
||||
} catch (Throwable var5) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "Unexpected exception while abandoning a conversation", var5);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
synchronized void acceptConversationInput(String input) {
|
||||
if (this.isConversing()) {
|
||||
Conversation conversation = this.conversationQueue.getFirst();
|
||||
|
||||
try {
|
||||
conversation.acceptInput(input);
|
||||
} catch (Throwable var4) {
|
||||
conversation.getContext().getPlugin().getLogger().log(Level.WARNING, String.format("Plugin %s generated an exception whilst handling conversation input", conversation.getContext().getPlugin().getDescription().getFullName()), var4);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
synchronized boolean isConversing() {
|
||||
return !this.conversationQueue.isEmpty();
|
||||
}
|
||||
|
||||
public synchronized boolean isConversingModaly() {
|
||||
return this.isConversing() && this.conversationQueue.getFirst().isModal();
|
||||
}
|
||||
}
|
@ -17,21 +17,20 @@ public class Config
|
||||
{
|
||||
// Give us a config!
|
||||
@Inject
|
||||
@DefaultConfig(sharedRoot = true)
|
||||
@DefaultConfig(sharedRoot = false)
|
||||
// idk what to do with this one.
|
||||
private ConfigurationLoader<CommentedConfigurationNode> configLoader = HoconConfigurationLoader.builder().setPath(SshdPlugin.instance.defaultConfig).build();
|
||||
private ConfigurationLoader<CommentedConfigurationNode> configLoader = HoconConfigurationLoader.builder().setPath(SshdPlugin.GetInstance().DefaultConfig).build();
|
||||
|
||||
public CommentedConfigurationNode configNode;
|
||||
|
||||
|
||||
public void setup()
|
||||
{
|
||||
// I'm not sure if this will even work, the sponge config API is confusing.
|
||||
if (!Files.exists((Path) SshdPlugin.instance.config.configLoader.getDefaultOptions()))
|
||||
if (!Files.exists(SshdPlugin.GetInstance().DefaultConfig))
|
||||
{
|
||||
try
|
||||
{
|
||||
Files.createFile((Path) SshdPlugin.instance.config.configLoader.getDefaultOptions());
|
||||
Files.createFile(SshdPlugin.GetInstance().DefaultConfig);
|
||||
this.load();
|
||||
this.populate();
|
||||
this.save();
|
||||
@ -102,6 +101,10 @@ public class Config
|
||||
"# You can use the console/in-game command `/mkpasswd [hash] PASSWORD` to\n" +
|
||||
"# generate a password hash string then copy it for your passwords below.\n" +
|
||||
"# You can also use `/mkpasswd help` to see what algorithms are supported.");
|
||||
|
||||
this.configNode.getNode("Credentials").setComment("# Associate each username with a password hash (or the password if the PasswordType is set to PLAIN)");
|
||||
this.configNode.getNode("Credentials", "user1", "password").setValue("MySecretPassword");
|
||||
this.configNode.getNode("Credentials", "user2", "password").setValue("MyBestFriendsPassword");
|
||||
//this.configNode.getNode("").setValue("").setComment("");
|
||||
|
||||
|
||||
|
@ -1,422 +0,0 @@
|
||||
package org.slf4j.impl;
|
||||
|
||||
import com.ryanmichela.sshd.SshdPlugin;
|
||||
import org.slf4j.ILoggerFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.Marker;
|
||||
import org.slf4j.helpers.FormattingTuple;
|
||||
import org.slf4j.helpers.MessageFormatter;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
/**
|
||||
* Copyright 2013 Ryan Michela
|
||||
*/
|
||||
// figure out logging...
|
||||
public class PluginSlf4jFactory implements ILoggerFactory
|
||||
{
|
||||
@Override
|
||||
public Logger getLogger(String name)
|
||||
{
|
||||
return new PluginSlf4jAdapter(name);
|
||||
}
|
||||
|
||||
public class PluginSlf4jAdapter implements Logger
|
||||
{
|
||||
private String name;
|
||||
|
||||
private boolean isEnabled(Level level)
|
||||
{
|
||||
// ???
|
||||
return SshdPlugin.instance != null && SshdPlugin.instance.logger.isLoggable(level);
|
||||
}
|
||||
|
||||
private void log(Level level, String s, Object[] objects)
|
||||
{
|
||||
if (SshdPlugin.instance != null && isEnabled(level))
|
||||
{
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(s, objects);
|
||||
SshdPlugin.instance.getLogger().log(level, ft.getMessage(), ft.getThrowable());
|
||||
}
|
||||
}
|
||||
|
||||
private void log(Level level, String s, Throwable throwable)
|
||||
{
|
||||
if (SshdPlugin.instance != null && isEnabled(level))
|
||||
{
|
||||
SshdPlugin.instance.logger.log(level, s, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
public PluginSlf4jAdapter(String name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTraceEnabled()
|
||||
{
|
||||
return isEnabled(Level.FINEST);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String s)
|
||||
{
|
||||
trace(s, new Object[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String s, Object o)
|
||||
{
|
||||
trace(s, new Object[]{o});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String s, Object o, Object o1)
|
||||
{
|
||||
trace(s, new Object[]{o, o1});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String s, Object[] objects)
|
||||
{
|
||||
log(Level.FINEST, s, objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String s, Throwable throwable)
|
||||
{
|
||||
log(Level.FINEST, s, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTraceEnabled(Marker marker)
|
||||
{
|
||||
return isTraceEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Marker marker, String s)
|
||||
{
|
||||
trace(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Marker marker, String s, Object o)
|
||||
{
|
||||
trace(s, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Marker marker, String s, Object o, Object o1)
|
||||
{
|
||||
trace(s, o, o1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Marker marker, String s, Object[] objects)
|
||||
{
|
||||
trace(s, objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Marker marker, String s, Throwable throwable)
|
||||
{
|
||||
trace(s, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugEnabled()
|
||||
{
|
||||
return isEnabled(Level.FINE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String s)
|
||||
{
|
||||
debug(s, new Object[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String s, Object o)
|
||||
{
|
||||
debug(s, new Object[]{o});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String s, Object o, Object o1)
|
||||
{
|
||||
debug(s, new Object[]{o, o1});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String s, Object[] objects)
|
||||
{
|
||||
log(Level.FINE, s, objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String s, Throwable throwable)
|
||||
{
|
||||
log(Level.FINE, s, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugEnabled(Marker marker)
|
||||
{
|
||||
return isDebugEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Marker marker, String s)
|
||||
{
|
||||
debug(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Marker marker, String s, Object o)
|
||||
{
|
||||
debug(s, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Marker marker, String s, Object o, Object o1)
|
||||
{
|
||||
debug(s, o, o1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Marker marker, String s, Object[] objects)
|
||||
{
|
||||
debug(s, objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Marker marker, String s, Throwable throwable)
|
||||
{
|
||||
debug(s, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInfoEnabled()
|
||||
{
|
||||
return isEnabled(Level.INFO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String s)
|
||||
{
|
||||
info(s, new Object[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String s, Object o)
|
||||
{
|
||||
info(s, new Object[]{o});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String s, Object o, Object o1)
|
||||
{
|
||||
info(s, new Object[]{o, o1});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String s, Object[] objects)
|
||||
{
|
||||
log(Level.INFO, s, objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String s, Throwable throwable)
|
||||
{
|
||||
log(Level.INFO, s, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInfoEnabled(Marker marker)
|
||||
{
|
||||
return isInfoEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Marker marker, String s)
|
||||
{
|
||||
info(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Marker marker, String s, Object o)
|
||||
{
|
||||
info(s, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Marker marker, String s, Object o, Object o1)
|
||||
{
|
||||
info(s, o, o1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Marker marker, String s, Object[] objects)
|
||||
{
|
||||
info(s, objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Marker marker, String s, Throwable throwable)
|
||||
{
|
||||
info(s, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWarnEnabled()
|
||||
{
|
||||
return isEnabled(Level.WARNING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String s)
|
||||
{
|
||||
warn(s, new Object[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String s, Object o)
|
||||
{
|
||||
warn(s, new Object[]{o});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String s, Object o, Object o1)
|
||||
{
|
||||
warn(s, new Object[]{o, o1});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String s, Object[] objects)
|
||||
{
|
||||
log(Level.WARNING, s, objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String s, Throwable throwable)
|
||||
{
|
||||
log(Level.WARNING, s, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWarnEnabled(Marker marker)
|
||||
{
|
||||
return isWarnEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Marker marker, String s)
|
||||
{
|
||||
warn(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Marker marker, String s, Object o)
|
||||
{
|
||||
warn(s, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Marker marker, String s, Object o, Object o1)
|
||||
{
|
||||
warn(s, o, o1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Marker marker, String s, Object[] objects)
|
||||
{
|
||||
warn(s, objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Marker marker, String s, Throwable throwable)
|
||||
{
|
||||
warn(s, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isErrorEnabled()
|
||||
{
|
||||
return isEnabled(Level.SEVERE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String s)
|
||||
{
|
||||
error(s, new Object[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String s, Object o)
|
||||
{
|
||||
error(s, new Object[]{o});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String s, Object o, Object o1)
|
||||
{
|
||||
error(s, new Object[]{o, o1});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String s, Object[] objects)
|
||||
{
|
||||
log(Level.SEVERE, s, objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String s, Throwable throwable)
|
||||
{
|
||||
log(Level.SEVERE, s, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isErrorEnabled(Marker marker)
|
||||
{
|
||||
return isErrorEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Marker marker, String s)
|
||||
{
|
||||
error(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Marker marker, String s, Object o)
|
||||
{
|
||||
error(s, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Marker marker, String s, Object o, Object o1)
|
||||
{
|
||||
error(s, o, o1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Marker marker, String s, Object[] objects)
|
||||
{
|
||||
error(s, objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Marker marker, String s, Throwable throwable)
|
||||
{
|
||||
error(s, throwable);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2004-2011 QOS.ch
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
package org.slf4j.impl;
|
||||
|
||||
import org.slf4j.ILoggerFactory;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.spi.LoggerFactoryBinder;
|
||||
|
||||
/**
|
||||
* The binding of {@link LoggerFactory} class with an actual instance of
|
||||
* {@link ILoggerFactory} is performed using information returned by this class.
|
||||
*
|
||||
* @author Ceki Gülcü
|
||||
*/
|
||||
public class StaticLoggerBinder implements LoggerFactoryBinder {
|
||||
|
||||
/**
|
||||
* The unique instance of this class.
|
||||
*
|
||||
*/
|
||||
private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
|
||||
|
||||
/**
|
||||
* Return the singleton of this class.
|
||||
*
|
||||
* @return the StaticLoggerBinder singleton
|
||||
*/
|
||||
public static final StaticLoggerBinder getSingleton() {
|
||||
return SINGLETON;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Declare the version of the SLF4J API this implementation is compiled against.
|
||||
* The value of this field is usually modified with each release.
|
||||
*/
|
||||
// to avoid constant folding by the compiler, this field must *not* be final
|
||||
public static String REQUESTED_API_VERSION = "1.6.99"; // !final
|
||||
|
||||
|
||||
private static final String loggerFactoryClassStr = PluginSlf4jFactory.class.getName();
|
||||
|
||||
/** The ILoggerFactory instance returned by the {@link #getLoggerFactory} method
|
||||
* should always be the same object
|
||||
*/
|
||||
private final ILoggerFactory loggerFactory;
|
||||
|
||||
private StaticLoggerBinder() {
|
||||
// Note: JCL gets substituted at build time by an appropriate Ant task
|
||||
loggerFactory = new PluginSlf4jFactory();
|
||||
}
|
||||
|
||||
public ILoggerFactory getLoggerFactory() {
|
||||
return loggerFactory;
|
||||
}
|
||||
|
||||
public String getLoggerFactoryClassStr() {
|
||||
return loggerFactoryClassStr;
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
name: SSHD
|
||||
version: ${project.version}
|
||||
author: Ryan Michela, Haarolean, toxuin, Justin Crawford, Zachery Coleman
|
||||
main: com.ryanmichela.sshd.SshdPlugin
|
||||
load: STARTUP
|
||||
commands:
|
||||
mkpasswd:
|
||||
description: Make a SSHD password hash
|
||||
usage: /mkpasswd <hash|help> <password>
|
Loading…
Reference in New Issue
Block a user