Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e45f7ebf4 | ||
|
|
0e05bb61bc | ||
|
|
0635ea7a35 |
4
pom.xml
4
pom.xml
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>com.ryanmichela</groupId>
|
<groupId>com.ryanmichela</groupId>
|
||||||
<artifactId>sshd</artifactId>
|
<artifactId>sshd</artifactId>
|
||||||
<version>1.3.4.2</version>
|
<version>1.3.5</version>
|
||||||
<url>https://github.com/Justasic/Bukkit-SSHD/</url>
|
<url>https://github.com/Justasic/Bukkit-SSHD/</url>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
@@ -56,6 +56,8 @@
|
|||||||
<groupId>org.apache.sshd</groupId>
|
<groupId>org.apache.sshd</groupId>
|
||||||
<artifactId>sshd-common</artifactId>
|
<artifactId>sshd-common</artifactId>
|
||||||
<version>2.3.0</version>
|
<version>2.3.0</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
<type>jar</type>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
@@ -11,30 +11,38 @@ import java.util.Map;
|
|||||||
*/
|
*/
|
||||||
public class ConfigPasswordAuthenticator implements PasswordAuthenticator {
|
public class ConfigPasswordAuthenticator implements PasswordAuthenticator {
|
||||||
|
|
||||||
private Map<String, Integer> failCounts = new HashMap<String, Integer>();
|
private Map<String, Integer> FailCounts = new HashMap<String, Integer>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean authenticate(String username, String password, ServerSession serverSession) {
|
public boolean authenticate(String username, String password, ServerSession ss)
|
||||||
if (SshdPlugin.instance.getConfig().getString("credentials." + username).equals(password)) {
|
{
|
||||||
failCounts.put(username, 0);
|
if (SshdPlugin.instance.getConfig().getString("Credentials." + username).equals(password))
|
||||||
return true;
|
{
|
||||||
}
|
FailCounts.put(username, 0);
|
||||||
SshdPlugin.instance.getLogger().info("Failed login for " + username + " using password authentication.");
|
return true;
|
||||||
|
}
|
||||||
|
SshdPlugin.instance.getLogger().info("Failed login for " + username + " using password authentication.");
|
||||||
|
|
||||||
try {
|
Integer tries = SshdPlugin.instance.getConfig().getInt("LoginRetries");
|
||||||
Thread.sleep(3000);
|
|
||||||
if (failCounts.containsKey(username)) {
|
try
|
||||||
failCounts.put(username, failCounts.get(username) + 1);
|
{
|
||||||
} else {
|
Thread.sleep(3000);
|
||||||
failCounts.put(username, 1);
|
if (this.FailCounts.containsKey(username))
|
||||||
}
|
this.FailCounts.put(username, this.FailCounts.get(username) + 1);
|
||||||
if (failCounts.get(username) >= 3) {
|
else
|
||||||
failCounts.put(username, 0);
|
this.FailCounts.put(username, 1);
|
||||||
serverSession.close(true);
|
|
||||||
}
|
if (this.FailCounts.get(username) >= tries)
|
||||||
} catch (InterruptedException e) {
|
{
|
||||||
// do nothing
|
this.FailCounts.put(username, 0);
|
||||||
}
|
ss.close(true);
|
||||||
return false;
|
}
|
||||||
}
|
}
|
||||||
|
catch (InterruptedException e)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,11 +18,55 @@ import java.util.logging.LogRecord;
|
|||||||
public class ConsoleLogFormatter extends Formatter {
|
public class ConsoleLogFormatter extends Formatter {
|
||||||
|
|
||||||
private SimpleDateFormat dateFormat;
|
private SimpleDateFormat dateFormat;
|
||||||
|
private static final Map<ChatColor, String> replacements = new EnumMap<ChatColor, String>(ChatColor.class);
|
||||||
|
|
||||||
public ConsoleLogFormatter() {
|
public ConsoleLogFormatter() {
|
||||||
this.dateFormat = new SimpleDateFormat("HH:mm:ss");
|
this.dateFormat = new SimpleDateFormat("HH:mm:ss");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String ColorizeString(String str)
|
||||||
|
{
|
||||||
|
// ORIGINAL CODE FROM org.bukkit.craftbukkit.command.ColouredConsoleSender
|
||||||
|
|
||||||
|
replacements.put(ChatColor.BLACK, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.BLACK).boldOff().toString());
|
||||||
|
replacements.put(ChatColor.DARK_BLUE, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.BLUE).boldOff().toString());
|
||||||
|
replacements.put(ChatColor.DARK_GREEN, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.GREEN).boldOff().toString());
|
||||||
|
replacements.put(ChatColor.DARK_AQUA, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.CYAN).boldOff().toString());
|
||||||
|
replacements.put(ChatColor.DARK_RED, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.RED).boldOff().toString());
|
||||||
|
replacements.put(ChatColor.DARK_PURPLE, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.MAGENTA).boldOff().toString());
|
||||||
|
replacements.put(ChatColor.GOLD, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.YELLOW).boldOff().toString());
|
||||||
|
replacements.put(ChatColor.GRAY, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.WHITE).boldOff().toString());
|
||||||
|
replacements.put(ChatColor.DARK_GRAY, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.BLACK).bold().toString());
|
||||||
|
replacements.put(ChatColor.BLUE, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.BLUE).bold().toString());
|
||||||
|
replacements.put(ChatColor.GREEN, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.GREEN).bold().toString());
|
||||||
|
replacements.put(ChatColor.AQUA, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.CYAN).bold().toString());
|
||||||
|
replacements.put(ChatColor.RED, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.RED).bold().toString());
|
||||||
|
replacements.put(ChatColor.LIGHT_PURPLE, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.MAGENTA).bold().toString());
|
||||||
|
replacements.put(ChatColor.YELLOW, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.YELLOW).bold().toString());
|
||||||
|
replacements.put(ChatColor.WHITE, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.WHITE).bold().toString());
|
||||||
|
replacements.put(ChatColor.MAGIC, Ansi.ansi().a(Ansi.Attribute.BLINK_SLOW).toString());
|
||||||
|
replacements.put(ChatColor.BOLD, Ansi.ansi().a(Ansi.Attribute.UNDERLINE_DOUBLE).toString());
|
||||||
|
replacements.put(ChatColor.STRIKETHROUGH, Ansi.ansi().a(Ansi.Attribute.STRIKETHROUGH_ON).toString());
|
||||||
|
replacements.put(ChatColor.UNDERLINE, Ansi.ansi().a(Ansi.Attribute.UNDERLINE).toString());
|
||||||
|
replacements.put(ChatColor.ITALIC, Ansi.ansi().a(Ansi.Attribute.ITALIC).toString());
|
||||||
|
replacements.put(ChatColor.RESET, Ansi.ansi().a(Ansi.Attribute.RESET).toString());
|
||||||
|
|
||||||
|
String result = str;
|
||||||
|
for (ChatColor color : ChatColor.values())
|
||||||
|
{
|
||||||
|
if (replacements.containsKey(color))
|
||||||
|
{
|
||||||
|
result = result.replaceAll("(?i)" + color.toString(), replacements.get(color));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = result.replaceAll("(?i)" + color.toString(), "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result += Ansi.ansi().reset().toString();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public String format(LogRecord logrecord) {
|
public String format(LogRecord logrecord) {
|
||||||
try {
|
try {
|
||||||
Class.forName("org.bukkit.craftbukkit.command.ColouredConsoleSender");
|
Class.forName("org.bukkit.craftbukkit.command.ColouredConsoleSender");
|
||||||
@@ -50,52 +94,10 @@ public class ConsoleLogFormatter extends Formatter {
|
|||||||
return stringbuilder.toString();
|
return stringbuilder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void colorize(LogRecord logrecord) {
|
private void colorize(LogRecord logrecord)
|
||||||
// ORIGINAL CODE FROM org.bukkit.craftbukkit.command.ColouredConsoleSender
|
{
|
||||||
final Map<ChatColor, String> replacements = new EnumMap<>(ChatColor.class);
|
String result = ColorizeString(logrecord.getMessage());
|
||||||
|
logrecord.setMessage(result);
|
||||||
replacements
|
|
||||||
.put(ChatColor.BLACK, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.BLACK).boldOff().toString());
|
|
||||||
replacements
|
|
||||||
.put(ChatColor.DARK_BLUE, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.BLUE).boldOff().toString());
|
|
||||||
replacements.put(ChatColor.DARK_GREEN,
|
|
||||||
Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.GREEN).boldOff().toString());
|
|
||||||
replacements
|
|
||||||
.put(ChatColor.DARK_AQUA, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.CYAN).boldOff().toString());
|
|
||||||
replacements
|
|
||||||
.put(ChatColor.DARK_RED, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.RED).boldOff().toString());
|
|
||||||
replacements.put(ChatColor.DARK_PURPLE,
|
|
||||||
Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.MAGENTA).boldOff().toString());
|
|
||||||
replacements
|
|
||||||
.put(ChatColor.GOLD, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.YELLOW).boldOff().toString());
|
|
||||||
replacements.put(ChatColor.GRAY, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.WHITE).boldOff().toString());
|
|
||||||
replacements
|
|
||||||
.put(ChatColor.DARK_GRAY, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.BLACK).bold().toString());
|
|
||||||
replacements.put(ChatColor.BLUE, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.BLUE).bold().toString());
|
|
||||||
replacements.put(ChatColor.GREEN, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.GREEN).bold().toString());
|
|
||||||
replacements.put(ChatColor.AQUA, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.CYAN).bold().toString());
|
|
||||||
replacements.put(ChatColor.RED, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.RED).bold().toString());
|
|
||||||
replacements.put(ChatColor.LIGHT_PURPLE,
|
|
||||||
Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.MAGENTA).bold().toString());
|
|
||||||
replacements.put(ChatColor.YELLOW, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.YELLOW).bold().toString());
|
|
||||||
replacements.put(ChatColor.WHITE, Ansi.ansi().a(Ansi.Attribute.RESET).fg(Ansi.Color.WHITE).bold().toString());
|
|
||||||
replacements.put(ChatColor.MAGIC, Ansi.ansi().a(Ansi.Attribute.BLINK_SLOW).toString());
|
|
||||||
replacements.put(ChatColor.BOLD, Ansi.ansi().a(Ansi.Attribute.UNDERLINE_DOUBLE).toString());
|
|
||||||
replacements.put(ChatColor.STRIKETHROUGH, Ansi.ansi().a(Ansi.Attribute.STRIKETHROUGH_ON).toString());
|
|
||||||
replacements.put(ChatColor.UNDERLINE, Ansi.ansi().a(Ansi.Attribute.UNDERLINE).toString());
|
|
||||||
replacements.put(ChatColor.ITALIC, Ansi.ansi().a(Ansi.Attribute.ITALIC).toString());
|
|
||||||
replacements.put(ChatColor.RESET, Ansi.ansi().a(Ansi.Attribute.RESET).toString());
|
|
||||||
|
|
||||||
String result = logrecord.getMessage();
|
|
||||||
for (ChatColor color : ChatColor.values()) {
|
|
||||||
if (replacements.containsKey(color)) {
|
|
||||||
result = result.replaceAll("(?i)" + color.toString(), replacements.get(color));
|
|
||||||
} else {
|
|
||||||
result = result.replaceAll("(?i)" + color.toString(), "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
result += Ansi.ansi().reset().toString();
|
|
||||||
logrecord.setMessage(result);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import com.ryanmichela.sshd.SshTerminal;
|
|||||||
import com.ryanmichela.sshd.SshdPlugin;
|
import com.ryanmichela.sshd.SshdPlugin;
|
||||||
import com.ryanmichela.sshd.StreamHandlerAppender;
|
import com.ryanmichela.sshd.StreamHandlerAppender;
|
||||||
import com.ryanmichela.sshd.implementations.SSHDCommandSender;
|
import com.ryanmichela.sshd.implementations.SSHDCommandSender;
|
||||||
|
import com.ryanmichela.sshd.ConsoleLogFormatter;
|
||||||
import jline.console.ConsoleReader;
|
import jline.console.ConsoleReader;
|
||||||
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;
|
||||||
@@ -22,142 +23,160 @@ import org.bukkit.Bukkit;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.net.InetAddress;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.StreamHandler;
|
import java.util.logging.StreamHandler;
|
||||||
|
|
||||||
public class ConsoleShellFactory implements ShellFactory {
|
public class ConsoleShellFactory implements ShellFactory {
|
||||||
|
|
||||||
static SSHDCommandSender sshdCommandSender = new SSHDCommandSender();
|
public Command createShell(ChannelSession cs) {
|
||||||
|
return new ConsoleShell();
|
||||||
|
}
|
||||||
|
|
||||||
public Command createShell(ChannelSession cs) {
|
public class ConsoleShell implements Command, Runnable {
|
||||||
return new ConsoleShell();
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
StreamHandlerAppender streamHandlerAppender;
|
||||||
private OutputStream out;
|
public ConsoleReader ConsoleReader;
|
||||||
private OutputStream err;
|
public SSHDCommandSender SshdCommandSender;
|
||||||
private ExitCallback callback;
|
|
||||||
private Environment environment;
|
|
||||||
private Thread thread;
|
|
||||||
|
|
||||||
StreamHandlerAppender streamHandlerAppender;
|
public InputStream getIn() {
|
||||||
public static ConsoleReader consoleReader;
|
return in;
|
||||||
|
}
|
||||||
|
|
||||||
public InputStream getIn() {
|
public OutputStream getOut() {
|
||||||
return in;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OutputStream getOut() {
|
public OutputStream getErr() {
|
||||||
return out;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
public OutputStream getErr() {
|
public Environment getEnvironment() {
|
||||||
return err;
|
return environment;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Environment getEnvironment() {
|
public void setInputStream(InputStream in) {
|
||||||
return environment;
|
this.in = in;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setInputStream(InputStream in) {
|
public void setOutputStream(OutputStream out) {
|
||||||
this.in = in;
|
this.out = out;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOutputStream(OutputStream out) {
|
public void setErrorStream(OutputStream err) {
|
||||||
this.out = out;
|
this.err = err;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setErrorStream(OutputStream err) {
|
public void setExitCallback(ExitCallback callback) {
|
||||||
this.err = err;
|
this.callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setExitCallback(ExitCallback callback) {
|
@Override
|
||||||
this.callback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void start(ChannelSession cs, Environment env) throws IOException
|
public void start(ChannelSession cs, Environment env) throws IOException
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
consoleReader = new ConsoleReader(in, new FlushyOutputStream(out), new SshTerminal());
|
this.ConsoleReader = new ConsoleReader(in, new FlushyOutputStream(out), new SshTerminal());
|
||||||
consoleReader.setExpandEvents(true);
|
this.ConsoleReader.setExpandEvents(true);
|
||||||
consoleReader.addCompleter(new ConsoleCommandCompleter());
|
this.ConsoleReader.addCompleter(new ConsoleCommandCompleter());
|
||||||
|
|
||||||
StreamHandler streamHandler = new FlushyStreamHandler(out, new ConsoleLogFormatter(), consoleReader);
|
StreamHandler streamHandler = new FlushyStreamHandler(out, new ConsoleLogFormatter(), this.ConsoleReader);
|
||||||
streamHandlerAppender = new StreamHandlerAppender(streamHandler);
|
streamHandlerAppender = new StreamHandlerAppender(streamHandler);
|
||||||
|
|
||||||
((Logger)LogManager.getRootLogger()).addAppender(streamHandlerAppender);
|
((Logger)LogManager.getRootLogger()).addAppender(streamHandlerAppender);
|
||||||
|
|
||||||
environment = env;
|
this.environment = env;
|
||||||
thread = new Thread(this, "SSHD ConsoleShell " + env.getEnv().get(Environment.ENV_USER));
|
this.Username = env.getEnv().get(Environment.ENV_USER);
|
||||||
thread.start();
|
this.SshdCommandSender = new SSHDCommandSender();
|
||||||
}
|
this.SshdCommandSender.console = this;
|
||||||
catch (Exception e)
|
thread = new Thread(this, "SSHD ConsoleShell " + this.Username);
|
||||||
{
|
thread.start();
|
||||||
throw new IOException("Error starting shell", e);
|
}
|
||||||
}
|
catch (Exception e)
|
||||||
}
|
{
|
||||||
|
throw new IOException("Error starting shell", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroy(ChannelSession cs) { ((Logger)LogManager.getRootLogger()).removeAppender(streamHandlerAppender); }
|
public void destroy(ChannelSession cs) { ((Logger)LogManager.getRootLogger()).removeAppender(streamHandlerAppender); }
|
||||||
|
|
||||||
public void run()
|
public void run()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!SshdPlugin.instance.getConfig().getString("mode").equals("RPC"))
|
if (!SshdPlugin.instance.getConfig().getString("Mode").equals("RPC"))
|
||||||
printPreamble(consoleReader);
|
printPreamble(this.ConsoleReader);
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
String command = consoleReader.readLine("\r>", null);
|
String command = this.ConsoleReader.readLine("\r>", null);
|
||||||
if (command == null)
|
// The user sent CTRL+D to close the shell, terminate the session.
|
||||||
continue;
|
if (command == null)
|
||||||
if (command.equals("exit") || command.equals("quit"))
|
break;
|
||||||
break;
|
// Skip someone spamming enter
|
||||||
Bukkit.getScheduler().runTask(
|
if (command.trim().isEmpty())
|
||||||
SshdPlugin.instance, () ->
|
continue;
|
||||||
{
|
// User wants to exit
|
||||||
if (SshdPlugin.instance.getConfig().getString("mode").equals("RPC") && command.startsWith("rpc"))
|
if (command.equals("exit") || command.equals("quit"))
|
||||||
{
|
break;
|
||||||
// NO ECHO NO PREAMBLE AND SHIT
|
// Clear the text from the screen (on supported terminals)
|
||||||
String cmd = command.substring("rpc".length() + 1, command.length());
|
if (command.equals("cls"))
|
||||||
Bukkit.dispatchCommand(sshdCommandSender, cmd);
|
{
|
||||||
}
|
this.ConsoleReader.clearScreen();
|
||||||
else
|
continue;
|
||||||
{
|
}
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void printPreamble(ConsoleReader consoleReader) throws IOException
|
Bukkit.getScheduler().runTask(
|
||||||
{
|
SshdPlugin.instance, () ->
|
||||||
consoleReader.println(" _____ _____ _ _ _____" + "\r");
|
{
|
||||||
consoleReader.println(" / ____/ ____| | | | __ \\" + "\r");
|
if (SshdPlugin.instance.getConfig().getString("Mode").equals("RPC") && command.startsWith("rpc"))
|
||||||
consoleReader.println("| (___| (___ | |__| | | | |" + "\r");
|
{
|
||||||
consoleReader.println(" \\___ \\\\___ \\| __ | | | |" + "\r");
|
// NO ECHO NO PREAMBLE AND SHIT
|
||||||
consoleReader.println(" ____) |___) | | | | |__| |" + "\r");
|
String cmd = command.substring("rpc".length() + 1, command.length());
|
||||||
consoleReader.println("|_____/_____/|_| |_|_____/" + "\r");
|
Bukkit.dispatchCommand(this.SshdCommandSender, cmd);
|
||||||
consoleReader.println("Connected to: " + Bukkit.getServer().getName() + "\r");
|
}
|
||||||
consoleReader.println("- " + Bukkit.getServer().getMotd() + "\r");
|
else
|
||||||
consoleReader.println("\r");
|
{
|
||||||
consoleReader.println("Type 'exit' to exit the shell." + "\r");
|
SshdPlugin.instance.getLogger().info("<" + this.Username + "> " + command);
|
||||||
consoleReader.println("===============================================" + "\r");
|
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
SshdPlugin.instance.getLogger().log(Level.SEVERE, "Error processing command from SSH", e);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
SshdPlugin.instance.getLogger().log(Level.INFO, this.Username + " disconnected from SSH.");
|
||||||
|
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");
|
||||||
|
// 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()) + "\r");
|
||||||
|
cr.println("\r");
|
||||||
|
cr.println("Type 'exit' to exit the shell." + "\r");
|
||||||
|
cr.println("===============================================" + "\r");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,6 +8,8 @@ import org.apache.sshd.server.session.ServerSession;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.security.PublicKey;
|
import java.security.PublicKey;
|
||||||
|
|
||||||
@@ -16,57 +18,52 @@ import java.security.PublicKey;
|
|||||||
*/
|
*/
|
||||||
public class PublicKeyAuthenticator implements PublickeyAuthenticator
|
public class PublicKeyAuthenticator implements PublickeyAuthenticator
|
||||||
{
|
{
|
||||||
|
private File authorizedKeysDir;
|
||||||
|
private Map<String, Integer> FailCounts = new HashMap<String, Integer>();
|
||||||
|
|
||||||
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)
|
@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");
|
||||||
|
|
||||||
if (keyFile.exists())
|
if (keyFile.exists())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// Read all the public key entries
|
||||||
List<AuthorizedKeyEntry> pklist = AuthorizedKeyEntry.readAuthorizedKeys(keyFile.toPath());
|
List<AuthorizedKeyEntry> pklist = AuthorizedKeyEntry.readAuthorizedKeys(keyFile.toPath());
|
||||||
|
// Get an authenticator
|
||||||
PublickeyAuthenticator auth = PublickeyAuthenticator.fromAuthorizedEntries(username, session, pklist,
|
PublickeyAuthenticator auth = PublickeyAuthenticator.fromAuthorizedEntries(username, session, pklist,
|
||||||
PublicKeyEntryResolver.IGNORING);
|
PublicKeyEntryResolver.IGNORING);
|
||||||
|
|
||||||
boolean accepted = auth.authenticate(username, key, session);
|
// Validate that the logging in user has the same valid SSH key
|
||||||
|
if (auth.authenticate(username, key, session))
|
||||||
if (accepted)
|
{
|
||||||
{
|
FailCounts.put(username, 0);
|
||||||
SshdPlugin.instance.getLogger().info(
|
return true;
|
||||||
username + " successfully authenticated via SSH session using key file " + keyFile.getAbsolutePath());
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SshdPlugin.instance.getLogger().info(
|
SshdPlugin.instance.getLogger().info(
|
||||||
username + " failed authentication via SSH session using key file " + keyFile.getAbsolutePath());
|
username + " failed authentication via SSH session using key file " + keyFile.getAbsolutePath());
|
||||||
}
|
}
|
||||||
return accepted;
|
|
||||||
/*
|
|
||||||
|
|
||||||
FileReader fr = new FileReader(keyFile);
|
// If the user fails with several SSH keys, then terminate the connection.
|
||||||
PemDecoder pd = new PemDecoder(fr);
|
if (this.FailCounts.containsKey(username))
|
||||||
PublicKey k = pd.getPemBytes();
|
this.FailCounts.put(username, this.FailCounts.get(username) + 1);
|
||||||
pd.close();
|
|
||||||
|
|
||||||
if (k != null)
|
|
||||||
{
|
|
||||||
if (ArrayUtils.isEquals(key.getEncoded(), k.getEncoded()))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
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)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ import jline.TerminalSupport;
|
|||||||
*/
|
*/
|
||||||
public class SshTerminal extends TerminalSupport {
|
public class SshTerminal extends TerminalSupport {
|
||||||
|
|
||||||
protected SshTerminal() {
|
protected SshTerminal() {
|
||||||
super(true);
|
super(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() throws Exception {
|
public void init() throws Exception {
|
||||||
setAnsiSupported(true);
|
setAnsiSupported(true);
|
||||||
setEchoEnabled(true);
|
setEchoEnabled(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ class SshdPlugin extends JavaPlugin
|
|||||||
instance = this;
|
instance = this;
|
||||||
|
|
||||||
sshd = SshServer.setUpDefaultServer();
|
sshd = SshServer.setUpDefaultServer();
|
||||||
sshd.setPort(getConfig().getInt("port", 22));
|
sshd.setPort(getConfig().getInt("Port", 1025));
|
||||||
String host = getConfig().getString("listenAddress", "all");
|
String host = getConfig().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");
|
||||||
@@ -56,7 +56,7 @@ class SshdPlugin extends JavaPlugin
|
|||||||
sshd.setPasswordAuthenticator(new ConfigPasswordAuthenticator());
|
sshd.setPasswordAuthenticator(new ConfigPasswordAuthenticator());
|
||||||
sshd.setPublickeyAuthenticator(new PublicKeyAuthenticator(authorizedKeys));
|
sshd.setPublickeyAuthenticator(new PublicKeyAuthenticator(authorizedKeys));
|
||||||
|
|
||||||
if (getConfig().getBoolean("enableSFTP"))
|
if (getConfig().getBoolean("EnableSFTP"))
|
||||||
{
|
{
|
||||||
sshd.setSubsystemFactories(Collections.singletonList(new SftpSubsystemFactory()));
|
sshd.setSubsystemFactories(Collections.singletonList(new SftpSubsystemFactory()));
|
||||||
sshd.setFileSystemFactory(
|
sshd.setFileSystemFactory(
|
||||||
|
|||||||
@@ -24,108 +24,116 @@ import java.util.logging.Level;
|
|||||||
|
|
||||||
public class SSHDCommandSender implements ConsoleCommandSender, CommandSender {
|
public class SSHDCommandSender implements ConsoleCommandSender, CommandSender {
|
||||||
|
|
||||||
private final PermissibleBase perm = new PermissibleBase(this);
|
private final PermissibleBase perm = new PermissibleBase(this);
|
||||||
private final SSHDConversationTracker conversationTracker = new SSHDConversationTracker();
|
private final SSHDConversationTracker conversationTracker = new SSHDConversationTracker();
|
||||||
|
// Set by the upstream allocating function
|
||||||
|
public ConsoleShellFactory.ConsoleShell console;
|
||||||
|
|
||||||
public void sendMessage(String message) {
|
public void sendMessage(String message) {
|
||||||
this.sendRawMessage(message);
|
this.sendRawMessage(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendRawMessage(String message) {
|
public void sendRawMessage(String message)
|
||||||
if(ConsoleShellFactory.ConsoleShell.consoleReader == null) return;
|
{
|
||||||
try {
|
// What the fuck does this code even do? Are we sending to one client or all of them?
|
||||||
ConsoleShellFactory.ConsoleShell.consoleReader.println(ChatColor.stripColor(message));
|
if (this.console.ConsoleReader == null)
|
||||||
} catch (IOException e) {
|
return;
|
||||||
SshdPlugin.instance.getLogger().log(Level.SEVERE, "Error sending message to SSHDCommandSender", e);
|
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) {
|
public void sendMessage(String[] messages) {
|
||||||
Arrays.asList(messages).forEach(this::sendMessage);
|
Arrays.asList(messages).forEach(this::sendMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "Console";
|
return "SSHD Console";
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isOp() {
|
public boolean isOp() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOp(boolean value) {
|
public void setOp(boolean value) {
|
||||||
throw new UnsupportedOperationException("Cannot change operator status of server console");
|
throw new UnsupportedOperationException("Cannot change operator status of server console");
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean beginConversation(Conversation conversation) {
|
public boolean beginConversation(Conversation conversation) {
|
||||||
return this.conversationTracker.beginConversation(conversation);
|
return this.conversationTracker.beginConversation(conversation);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void abandonConversation(Conversation conversation) {
|
public void abandonConversation(Conversation conversation) {
|
||||||
this.conversationTracker.abandonConversation(conversation, new ConversationAbandonedEvent(conversation, new ManuallyAbandonedConversationCanceller()));
|
this.conversationTracker.abandonConversation(conversation, new ConversationAbandonedEvent(conversation, new ManuallyAbandonedConversationCanceller()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void abandonConversation(Conversation conversation, ConversationAbandonedEvent details) {
|
public void abandonConversation(Conversation conversation, ConversationAbandonedEvent details) {
|
||||||
this.conversationTracker.abandonConversation(conversation, details);
|
this.conversationTracker.abandonConversation(conversation, details);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void acceptConversationInput(String input) {
|
public void acceptConversationInput(String input) {
|
||||||
this.conversationTracker.acceptConversationInput(input);
|
this.conversationTracker.acceptConversationInput(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isConversing() {
|
public boolean isConversing() {
|
||||||
return this.conversationTracker.isConversing();
|
return this.conversationTracker.isConversing();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPermissionSet(String name) {
|
public boolean isPermissionSet(String name) {
|
||||||
return this.perm.isPermissionSet(name);
|
return this.perm.isPermissionSet(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPermissionSet(Permission perm) {
|
public boolean isPermissionSet(Permission perm) {
|
||||||
return this.perm.isPermissionSet(perm);
|
return this.perm.isPermissionSet(perm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasPermission(String name) {
|
public boolean hasPermission(String name) {
|
||||||
return this.perm.hasPermission(name);
|
return this.perm.hasPermission(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasPermission(Permission perm) {
|
public boolean hasPermission(Permission perm) {
|
||||||
return this.perm.hasPermission(perm);
|
return this.perm.hasPermission(perm);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) {
|
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value) {
|
||||||
return this.perm.addAttachment(plugin, name, value);
|
return this.perm.addAttachment(plugin, name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PermissionAttachment addAttachment(Plugin plugin) {
|
public PermissionAttachment addAttachment(Plugin plugin) {
|
||||||
return this.perm.addAttachment(plugin);
|
return this.perm.addAttachment(plugin);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) {
|
public PermissionAttachment addAttachment(Plugin plugin, String name, boolean value, int ticks) {
|
||||||
return this.perm.addAttachment(plugin, name, value, ticks);
|
return this.perm.addAttachment(plugin, name, value, ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
public PermissionAttachment addAttachment(Plugin plugin, int ticks) {
|
public PermissionAttachment addAttachment(Plugin plugin, int ticks) {
|
||||||
return this.perm.addAttachment(plugin, ticks);
|
return this.perm.addAttachment(plugin, ticks);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeAttachment(PermissionAttachment attachment) {
|
public void removeAttachment(PermissionAttachment attachment) {
|
||||||
this.perm.removeAttachment(attachment);
|
this.perm.removeAttachment(attachment);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void recalculatePermissions() {
|
public void recalculatePermissions() {
|
||||||
this.perm.recalculatePermissions();
|
this.perm.recalculatePermissions();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
|
public Set<PermissionAttachmentInfo> getEffectivePermissions() {
|
||||||
return this.perm.getEffectivePermissions();
|
return this.perm.getEffectivePermissions();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPlayer() {
|
public boolean isPlayer() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Server getServer() {
|
public Server getServer() {
|
||||||
return Bukkit.getServer();
|
return Bukkit.getServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,70 +9,70 @@ import java.util.LinkedList;
|
|||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
public class SSHDConversationTracker {
|
public class SSHDConversationTracker {
|
||||||
private LinkedList<Conversation> conversationQueue = new LinkedList<>();
|
private LinkedList<Conversation> conversationQueue = new LinkedList<>();
|
||||||
|
|
||||||
synchronized boolean beginConversation(Conversation conversation) {
|
synchronized boolean beginConversation(Conversation conversation) {
|
||||||
if (!this.conversationQueue.contains(conversation)) {
|
if (!this.conversationQueue.contains(conversation)) {
|
||||||
this.conversationQueue.addLast(conversation);
|
this.conversationQueue.addLast(conversation);
|
||||||
if (this.conversationQueue.getFirst() == conversation) {
|
if (this.conversationQueue.getFirst() == conversation) {
|
||||||
conversation.begin();
|
conversation.begin();
|
||||||
conversation.outputNextPrompt();
|
conversation.outputNextPrompt();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void abandonConversation(Conversation conversation, ConversationAbandonedEvent details) {
|
synchronized void abandonConversation(Conversation conversation, ConversationAbandonedEvent details) {
|
||||||
if (!this.conversationQueue.isEmpty()) {
|
if (!this.conversationQueue.isEmpty()) {
|
||||||
if (this.conversationQueue.getFirst() == conversation) {
|
if (this.conversationQueue.getFirst() == conversation) {
|
||||||
conversation.abandon(details);
|
conversation.abandon(details);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.conversationQueue.contains(conversation)) {
|
if (this.conversationQueue.contains(conversation)) {
|
||||||
this.conversationQueue.remove(conversation);
|
this.conversationQueue.remove(conversation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.conversationQueue.isEmpty()) {
|
if (!this.conversationQueue.isEmpty()) {
|
||||||
this.conversationQueue.getFirst().outputNextPrompt();
|
this.conversationQueue.getFirst().outputNextPrompt();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized void abandonAllConversations() {
|
public synchronized void abandonAllConversations() {
|
||||||
LinkedList<Conversation> oldQueue = this.conversationQueue;
|
LinkedList<Conversation> oldQueue = this.conversationQueue;
|
||||||
this.conversationQueue = new LinkedList<>();
|
this.conversationQueue = new LinkedList<>();
|
||||||
|
|
||||||
for (Conversation conversation : oldQueue) {
|
for (Conversation conversation : oldQueue) {
|
||||||
try {
|
try {
|
||||||
conversation.abandon(new ConversationAbandonedEvent(conversation, new ManuallyAbandonedConversationCanceller()));
|
conversation.abandon(new ConversationAbandonedEvent(conversation, new ManuallyAbandonedConversationCanceller()));
|
||||||
} catch (Throwable var5) {
|
} catch (Throwable var5) {
|
||||||
Bukkit.getLogger().log(Level.SEVERE, "Unexpected exception while abandoning a conversation", var5);
|
Bukkit.getLogger().log(Level.SEVERE, "Unexpected exception while abandoning a conversation", var5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized void acceptConversationInput(String input) {
|
synchronized void acceptConversationInput(String input) {
|
||||||
if (this.isConversing()) {
|
if (this.isConversing()) {
|
||||||
Conversation conversation = this.conversationQueue.getFirst();
|
Conversation conversation = this.conversationQueue.getFirst();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
conversation.acceptInput(input);
|
conversation.acceptInput(input);
|
||||||
} catch (Throwable var4) {
|
} 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);
|
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() {
|
synchronized boolean isConversing() {
|
||||||
return !this.conversationQueue.isEmpty();
|
return !this.conversationQueue.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized boolean isConversingModaly() {
|
public synchronized boolean isConversingModaly() {
|
||||||
return this.isConversing() && this.conversationQueue.getFirst().isModal();
|
return this.isConversing() && this.conversationQueue.getFirst().isModal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,35 @@
|
|||||||
# The IP addresses(s) the SSH server will listen on. Use a comma separated list for multiple addresses.
|
# The IP addresses(s) the SSH server will listen on. Use a comma separated list for multiple addresses.
|
||||||
# Leave as "all" for all addresses.
|
# Leave as "all" for all addresses.
|
||||||
listenAddress: all
|
ListenAddress: all
|
||||||
# The port the SSH server will listen on.
|
# The port the SSH server will listen on. Note that anything above 1024 will require you to run
|
||||||
port: 22
|
# 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
|
# 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.
|
# 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.
|
# 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.
|
# 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
|
# To authorize a user to login with their public key, install their key using the
|
||||||
# PEM certificate in the authorized_users directory. Name the key file with user's user
|
# OpenSSH authorized_keys file format in the authorized_users directory. Name the key
|
||||||
# name (no file extension).
|
# 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.
|
# 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
|
# user1: password1
|
||||||
# user2: password2
|
# user2: password2
|
||||||
|
|||||||
Reference in New Issue
Block a user