diff --git a/pom.xml b/pom.xml index b126ae3..c3873fd 100644 --- a/pom.xml +++ b/pom.xml @@ -56,6 +56,8 @@ org.apache.sshd sshd-common 2.3.0 + compile + jar diff --git a/src/main/java/com/ryanmichela/sshd/ConfigPasswordAuthenticator.java b/src/main/java/com/ryanmichela/sshd/ConfigPasswordAuthenticator.java index 4f850c2..37202da 100644 --- a/src/main/java/com/ryanmichela/sshd/ConfigPasswordAuthenticator.java +++ b/src/main/java/com/ryanmichela/sshd/ConfigPasswordAuthenticator.java @@ -11,30 +11,38 @@ import java.util.Map; */ public class ConfigPasswordAuthenticator implements PasswordAuthenticator { - private Map failCounts = new HashMap(); + private Map FailCounts = new HashMap(); - @Override - public boolean authenticate(String username, String password, ServerSession serverSession) { - if (SshdPlugin.instance.getConfig().getString("credentials." + username).equals(password)) { - failCounts.put(username, 0); - return true; - } - SshdPlugin.instance.getLogger().info("Failed login for " + username + " using password authentication."); + @Override + public boolean authenticate(String username, String password, ServerSession ss) + { + if (SshdPlugin.instance.getConfig().getString("Credentials." + username).equals(password)) + { + FailCounts.put(username, 0); + return true; + } + SshdPlugin.instance.getLogger().info("Failed login for " + username + " using password authentication."); - try { - Thread.sleep(3000); - if (failCounts.containsKey(username)) { - failCounts.put(username, failCounts.get(username) + 1); - } else { - failCounts.put(username, 1); - } - if (failCounts.get(username) >= 3) { - failCounts.put(username, 0); - serverSession.close(true); - } - } catch (InterruptedException e) { - // do nothing - } - return false; - } + Integer tries = SshdPlugin.instance.getConfig().getInt("LoginRetries"); + + try + { + Thread.sleep(3000); + if (this.FailCounts.containsKey(username)) + this.FailCounts.put(username, this.FailCounts.get(username) + 1); + else + this.FailCounts.put(username, 1); + + if (this.FailCounts.get(username) >= tries) + { + this.FailCounts.put(username, 0); + ss.close(true); + } + } + catch (InterruptedException e) + { + // do nothing + } + return false; + } } diff --git a/src/main/java/com/ryanmichela/sshd/ConsoleShellFactory.java b/src/main/java/com/ryanmichela/sshd/ConsoleShellFactory.java index aab350e..de9900c 100644 --- a/src/main/java/com/ryanmichela/sshd/ConsoleShellFactory.java +++ b/src/main/java/com/ryanmichela/sshd/ConsoleShellFactory.java @@ -27,137 +27,140 @@ import java.util.logging.StreamHandler; public class ConsoleShellFactory implements ShellFactory { - static SSHDCommandSender sshdCommandSender = new SSHDCommandSender(); + public Command createShell(ChannelSession cs) { + return new ConsoleShell(); + } - public Command createShell(ChannelSession cs) { - return new ConsoleShell(); - } + public class ConsoleShell implements Command, Runnable { - public static class ConsoleShell implements Command, Runnable { + private InputStream in; + private OutputStream out; + private OutputStream err; + private ExitCallback callback; + private Environment environment; + private Thread thread; + private String Username; - private InputStream in; - private OutputStream out; - private OutputStream err; - private ExitCallback callback; - private Environment environment; - private Thread thread; + StreamHandlerAppender streamHandlerAppender; + public ConsoleReader ConsoleReader; + public SSHDCommandSender SshdCommandSender; - StreamHandlerAppender streamHandlerAppender; - public static ConsoleReader consoleReader; + public InputStream getIn() { + return in; + } - public InputStream getIn() { - return in; - } + public OutputStream getOut() { + return out; + } - public OutputStream getOut() { - return out; - } + public OutputStream getErr() { + return err; + } - public OutputStream getErr() { - return err; - } + public Environment getEnvironment() { + return environment; + } - public Environment getEnvironment() { - return environment; - } + public void setInputStream(InputStream in) { + this.in = in; + } - public void setInputStream(InputStream in) { - this.in = in; - } + public void setOutputStream(OutputStream out) { + this.out = out; + } - public void setOutputStream(OutputStream out) { - this.out = out; - } + public void setErrorStream(OutputStream err) { + this.err = err; + } - public void setErrorStream(OutputStream err) { - this.err = err; - } + public void setExitCallback(ExitCallback callback) { + this.callback = callback; + } - public void setExitCallback(ExitCallback callback) { - this.callback = callback; - } - - @Override + @Override public void start(ChannelSession cs, Environment env) throws IOException - { - try - { - consoleReader = new ConsoleReader(in, new FlushyOutputStream(out), new SshTerminal()); - consoleReader.setExpandEvents(true); - consoleReader.addCompleter(new ConsoleCommandCompleter()); + { + try + { + this.ConsoleReader = new ConsoleReader(in, new FlushyOutputStream(out), new SshTerminal()); + this.ConsoleReader.setExpandEvents(true); + this.ConsoleReader.addCompleter(new ConsoleCommandCompleter()); - StreamHandler streamHandler = new FlushyStreamHandler(out, new ConsoleLogFormatter(), consoleReader); - streamHandlerAppender = new StreamHandlerAppender(streamHandler); + StreamHandler streamHandler = new FlushyStreamHandler(out, new ConsoleLogFormatter(), this.ConsoleReader); + streamHandlerAppender = new StreamHandlerAppender(streamHandler); - ((Logger)LogManager.getRootLogger()).addAppender(streamHandlerAppender); + ((Logger)LogManager.getRootLogger()).addAppender(streamHandlerAppender); - environment = env; - thread = new Thread(this, "SSHD ConsoleShell " + env.getEnv().get(Environment.ENV_USER)); - thread.start(); - } - catch (Exception e) - { - throw new IOException("Error starting shell", e); - } - } + this.environment = env; + this.Username = env.getEnv().get(Environment.ENV_USER); + this.SshdCommandSender = new SSHDCommandSender(); + this.SshdCommandSender.console = this; + thread = new Thread(this, "SSHD ConsoleShell " + this.Username); + thread.start(); + } + catch (Exception e) + { + throw new IOException("Error starting shell", e); + } + } - @Override + @Override public void destroy(ChannelSession cs) { ((Logger)LogManager.getRootLogger()).removeAppender(streamHandlerAppender); } public void run() - { - try - { - if (!SshdPlugin.instance.getConfig().getString("mode").equals("RPC")) - printPreamble(consoleReader); - while (true) - { - String command = consoleReader.readLine("\r>", null); - if (command == null) - continue; - if (command.equals("exit") || command.equals("quit")) - break; - Bukkit.getScheduler().runTask( - SshdPlugin.instance, () -> - { - if (SshdPlugin.instance.getConfig().getString("mode").equals("RPC") && command.startsWith("rpc")) - { - // NO ECHO NO PREAMBLE AND SHIT - String cmd = command.substring("rpc".length() + 1, command.length()); - Bukkit.dispatchCommand(sshdCommandSender, cmd); - } - else - { - SshdPlugin.instance.getLogger().info("<" + environment.getEnv().get(Environment.ENV_USER) + "> " - + command); - Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command); - } - }); - } - } - catch (IOException e) - { - SshdPlugin.instance.getLogger().log(Level.SEVERE, "Error processing command from SSH", e); - } - finally - { - callback.onExit(0); - } - } + { + try + { + if (!SshdPlugin.instance.getConfig().getString("Mode").equals("RPC")) + printPreamble(this.ConsoleReader); + while (true) + { + String command = this.ConsoleReader.readLine("\r>", null); + if (command == null || command.trim().isEmpty()) + continue; + if (command.equals("exit") || command.equals("quit")) + break; - private void printPreamble(ConsoleReader consoleReader) throws IOException - { - consoleReader.println(" _____ _____ _ _ _____" + "\r"); - consoleReader.println(" / ____/ ____| | | | __ \\" + "\r"); - consoleReader.println("| (___| (___ | |__| | | | |" + "\r"); - consoleReader.println(" \\___ \\\\___ \\| __ | | | |" + "\r"); - consoleReader.println(" ____) |___) | | | | |__| |" + "\r"); - consoleReader.println("|_____/_____/|_| |_|_____/" + "\r"); - consoleReader.println("Connected to: " + Bukkit.getServer().getName() + "\r"); - consoleReader.println("- " + Bukkit.getServer().getMotd() + "\r"); - consoleReader.println("\r"); - consoleReader.println("Type 'exit' to exit the shell." + "\r"); - consoleReader.println("===============================================" + "\r"); - } + Bukkit.getScheduler().runTask( + SshdPlugin.instance, () -> + { + if (SshdPlugin.instance.getConfig().getString("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); + } + else + { + SshdPlugin.instance.getLogger().info("<" + this.Username + "> " + command); + Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command); + } + }); + } + } + catch (IOException e) + { + SshdPlugin.instance.getLogger().log(Level.SEVERE, "Error processing command from SSH", e); + } + finally + { + callback.onExit(0); + } + } + + private void printPreamble(ConsoleReader cr) throws IOException + { + cr.println(" _____ _____ _ _ _____" + "\r"); + cr.println(" / ____/ ____| | | | __ \\" + "\r"); + cr.println("| (___| (___ | |__| | | | |" + "\r"); + cr.println(" \\___ \\\\___ \\| __ | | | |" + "\r"); + cr.println(" ____) |___) | | | | |__| |" + "\r"); + cr.println("|_____/_____/|_| |_|_____/" + "\r"); + cr.println("Connected to: " + Bukkit.getServer().getName() + "\r"); + cr.println("- " + Bukkit.getServer().getMotd() + "\r"); + cr.println("\r"); + cr.println("Type 'exit' to exit the shell." + "\r"); + cr.println("===============================================" + "\r"); + } } } \ No newline at end of file diff --git a/src/main/java/com/ryanmichela/sshd/PublicKeyAuthenticator.java b/src/main/java/com/ryanmichela/sshd/PublicKeyAuthenticator.java index b9f4ee3..0a14696 100644 --- a/src/main/java/com/ryanmichela/sshd/PublicKeyAuthenticator.java +++ b/src/main/java/com/ryanmichela/sshd/PublicKeyAuthenticator.java @@ -8,6 +8,8 @@ import org.apache.sshd.server.session.ServerSession; import java.io.File; import java.util.List; +import java.util.HashMap; +import java.util.Map; import java.io.FileReader; import java.security.PublicKey; @@ -16,57 +18,54 @@ import java.security.PublicKey; */ public class PublicKeyAuthenticator implements PublickeyAuthenticator { + private File authorizedKeysDir; + private Map FailCounts = new HashMap(); - private File authorizedKeysDir; - - public PublicKeyAuthenticator(File authorizedKeysDir) { this.authorizedKeysDir = authorizedKeysDir; } + public PublicKeyAuthenticator(File authorizedKeysDir) { this.authorizedKeysDir = authorizedKeysDir; } @Override public boolean authenticate(String username, PublicKey key, ServerSession session) { byte[] keyBytes = key.getEncoded(); - File keyFile = new File(authorizedKeysDir, username); + File keyFile = new File(authorizedKeysDir, username); + Integer tries = SshdPlugin.instance.getConfig().getInt("LoginRetries"); if (keyFile.exists()) { try { + // Read all the public key entries List pklist = AuthorizedKeyEntry.readAuthorizedKeys(keyFile.toPath()); - + // Get an authenticator PublickeyAuthenticator auth = PublickeyAuthenticator.fromAuthorizedEntries(username, session, pklist, PublicKeyEntryResolver.IGNORING); - boolean accepted = auth.authenticate(username, key, session); - - if (accepted) - { + // Validate that the logging in user has the same valid SSH key + if (auth.authenticate(username, key, session)) + { SshdPlugin.instance.getLogger().info( username + " successfully authenticated via SSH session using key file " + keyFile.getAbsolutePath()); + FailCounts.put(username, 0); + return true; } else { SshdPlugin.instance.getLogger().info( username + " failed authentication via SSH session using key file " + keyFile.getAbsolutePath()); } - return accepted; - /* - FileReader fr = new FileReader(keyFile); - PemDecoder pd = new PemDecoder(fr); - PublicKey k = pd.getPemBytes(); - pd.close(); - - if (k != null) - { - if (ArrayUtils.isEquals(key.getEncoded(), k.getEncoded())) - { - return true; - } - } + // If the user fails with several SSH keys, then terminate the connection. + if (this.FailCounts.containsKey(username)) + this.FailCounts.put(username, this.FailCounts.get(username) + 1); else + this.FailCounts.put(username, 1); + + if (this.FailCounts.get(username) >= tries) { - SshdPlugin.instance.getLogger().severe("Failed to parse PEM file. " + keyFile.getAbsolutePath()); - } - */ + this.FailCounts.put(username, 0); + session.close(true); + } + + return false; } catch (Exception e) { diff --git a/src/main/java/com/ryanmichela/sshd/SshdPlugin.java b/src/main/java/com/ryanmichela/sshd/SshdPlugin.java index 79d84e4..01e48c2 100644 --- a/src/main/java/com/ryanmichela/sshd/SshdPlugin.java +++ b/src/main/java/com/ryanmichela/sshd/SshdPlugin.java @@ -44,8 +44,8 @@ class SshdPlugin extends JavaPlugin instance = this; sshd = SshServer.setUpDefaultServer(); - sshd.setPort(getConfig().getInt("port", 22)); - String host = getConfig().getString("listenAddress", "all"); + sshd.setPort(getConfig().getInt("Port", 1025)); + String host = getConfig().getString("ListenAddress", "all"); sshd.setHost(host.equals("all") ? null : host); File hostKey = new File(getDataFolder(), "hostkey"); @@ -56,7 +56,7 @@ class SshdPlugin extends JavaPlugin sshd.setPasswordAuthenticator(new ConfigPasswordAuthenticator()); sshd.setPublickeyAuthenticator(new PublicKeyAuthenticator(authorizedKeys)); - if (getConfig().getBoolean("enableSFTP")) + if (getConfig().getBoolean("EnableSFTP")) { sshd.setSubsystemFactories(Collections.singletonList(new SftpSubsystemFactory())); sshd.setFileSystemFactory( diff --git a/src/main/java/com/ryanmichela/sshd/implementations/SSHDCommandSender.java b/src/main/java/com/ryanmichela/sshd/implementations/SSHDCommandSender.java index 5442e00..30b7baf 100644 --- a/src/main/java/com/ryanmichela/sshd/implementations/SSHDCommandSender.java +++ b/src/main/java/com/ryanmichela/sshd/implementations/SSHDCommandSender.java @@ -24,108 +24,116 @@ import java.util.logging.Level; public class SSHDCommandSender implements ConsoleCommandSender, CommandSender { - private final PermissibleBase perm = new PermissibleBase(this); - private final SSHDConversationTracker conversationTracker = new SSHDConversationTracker(); + private final PermissibleBase perm = new PermissibleBase(this); + private final SSHDConversationTracker conversationTracker = new SSHDConversationTracker(); + // Set by the upstream allocating function + public ConsoleShellFactory.ConsoleShell console; - public void sendMessage(String message) { - this.sendRawMessage(message); - } + public void sendMessage(String message) { + this.sendRawMessage(message); + } - public void sendRawMessage(String message) { - if(ConsoleShellFactory.ConsoleShell.consoleReader == null) return; - try { - ConsoleShellFactory.ConsoleShell.consoleReader.println(ChatColor.stripColor(message)); - } catch (IOException e) { - SshdPlugin.instance.getLogger().log(Level.SEVERE, "Error sending message to SSHDCommandSender", e); - } - } + public void sendRawMessage(String message) + { + // What the fuck does this code even do? Are we sending to one client or all of them? + if (this.console.ConsoleReader == null) + return; + try + { + this.console.ConsoleReader.println(ChatColor.stripColor(message)); + } + catch (IOException e) + { + SshdPlugin.instance.getLogger().log(Level.SEVERE, "Error sending message to SSHDCommandSender", e); + } + } - public void sendMessage(String[] messages) { - Arrays.asList(messages).forEach(this::sendMessage); - } + public void sendMessage(String[] messages) { + Arrays.asList(messages).forEach(this::sendMessage); + } - public String getName() { - return "Console"; - } + public String getName() { + return "SSHD Console"; + } - public boolean isOp() { - return true; - } + public boolean isOp() { + return true; + } - public void setOp(boolean value) { - throw new UnsupportedOperationException("Cannot change operator status of server console"); - } + 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 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) { + this.conversationTracker.abandonConversation(conversation, new ConversationAbandonedEvent(conversation, new ManuallyAbandonedConversationCanceller())); + } - public void abandonConversation(Conversation conversation, ConversationAbandonedEvent details) { - this.conversationTracker.abandonConversation(conversation, details); - } + public void abandonConversation(Conversation conversation, ConversationAbandonedEvent details) { + this.conversationTracker.abandonConversation(conversation, details); + } - public void acceptConversationInput(String input) { - this.conversationTracker.acceptConversationInput(input); - } + public void acceptConversationInput(String input) { + this.conversationTracker.acceptConversationInput(input); + } - public boolean isConversing() { - return this.conversationTracker.isConversing(); - } + public boolean isConversing() { + return this.conversationTracker.isConversing(); + } - public boolean isPermissionSet(String name) { - return this.perm.isPermissionSet(name); - } + public boolean isPermissionSet(String name) { + return this.perm.isPermissionSet(name); + } - public boolean isPermissionSet(Permission perm) { - return this.perm.isPermissionSet(perm); - } + public boolean isPermissionSet(Permission perm) { + return this.perm.isPermissionSet(perm); + } - public boolean hasPermission(String name) { - return this.perm.hasPermission(name); - } + public boolean hasPermission(String name) { + return this.perm.hasPermission(name); + } - public boolean hasPermission(Permission perm) { - return this.perm.hasPermission(perm); - } + 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, 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) { + 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, 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 PermissionAttachment addAttachment(Plugin plugin, int ticks) { + return this.perm.addAttachment(plugin, ticks); + } - public void removeAttachment(PermissionAttachment attachment) { - this.perm.removeAttachment(attachment); - } + public void removeAttachment(PermissionAttachment attachment) { + this.perm.removeAttachment(attachment); + } - public void recalculatePermissions() { - this.perm.recalculatePermissions(); - } + public void recalculatePermissions() { + this.perm.recalculatePermissions(); + } - public Set getEffectivePermissions() { - return this.perm.getEffectivePermissions(); - } + public Set getEffectivePermissions() { + return this.perm.getEffectivePermissions(); + } - public boolean isPlayer() { - return false; - } + public boolean isPlayer() { + return false; + } - public Server getServer() { - return Bukkit.getServer(); - } + public Server getServer() { + return Bukkit.getServer(); + } } diff --git a/src/main/java/com/ryanmichela/sshd/implementations/SSHDConversationTracker.java b/src/main/java/com/ryanmichela/sshd/implementations/SSHDConversationTracker.java index 947ef2d..5b9bb4f 100644 --- a/src/main/java/com/ryanmichela/sshd/implementations/SSHDConversationTracker.java +++ b/src/main/java/com/ryanmichela/sshd/implementations/SSHDConversationTracker.java @@ -9,70 +9,70 @@ import java.util.LinkedList; import java.util.logging.Level; public class SSHDConversationTracker { - private LinkedList conversationQueue = new LinkedList<>(); + private LinkedList 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; - } - } + 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; - } + return true; + } - synchronized void abandonConversation(Conversation conversation, ConversationAbandonedEvent details) { - if (!this.conversationQueue.isEmpty()) { - if (this.conversationQueue.getFirst() == conversation) { - conversation.abandon(details); - } + 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.contains(conversation)) { + this.conversationQueue.remove(conversation); + } - if (!this.conversationQueue.isEmpty()) { - this.conversationQueue.getFirst().outputNextPrompt(); - } - } + if (!this.conversationQueue.isEmpty()) { + this.conversationQueue.getFirst().outputNextPrompt(); + } + } - } + } - public synchronized void abandonAllConversations() { - LinkedList oldQueue = this.conversationQueue; - this.conversationQueue = new LinkedList<>(); + public synchronized void abandonAllConversations() { + LinkedList 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); - } - } + 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(); + 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); - } - } + 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(); - } + synchronized boolean isConversing() { + return !this.conversationQueue.isEmpty(); + } - public synchronized boolean isConversingModaly() { - return this.isConversing() && this.conversationQueue.getFirst().isModal(); - } + public synchronized boolean isConversingModaly() { + return this.isConversing() && this.conversationQueue.getFirst().isModal(); + } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 5427555..31e049c 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,22 +1,35 @@ # The IP addresses(s) the SSH server will listen on. Use a comma separated list for multiple addresses. # Leave as "all" for all addresses. -listenAddress: all -# The port the SSH server will listen on. -port: 22 +ListenAddress: all +# The port the SSH server will listen on. Note that anything above 1024 will require you to run +# the whole minecraft server with elevated privileges, this is not recommended and you should +# use iptables to route packets from a lower port. +Port: 1025 # Operational mode. Don't touch if you don't know what you're doing. Can be either DEFAULT or RPC -mode: DEFAULT +Mode: DEFAULT # Enable built-in SFTP server or not. You'll be able to connect and upload/download files via SFTP protocol. # Might be useful for testing purposes as well , i. e. docker containers. -enableSFTP: true +EnableSFTP: true + +# Number of times a person can fail to use an SSH key or enter a password +# before it terminates the connection. +LoginRetries: 3 # By default, only public key authentication is enabled. This is the most secure mode. -# To authorize a user to log in with public key authentication, install their public -# PEM certificate in the authorized_users directory. Name the key file with user's user -# name (no file extension). +# To authorize a user to login with their public key, install their key using the +# OpenSSH authorized_keys file format in the authorized_users directory. Name the key +# file with the user's username and no extension. Note: If you want to let a user have +# many keys, you can append the keys to their file in authorized_users. # For less secure username and password based authentication, complete the sections below. -credentials: + +# Type of hashing to use for the passwords below. +# Options are: PLAIN (insecure), bcrypt, pbkdf, sha256 +PasswordType: bcrypt + +# Associate each username with a password hash (or the password if the PasswordType is set to PLAIN) +Credentials: # user1: password1 # user2: password2