Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
170a96eb94 | ||
|
|
ec1ed8cb9e | ||
|
|
67146ce589 | ||
|
|
e986cacc50 |
26
README.md
26
README.md
@@ -1,11 +1,15 @@
|
||||
Spigot-SSHD
|
||||
Minecraft-SSHD
|
||||
===========
|
||||
|
||||
[](https://travis-ci.org/Justasic/Spigot-SSHD)
|
||||
[](https://travis-ci.org/Justasic/Minecraft-SSHD)
|
||||
[](https://github.com/Justasic/Minecraft-SSHD/releases/latest)
|
||||
[](https://github.com/Justasic/Minecraft-SSHD/blob/master/LICENSE)
|
||||
|
||||
Have you ever wished you could remotely access your server's admin console without having to setup a complex remote access system? Now you can with SSHD.
|
||||
<img align="left" width="140" height="140" src="docs/ssh_logo.png?raw=true" hspace="5" vspace="5" alt="diskover"><br/>
|
||||
|
||||
SSHD securely exposes your Spigot admin console using the SSH protocol - the same protocol that serves as the secure foundation for nearly all remote server administration.
|
||||
**Have you ever wished you could remotely access your server's admin console without having to setup a complex remote access system? Now you can with Minecraft-SSHD!**
|
||||
|
||||
Minecraft-SSHD securely exposes your BungeeCord admin console and the server filesystem using the SSH protocol - the same protocol that serves as the secure foundation for nearly all remote server administration.<br/>
|
||||
|
||||
- Compatible with all ssh clients, regardless of operating system.
|
||||
- Remotely view your server log in real-time.
|
||||
@@ -16,7 +20,7 @@ SSHD securely exposes your Spigot admin console using the SSH protocol - the sam
|
||||
- Run Spigot without using screen or tmux (by adding `-noconsole`)
|
||||
- Remotely script your server by issuing one-off console commands with ssh.
|
||||
|
||||
### Why should I use SSHD?
|
||||
### Why should I use Minecraft-SSHD?
|
||||
|
||||
- You are in a shared hosting environment that only gives you access to the - log files.
|
||||
- You want to share access to your server console, but don't want to give anybody access to the machine its running on.
|
||||
@@ -26,6 +30,13 @@ SSHD securely exposes your Spigot admin console using the SSH protocol - the sam
|
||||
|
||||
Note: By default, only public key authentication is enabled. This is the most secure authentication mode! Setting a username and password will make your server less secure.
|
||||
|
||||
Screenshots
|
||||
============
|
||||
|
||||
<img align="left" width="390" src="docs/console.png?raw=true" hspace="5" vspace="5" alt="console">
|
||||
<img width="400" src="docs/session.png?raw=true" alt="session"><br>
|
||||
|
||||
|
||||
Setting Up Public Key Authentication
|
||||
====================================
|
||||
|
||||
@@ -82,7 +93,8 @@ mkpasswd supports the following hash algorithms:
|
||||
|
||||
`sshd.mkpasswd` - Checks if the in-game user has access to run the mkpasswd command.
|
||||
|
||||
SSHD uses cryptographic certificates or a secure username and password to verify remote access.
|
||||
Minecraft-SSHD uses cryptographic certificates or a secure username and password to verify remote access.
|
||||
|
||||
|
||||
## Source Code
|
||||
[Get the source on GitHub](https://github.com/Justasic/Spigot-SSHD "Source Code")
|
||||
[Get the source on GitHub](https://github.com/Justasic/Minecraft-SSHD "Source Code")
|
||||
|
||||
BIN
docs/console.png
Normal file
BIN
docs/console.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 355 KiB |
BIN
docs/session.png
Normal file
BIN
docs/session.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 266 KiB |
BIN
docs/ssh_logo.png
Normal file
BIN
docs/ssh_logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
133
docs/ssh_logo.svg
Normal file
133
docs/ssh_logo.svg
Normal file
@@ -0,0 +1,133 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="800"
|
||||
height="800"
|
||||
viewBox="0 0 211.66666 211.66667"
|
||||
version="1.1"
|
||||
id="svg8"
|
||||
sodipodi:docname="ssh_logo.svg"
|
||||
inkscape:version="0.92.4 5da689c313, 2019-01-14">
|
||||
<defs
|
||||
id="defs2">
|
||||
<filter
|
||||
style="color-interpolation-filters:sRGB;"
|
||||
inkscape:label="Drop Shadow"
|
||||
id="filter5273">
|
||||
<feFlood
|
||||
flood-opacity="1"
|
||||
flood-color="rgb(0,0,0)"
|
||||
result="flood"
|
||||
id="feFlood5263" />
|
||||
<feComposite
|
||||
in="flood"
|
||||
in2="SourceGraphic"
|
||||
operator="in"
|
||||
result="composite1"
|
||||
id="feComposite5265" />
|
||||
<feGaussianBlur
|
||||
in="composite1"
|
||||
stdDeviation="3.5"
|
||||
result="blur"
|
||||
id="feGaussianBlur5267" />
|
||||
<feOffset
|
||||
dx="1"
|
||||
dy="1"
|
||||
result="offset"
|
||||
id="feOffset5269" />
|
||||
<feComposite
|
||||
in="SourceGraphic"
|
||||
in2="offset"
|
||||
operator="over"
|
||||
result="composite2"
|
||||
id="feComposite5271" />
|
||||
</filter>
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.7"
|
||||
inkscape:cx="375.64503"
|
||||
inkscape:cy="367.3313"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer3"
|
||||
showgrid="false"
|
||||
units="px"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="1920"
|
||||
inkscape:window-y="119"
|
||||
inkscape:window-maximized="1" />
|
||||
<metadata
|
||||
id="metadata5">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Background"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-85.333343)">
|
||||
<circle
|
||||
style="fill:#4c4c4c;fill-opacity:1;stroke-width:0.30369404;filter:url(#filter5273)"
|
||||
id="path4533"
|
||||
cx="105"
|
||||
cy="192.00002"
|
||||
r="100" />
|
||||
<circle
|
||||
style="fill:#242424;fill-opacity:1;stroke-width:0.27332464;"
|
||||
id="path4533-3"
|
||||
cx="105"
|
||||
cy="192.00002"
|
||||
r="90" />
|
||||
</g>
|
||||
<g
|
||||
inkscape:groupmode="layer"
|
||||
id="layer3"
|
||||
inkscape:label="Text"
|
||||
style="opacity:0.98999999">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:145.88342285px;line-height:0;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.31260732"
|
||||
x="130.4019"
|
||||
y="91.524567"
|
||||
id="text5759"
|
||||
transform="scale(0.84637592,1.1815081)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan5757"
|
||||
x="130.4019"
|
||||
y="91.524567"
|
||||
style="font-size:145.88342285px;line-height:0;fill:#ffffff;fill-opacity:1;stroke-width:0.31260732">_</tspan></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:145.88342285px;line-height:0;font-family:sans-serif;-inkscape-font-specification:'sans-serif, Bold';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;opacity:0.98999999;fill:#20bb00;fill-opacity:1;stroke:none;stroke-width:0.31260732"
|
||||
x="39.53738"
|
||||
y="118.43275"
|
||||
id="text5759-2"
|
||||
transform="scale(0.84637592,1.1815081)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan5757-5"
|
||||
x="39.53738"
|
||||
y="118.43275"
|
||||
style="font-size:123.47222137px;line-height:0;fill:#20bb00;fill-opacity:1;stroke-width:0.31260732">></tspan></text>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.5 KiB |
5
pom.xml
5
pom.xml
@@ -6,8 +6,9 @@
|
||||
|
||||
<groupId>com.ryanmichela</groupId>
|
||||
<artifactId>sshd</artifactId>
|
||||
<version>1.3.6.1</version>
|
||||
<url>https://github.com/Justasic/Bukkit-SSHD/</url>
|
||||
<description>Minecraft-SSHD: The SSH daemon for Minecraft servers.</description>
|
||||
<version>1.3.7</version>
|
||||
<url>https://github.com/Justasic/Minecraft-SSHD/</url>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
|
||||
@@ -96,7 +96,7 @@ public class ConsoleLogFormatter extends Formatter {
|
||||
stringbuilder.append(stringwriter.toString());
|
||||
}
|
||||
|
||||
return stringbuilder.toString();
|
||||
return stringbuilder.toString().replace("\n", "\r\n");
|
||||
}
|
||||
|
||||
private void colorize(LogRecord logrecord)
|
||||
|
||||
@@ -136,6 +136,8 @@ public class ConsoleShellFactory implements ShellFactory {
|
||||
if (command.equals("cls"))
|
||||
{
|
||||
this.ConsoleReader.clearScreen();
|
||||
this.ConsoleReader.drawLine();
|
||||
this.ConsoleReader.flush();
|
||||
continue;
|
||||
}
|
||||
// Hide the mkpasswd command input from other users.
|
||||
@@ -152,10 +154,18 @@ public class ConsoleShellFactory implements ShellFactory {
|
||||
}
|
||||
else
|
||||
{
|
||||
// Don't send our mkpasswd command output. This will echo passwords back
|
||||
// to the console for all to see. This command is strictly between
|
||||
// our plugin and the connected client.
|
||||
if (!mkpasswd)
|
||||
{
|
||||
SshdPlugin.instance.getLogger().info("<" + this.Username + "> " + command);
|
||||
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command);
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command);
|
||||
}
|
||||
else
|
||||
{
|
||||
Bukkit.dispatchCommand(this.SshdCommandSender, command);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -12,9 +12,28 @@ import com.ryanmichela.sshd.SshdPlugin;
|
||||
|
||||
class MkpasswdCommand implements CommandExecutor
|
||||
{
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args)
|
||||
// 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(CommandSender sender, boolean invalid)
|
||||
{
|
||||
if (invalid)
|
||||
sender.sendMessage("\u00A7cInvalid Syntax\u00A7r");
|
||||
sender.sendMessage("\u00A7a/mkpasswd <help|hash> <password>\u00A7r");
|
||||
sender.sendMessage("\u00A79Supported Hashes: SHA256, PBKDF2, BCRYPT, PLAIN\u00A7r");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args)
|
||||
{
|
||||
// If we're not mkpasswd, just fuck off.
|
||||
if (!label.equalsIgnoreCase("mkpasswd"))
|
||||
return false;
|
||||
|
||||
String algoritm, password;
|
||||
try
|
||||
{
|
||||
@@ -22,78 +41,52 @@ class MkpasswdCommand implements CommandExecutor
|
||||
// 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.
|
||||
return false;
|
||||
this.SendSyntax(sender, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If they're console, allow regardless.
|
||||
if (!(sender instanceof Player))
|
||||
{
|
||||
if (label.equalsIgnoreCase("mkpasswd"))
|
||||
boolean hasperm = (sender instanceof Player) ? ((Player)sender).hasPermission("sshd.mkpasswd") : true;
|
||||
|
||||
if (hasperm)
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
String hash = "";
|
||||
// Dumb but whatever. Some people are really dense.
|
||||
if (algoritm.equalsIgnoreCase("PLAIN"))
|
||||
{
|
||||
// Dumb but whatever. Some people are really dense.
|
||||
if (algoritm.equalsIgnoreCase("PLAIN"))
|
||||
{
|
||||
// I mean c'mon...
|
||||
sender.sendMessage("Bro really? it's literally your unencrypted password...");
|
||||
}
|
||||
else if (algoritm.equalsIgnoreCase("pbkdf2"))
|
||||
sender.sendMessage("Your hash: " + Cryptography.PBKDF2_HashPassword(password));
|
||||
else if (algoritm.equalsIgnoreCase("bcrypt"))
|
||||
sender.sendMessage("Your hash: " + Cryptography.BCrypt_HashPassword(password));
|
||||
else if (algoritm.equalsIgnoreCase("sha256"))
|
||||
sender.sendMessage("Your hash: " + Cryptography.SHA256_HashPassword(password));
|
||||
else if (algoritm.equalsIgnoreCase("help"))
|
||||
sender.sendMessage("Supported hash algorithms: pbkdf2, bcrypt, sha256, plain");
|
||||
else
|
||||
return false;
|
||||
// I mean c'mon...
|
||||
sender.sendMessage("Bro really? it's literally your unencrypted password...");
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
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
|
||||
{
|
||||
// We're console, just print the stack trace.
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
this.SendSyntax(sender, !algoritm.equalsIgnoreCase("help"));
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
|
||||
sender.sendMessage("\u00A79Your Hash: " + hash + "\u00A7r");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// We're console, just print the stack trace.
|
||||
e.printStackTrace();
|
||||
sender.sendMessage("\u00A7cAn error occured. Please check console for details.\u00A7r");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Player player = (Player) sender;
|
||||
if (label.equalsIgnoreCase("mkpasswd"))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (player.hasPermission("sshd.mkpasswd"))
|
||||
{
|
||||
// Dumb but whatever. Some people are really dense.
|
||||
if (algoritm.equalsIgnoreCase("PLAIN"))
|
||||
sender.sendMessage(password);
|
||||
else if (algoritm.equalsIgnoreCase("pbkdf2"))
|
||||
sender.sendMessage(Cryptography.PBKDF2_HashPassword(password));
|
||||
else if (algoritm.equalsIgnoreCase("bcrypt"))
|
||||
sender.sendMessage(Cryptography.BCrypt_HashPassword(password));
|
||||
else if (algoritm.equalsIgnoreCase("sha256"))
|
||||
sender.sendMessage(Cryptography.SHA256_HashPassword(password));
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// since this is a player, send a failure message
|
||||
sender.sendMessage("An error occured, please check console.");
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -16,21 +16,23 @@ import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.ryanmichela.sshd.ConsoleShellFactory;
|
||||
import com.ryanmichela.sshd.ConsoleLogFormatter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
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 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 + "\r");
|
||||
}
|
||||
|
||||
public void sendRawMessage(String message)
|
||||
@@ -40,7 +42,18 @@ public class SSHDCommandSender implements ConsoleCommandSender, CommandSender {
|
||||
return;
|
||||
try
|
||||
{
|
||||
this.console.ConsoleReader.println(ChatColor.stripColor(message));
|
||||
this.console.ConsoleReader.println(ConsoleLogFormatter.ColorizeString(message).replace("\n", "\n\r"));
|
||||
this.console.ConsoleReader.print(this.console.ConsoleReader.RESET_LINE + "");
|
||||
this.console.ConsoleReader.flush();
|
||||
try
|
||||
{
|
||||
this.console.ConsoleReader.drawLine();
|
||||
}
|
||||
catch (Throwable ex)
|
||||
{
|
||||
this.console.ConsoleReader.getCursorBuffer().clear();
|
||||
}
|
||||
this.console.ConsoleReader.flush();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
name: SSHD
|
||||
version: ${project.version}
|
||||
author: Ryan Michela, Haarolean, toxuin, Justin Crawford
|
||||
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>
|
||||
usage: /mkpasswd <hash|help> <password>
|
||||
|
||||
Reference in New Issue
Block a user