Merge pull request #5 from rmichela/rpc

Added RPC mode without preamble and annoying stuff.
This commit is contained in:
Roman Zabaluev 2018-02-25 17:22:22 +03:00 committed by GitHub
commit 15faff3dd4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 230 additions and 13 deletions

View File

@ -1,5 +1,6 @@
package com.ryanmichela.sshd; package com.ryanmichela.sshd;
import com.ryanmichela.sshd.implementations.SSHDCommandSender;
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;
@ -12,9 +13,13 @@ 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.util.logging.Level;
import java.util.logging.StreamHandler; import java.util.logging.StreamHandler;
public class ConsoleShellFactory implements Factory<Command> { public class ConsoleShellFactory implements Factory<Command> {
static SSHDCommandSender sshdCommandSender = new SSHDCommandSender();
public Command get() { public Command get() {
return this.create(); return this.create();
} }
@ -24,7 +29,6 @@ public class ConsoleShellFactory implements Factory<Command> {
} }
public static class ConsoleShell implements Command, Runnable { public static class ConsoleShell implements Command, Runnable {
private InputStream in; private InputStream in;
private OutputStream out; private OutputStream out;
private OutputStream err; private OutputStream err;
@ -33,7 +37,7 @@ public class ConsoleShellFactory implements Factory<Command> {
private Thread thread; private Thread thread;
StreamHandlerAppender streamHandlerAppender; StreamHandlerAppender streamHandlerAppender;
ConsoleReader consoleReader; public static ConsoleReader consoleReader;
public InputStream getIn() { public InputStream getIn() {
return in; return in;
@ -68,7 +72,6 @@ public class ConsoleShellFactory implements Factory<Command> {
} }
public void start(Environment env) throws IOException { public void start(Environment env) throws IOException {
try { try {
consoleReader = new ConsoleReader(in, new FlushyOutputStream(out), new SshTerminal()); consoleReader = new ConsoleReader(in, new FlushyOutputStream(out), new SshTerminal());
consoleReader.setExpandEvents(true); consoleReader.setExpandEvents(true);
@ -93,21 +96,25 @@ public class ConsoleShellFactory implements Factory<Command> {
public void run() { public void run() {
try { try {
if (!SshdPlugin.instance.getConfig().getString("mode").equals("RPC"))
printPreamble(consoleReader); printPreamble(consoleReader);
while (true) { while (true) {
String command = consoleReader.readLine("\r>", null); String command = consoleReader.readLine("\r>", null);
if (command != null) { if (command == null) continue;
if (command.equals("exit")) { if (command.equals("exit")) break;
break;
}
SshdPlugin.instance.getLogger().info("<" + environment.getEnv().get(Environment.ENV_USER) + "> " + command);
Bukkit.getScheduler().runTask(SshdPlugin.instance, () -> { 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); Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command);
}
}); });
} }
}
} catch (IOException e) { } catch (IOException e) {
SshdPlugin.instance.getLogger().severe("Error processing command from SSH"); SshdPlugin.instance.getLogger().log(Level.SEVERE, "Error processing command from SSH", e);
} finally { } finally {
callback.onExit(0); callback.onExit(0);
} }

View File

@ -0,0 +1,129 @@
package com.ryanmichela.sshd.implementations;
import com.ryanmichela.sshd.ConsoleShellFactory;
import com.ryanmichela.sshd.SshdPlugin;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.conversations.Conversation;
import org.bukkit.conversations.ConversationAbandonedEvent;
import org.bukkit.conversations.ManuallyAbandonedConversationCanceller;
import org.bukkit.permissions.PermissibleBase;
import org.bukkit.permissions.Permission;
import org.bukkit.permissions.PermissionAttachment;
import org.bukkit.permissions.PermissionAttachmentInfo;
import org.bukkit.plugin.Plugin;
import java.io.IOException;
import java.util.Arrays;
import java.util.Set;
import java.util.logging.Level;
public class SSHDCommandSender implements ConsoleCommandSender, CommandSender {
private final PermissibleBase perm = new PermissibleBase(this);
private final SSHDConversationTracker conversationTracker = new SSHDConversationTracker();
public void sendMessage(String message) {
this.sendRawMessage(message);
}
public void sendRawMessage(String message) {
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 sendMessage(String[] messages) {
Arrays.asList(messages).forEach(this::sendMessage);
}
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();
}
}

View File

@ -0,0 +1,78 @@
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();
}
}

View File

@ -4,6 +4,9 @@ listenAddress: all
# The port the SSH server will listen on. # The port the SSH server will listen on.
port: 22 port: 22
# Operational mode. Don't touch if you don't know what you're doing. Can be either DEFAULT or RPC
mode: DEFAULT
# 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 log in with public key authentication, install their public
# PEM certificate in the authorized_users directory. Name the key file with user's user # PEM certificate in the authorized_users directory. Name the key file with user's user