Compare commits
6 Commits
Author | SHA1 | Date |
---|---|---|
Zachery | bf72021439 | |
Justin Crawford | dd76551cf9 | |
Justin Crawford | a7918c68aa | |
Justin Crawford | 41b561a88c | |
Zachery | 67aa5c63ea | |
Zachery | 7c6ae57513 |
|
@ -1,4 +1,4 @@
|
|||
Minecraft-SSHD
|
||||
Minecraft-SSHD (Sponge Edition!)
|
||||
===========
|
||||
|
||||
[![Build Status](https://travis-ci.org/Justasic/Minecraft-SSHD.svg?branch=master)](https://travis-ci.org/Justasic/Minecraft-SSHD)
|
||||
|
@ -9,7 +9,7 @@ Minecraft-SSHD
|
|||
|
||||
**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/>
|
||||
Minecraft-SSHD securely exposes your Sponge 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.
|
||||
|
@ -22,7 +22,7 @@ Minecraft-SSHD securely exposes your BungeeCord admin console and the server fil
|
|||
|
||||
### Why should I use Minecraft-SSHD?
|
||||
|
||||
- You are in a shared hosting environment that only gives you access to the - log files.
|
||||
- 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.
|
||||
- You always wanted to use RCON, but want to see the server log as well.
|
||||
- You are tired of running your server in a GNU screen or tmux session.
|
||||
|
|
|
@ -0,0 +1,89 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="minecraft" name="Minecraft">
|
||||
<configuration>
|
||||
<autoDetectTypes>
|
||||
<platformType>SPONGE</platformType>
|
||||
</autoDetectTypes>
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
|
||||
<output url="file://$MODULE_DIR$/target/classes" />
|
||||
<output-test url="file://$MODULE_DIR$/target/test-classes" />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="Maven: org.apache.sshd:sshd-core:2.3.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.sshd:sshd-mina:2.3.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.sshd:sshd-common:2.3.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.sshd:sshd-sftp:2.3.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: net.i2p.crypto:eddsa:0.3.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.mina:mina-core:2.1.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.28" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.slf4j:slf4j-jdk14:1.7.28" level="project" />
|
||||
<orderEntry type="library" name="Maven: jline:jline:2.12.1" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: org.apache.logging.log4j:log4j-core:2.0" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: org.apache.logging.log4j:log4j-api:2.1" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: commons-codec:commons-codec:1.10" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: org.spongepowered:spongeapi:7.1.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.google.guava:guava:21.0" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: com.google.errorprone:error_prone_annotations:2.0.15" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: com.google.code.gson:gson:2.8.0" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: org.apache.commons:commons-lang3:3.5" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: com.google.code.findbugs:jsr305:3.0.1" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: com.google.inject:guice:4.1.0" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: javax.inject:javax.inject:1" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: aopalliance:aopalliance:1.0" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: com.github.ben-manes.caffeine:caffeine:2.5.4" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: com.github.ben-manes.caffeine:guava:2.5.4" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: org.spongepowered:plugin-meta:0.4.1" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: org.spongepowered:configurate-hocon:3.6" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: org.spongepowered:configurate-core:3.6" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: org.checkerframework:checker-qual:2.4.0" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: com.typesafe:config:1.3.1" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: org.spongepowered:configurate-gson:3.6" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: org.spongepowered:configurate-yaml:3.6" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: org.yaml:snakeyaml:1.18" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: com.flowpowered:flow-math:1.0.3" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: com.flowpowered:flow-noise:1.0.1-SNAPSHOT" level="project" />
|
||||
<orderEntry type="library" scope="PROVIDED" name="Maven: org.ow2.asm:asm:5.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: pl.project13.maven:git-commit-id-plugin:maven-plugin:3.0.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.maven:maven-plugin-api:3.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.maven:maven-model:3.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.maven:maven-artifact:3.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.sonatype.sisu:sisu-inject-plexus:1.4.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.sonatype.sisu:sisu-inject-bean:1.4.2" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.sonatype.sisu:sisu-guice:noaop:2.1.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.maven:maven-core:3.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.maven:maven-settings:3.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.maven:maven-settings-builder:3.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.maven:maven-repository-metadata:3.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.apache.maven:maven-model-builder:3.0" level="project" />
|
||||
<orderEntry type="library" scope="RUNTIME" name="Maven: org.apache.maven:maven-aether-provider:3.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.sonatype.aether:aether-impl:1.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.sonatype.aether:aether-spi:1.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.sonatype.aether:aether-api:1.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.sonatype.aether:aether-util:1.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.codehaus.plexus:plexus-interpolation:1.14" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.codehaus.plexus:plexus-utils:2.0.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.codehaus.plexus:plexus-classworlds:2.2.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.codehaus.plexus:plexus-component-annotations:1.5.5" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.sonatype.plexus:plexus-sec-dispatcher:1.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.sonatype.plexus:plexus-cipher:1.4" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.sonatype.plexus:plexus-build-api:0.0.7" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.9.9.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.9.0" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.9.9" level="project" />
|
||||
<orderEntry type="library" name="Maven: joda-time:joda-time:2.10.3" level="project" />
|
||||
<orderEntry type="library" name="Maven: org.eclipse.jgit:org.eclipse.jgit:5.2.2.201904231744-r" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.jcraft:jsch:0.1.54" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.jcraft:jzlib:1.1.1" level="project" />
|
||||
<orderEntry type="library" name="Maven: com.googlecode.javaewah:JavaEWAH:1.1.6" level="project" />
|
||||
</component>
|
||||
</module>
|
198
pom.xml
198
pom.xml
|
@ -1,50 +1,35 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.ryanmichela</groupId>
|
||||
<artifactId>sshd</artifactId>
|
||||
<description>Minecraft-SSHD: The SSH daemon for Minecraft servers.</description>
|
||||
<version>1.3.7</version>
|
||||
<url>https://github.com/Justasic/Minecraft-SSHD/</url>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<groupId>com.ryanmichela</groupId>
|
||||
<artifactId>sshd</artifactId>
|
||||
<version>2.0.0</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>Sponge-SSHD</name>
|
||||
<description>Sponge port for Minecraft-SSHD. SSH for your minecraft server!</description>
|
||||
<url>https://github.com/Justasic/Minecraft-SSHD/</url>
|
||||
|
||||
<!-- Repositories -->
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/groups/public</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<!-- License -->
|
||||
<licenses>
|
||||
<license>
|
||||
<name>GPL2</name>
|
||||
<url>http://www.gnu.org/licenses/gpl-2.0.html</url>
|
||||
</license>
|
||||
</licenses>
|
||||
|
||||
<!-- Dependencies -->
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
<version>1.14.4-R0.1-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>sponge</id>
|
||||
<url>https://repo.spongepowered.org/maven</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.sshd</groupId>
|
||||
<artifactId>sshd-core</artifactId>
|
||||
<version>2.3.0</version>
|
||||
<scope>compile</scope>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
@ -57,8 +42,6 @@
|
|||
<groupId>org.apache.sshd</groupId>
|
||||
<artifactId>sshd-common</artifactId>
|
||||
<version>2.3.0</version>
|
||||
<scope>compile</scope>
|
||||
<type>jar</type>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
|
@ -72,24 +55,6 @@
|
|||
<artifactId>eddsa</artifactId>
|
||||
<version>0.3.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.mina</groupId>
|
||||
<artifactId>mina-core</artifactId>
|
||||
<version>2.1.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
<version>1.7.28</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-jdk14</artifactId>
|
||||
<version>1.7.28</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>jline</groupId>
|
||||
|
@ -100,76 +65,73 @@
|
|||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-core</artifactId>
|
||||
<version>2.0</version>
|
||||
<scope>provided</scope>
|
||||
<version>2.1</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>2.1</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- include Sponge API -->
|
||||
<dependency>
|
||||
<groupId>org.spongepowered</groupId>
|
||||
<artifactId>spongeapi</artifactId>
|
||||
<version>7.1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
<version>1.10</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<!-- Set our default goal to be clean and build a package -->
|
||||
<defaultGoal>clean package</defaultGoal>
|
||||
<!-- Include our git hash in the final name -->
|
||||
<finalName>${project.artifactId}-${project.version}</finalName>
|
||||
|
||||
<!-- Build -->
|
||||
<build>
|
||||
<defaultGoal>clean package</defaultGoal>
|
||||
<resources>
|
||||
<resource>
|
||||
<targetPath>.</targetPath>
|
||||
<filtering>true</filtering>
|
||||
<directory>${basedir}/src/main/resources</directory>
|
||||
<includes>
|
||||
<include>motd.txt</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<resources>
|
||||
<resource>
|
||||
<targetPath>.</targetPath>
|
||||
<filtering>true</filtering>
|
||||
<directory>${basedir}/src/main/resources</directory>
|
||||
<includes>
|
||||
<include>plugin.yml</include>
|
||||
<include>config.yml</include>
|
||||
<include>motd.txt</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
<!-- Plugins -->
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<finalName>${project.artifactId}-${project.version}</finalName>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-assembly-plugin</artifactId>
|
||||
<version>3.1.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>single</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<finalName>${project.name}-${project.version}</finalName>
|
||||
<appendAssemblyId>false</appendAssemblyId>
|
||||
<descriptorRefs>
|
||||
<descriptorRef>jar-with-dependencies</descriptorRef>
|
||||
</descriptorRefs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<!-- Compile plugin -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.7.0</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<showDeprecation>true</showDeprecation>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
<!-- Compile plugin -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.7.0</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<showDeprecation>true</showDeprecation>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,222 @@
|
|||
package com.ryanmichela.sshd;
|
||||
// The below code was taken from md_5's BungeeCord project - Justin
|
||||
/*
|
||||
Copyright (c) 2012, md_5. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
You may not use the software for commercial software hosting services without
|
||||
written permission from the author.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* Simplistic enumeration of all supported color values for chat.
|
||||
*/
|
||||
public enum ChatColor
|
||||
{
|
||||
/**
|
||||
* Represents black.
|
||||
*/
|
||||
BLACK( '0', "black" ),
|
||||
/**
|
||||
* Represents dark blue.
|
||||
*/
|
||||
DARK_BLUE( '1', "dark_blue" ),
|
||||
/**
|
||||
* Represents dark green.
|
||||
*/
|
||||
DARK_GREEN( '2', "dark_green" ),
|
||||
/**
|
||||
* Represents dark blue (aqua).
|
||||
*/
|
||||
DARK_AQUA( '3', "dark_aqua" ),
|
||||
/**
|
||||
* Represents dark red.
|
||||
*/
|
||||
DARK_RED( '4', "dark_red" ),
|
||||
/**
|
||||
* Represents dark purple.
|
||||
*/
|
||||
DARK_PURPLE( '5', "dark_purple" ),
|
||||
/**
|
||||
* Represents gold.
|
||||
*/
|
||||
GOLD( '6', "gold" ),
|
||||
/**
|
||||
* Represents gray.
|
||||
*/
|
||||
GRAY( '7', "gray" ),
|
||||
/**
|
||||
* Represents dark gray.
|
||||
*/
|
||||
DARK_GRAY( '8', "dark_gray" ),
|
||||
/**
|
||||
* Represents blue.
|
||||
*/
|
||||
BLUE( '9', "blue" ),
|
||||
/**
|
||||
* Represents green.
|
||||
*/
|
||||
GREEN( 'a', "green" ),
|
||||
/**
|
||||
* Represents aqua.
|
||||
*/
|
||||
AQUA( 'b', "aqua" ),
|
||||
/**
|
||||
* Represents red.
|
||||
*/
|
||||
RED( 'c', "red" ),
|
||||
/**
|
||||
* Represents light purple.
|
||||
*/
|
||||
LIGHT_PURPLE( 'd', "light_purple" ),
|
||||
/**
|
||||
* Represents yellow.
|
||||
*/
|
||||
YELLOW( 'e', "yellow" ),
|
||||
/**
|
||||
* Represents white.
|
||||
*/
|
||||
WHITE( 'f', "white" ),
|
||||
/**
|
||||
* Represents magical characters that change around randomly.
|
||||
*/
|
||||
MAGIC( 'k', "obfuscated" ),
|
||||
/**
|
||||
* Makes the text bold.
|
||||
*/
|
||||
BOLD( 'l', "bold" ),
|
||||
/**
|
||||
* Makes a line appear through the text.
|
||||
*/
|
||||
STRIKETHROUGH( 'm', "strikethrough" ),
|
||||
/**
|
||||
* Makes the text appear underlined.
|
||||
*/
|
||||
UNDERLINE( 'n', "underline" ),
|
||||
/**
|
||||
* Makes the text italic.
|
||||
*/
|
||||
ITALIC( 'o', "italic" ),
|
||||
/**
|
||||
* Resets all previous chat colors or formats.
|
||||
*/
|
||||
RESET( 'r', "reset" );
|
||||
/**
|
||||
* The special character which prefixes all chat colour codes. Use this if
|
||||
* you need to dynamically convert colour codes from your custom format.
|
||||
*/
|
||||
public static final char COLOR_CHAR = '\u00A7';
|
||||
public static final String ALL_CODES = "0123456789AaBbCcDdEeFfKkLlMmNnOoRr";
|
||||
/**
|
||||
* Pattern to remove all colour codes.
|
||||
*/
|
||||
public static final Pattern STRIP_COLOR_PATTERN = Pattern.compile( "(?i)" + String.valueOf( COLOR_CHAR ) + "[0-9A-FK-OR]" );
|
||||
/**
|
||||
* Colour instances keyed by their active character.
|
||||
*/
|
||||
private static final Map<Character, ChatColor> BY_CHAR = new HashMap<Character, ChatColor>();
|
||||
/**
|
||||
* The code appended to {@link #COLOR_CHAR} to make usable colour.
|
||||
*/
|
||||
private final char code;
|
||||
/**
|
||||
* This colour's colour char prefixed by the {@link #COLOR_CHAR}.
|
||||
*/
|
||||
private final String toString;
|
||||
private final String name;
|
||||
|
||||
public String getName() { return this.name; }
|
||||
|
||||
static
|
||||
{
|
||||
for ( ChatColor colour : values() )
|
||||
{
|
||||
BY_CHAR.put( colour.code, colour );
|
||||
}
|
||||
}
|
||||
|
||||
private ChatColor(char code, String name)
|
||||
{
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
this.toString = new String( new char[]
|
||||
{
|
||||
COLOR_CHAR, code
|
||||
} );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return toString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips the given message of all color codes
|
||||
*
|
||||
* @param input String to strip of color
|
||||
* @return A copy of the input string, without any coloring
|
||||
*/
|
||||
public static String stripColor(final String input)
|
||||
{
|
||||
if ( input == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return STRIP_COLOR_PATTERN.matcher( input ).replaceAll( "" );
|
||||
}
|
||||
|
||||
public static String translateAlternateColorCodes(char altColorChar, String textToTranslate)
|
||||
{
|
||||
char[] b = textToTranslate.toCharArray();
|
||||
for ( int i = 0; i < b.length - 1; i++ )
|
||||
{
|
||||
if ( b[i] == altColorChar && ALL_CODES.indexOf( b[i + 1] ) > -1 )
|
||||
{
|
||||
b[i] = ChatColor.COLOR_CHAR;
|
||||
b[i + 1] = Character.toLowerCase( b[i + 1] );
|
||||
}
|
||||
}
|
||||
return new String( b );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the colour represented by the specified code.
|
||||
*
|
||||
* @param code the code to search for
|
||||
* @return the mapped colour, or null if non exists
|
||||
*/
|
||||
public static ChatColor getByChar(char code)
|
||||
{
|
||||
return BY_CHAR.get( code );
|
||||
}
|
||||
}
|
|
@ -19,11 +19,11 @@ public class ConfigPasswordAuthenticator implements PasswordAuthenticator {
|
|||
public boolean authenticate(String username, String password, ServerSession ss)
|
||||
{
|
||||
// Depending on our hash type, we have to try and figure out what we're doing.
|
||||
String HashType = SshdPlugin.instance.getConfig().getString("PasswordType");
|
||||
String ConfigHash = SshdPlugin.instance.getConfig().getString("Credentials." + username.trim());
|
||||
String HashType = SshdPlugin.GetInstance().PasswordType;
|
||||
String ConfigHash = SshdPlugin.GetInstance().config.configNode.getNode("Credentials", username.trim(), "password").getString();
|
||||
|
||||
if (ConfigHash == null)
|
||||
SshdPlugin.instance.getLogger().warning("Config has no such user: " + username);
|
||||
SshdPlugin.GetInstance().logger.warn("Config has no such user: " + username);
|
||||
else
|
||||
{
|
||||
try
|
||||
|
@ -69,8 +69,8 @@ public class ConfigPasswordAuthenticator implements PasswordAuthenticator {
|
|||
}
|
||||
}
|
||||
|
||||
SshdPlugin.instance.getLogger().info("Failed login for " + username + " using " + HashType + "-based password authentication.");
|
||||
Integer tries = SshdPlugin.instance.getConfig().getInt("LoginRetries");
|
||||
SshdPlugin.GetInstance().logger.info("Failed login for " + username + " using " + HashType + "-based password authentication.");
|
||||
Integer tries = SshdPlugin.GetInstance().LoginRetries;
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -83,7 +83,7 @@ public class ConfigPasswordAuthenticator implements PasswordAuthenticator {
|
|||
if (this.FailCounts.get(username) >= tries)
|
||||
{
|
||||
this.FailCounts.put(username, 0);
|
||||
SshdPlugin.instance.getLogger().info("Too many failures for " + username + ", disconnecting.");
|
||||
SshdPlugin.GetInstance().logger.info("Too many failures for " + username + ", disconnecting.");
|
||||
ss.close(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,40 +5,61 @@ package com.ryanmichela.sshd;
|
|||
*/
|
||||
|
||||
import jline.console.completer.Completer;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandMap;
|
||||
|
||||
import org.spongepowered.api.Sponge;
|
||||
import org.spongepowered.api.scheduler.SpongeExecutorService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class ConsoleCommandCompleter implements Completer {
|
||||
public class ConsoleCommandCompleter implements Completer
|
||||
{
|
||||
private SpongeExecutorService MinecraftExecutor;
|
||||
|
||||
public int complete(final String buffer, final int cursor, final List<CharSequence> candidates) {
|
||||
Waitable<List<String>> waitable = new Waitable<List<String>>() {
|
||||
public ConsoleCommandCompleter()
|
||||
{
|
||||
super();
|
||||
this.MinecraftExecutor = Sponge.getScheduler().createSyncExecutor(SshdPlugin.GetInstance());
|
||||
}
|
||||
|
||||
public int complete(final String buffer, final int cursor, final List<CharSequence> candidates)
|
||||
{
|
||||
Waitable<List<String>> waitable = new Waitable<List<String>>()
|
||||
{
|
||||
@Override
|
||||
protected List<String> evaluate() {
|
||||
CommandMap commandMap = ReflectionUtil.getProtectedValue(Bukkit.getServer(), "commandMap");
|
||||
return commandMap.tabComplete(Bukkit.getServer().getConsoleSender(), buffer);
|
||||
protected List<String> evaluate()
|
||||
{
|
||||
return Sponge.getCommandManager().getSuggestions(Sponge.getServer().getConsole(), buffer, null);
|
||||
}
|
||||
};
|
||||
Bukkit.getScheduler().runTask(SshdPlugin.instance, waitable);
|
||||
try {
|
||||
|
||||
this.MinecraftExecutor.execute(waitable);
|
||||
try
|
||||
{
|
||||
List<String> offers = waitable.get();
|
||||
if (offers == null) {
|
||||
if (offers == null)
|
||||
{
|
||||
return cursor;
|
||||
}
|
||||
candidates.addAll(offers);
|
||||
|
||||
final int lastSpace = buffer.lastIndexOf(' ');
|
||||
if (lastSpace == -1) {
|
||||
if (lastSpace == -1)
|
||||
{
|
||||
return cursor - buffer.length();
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
return cursor - (buffer.length() - lastSpace - 1);
|
||||
}
|
||||
} catch (ExecutionException e) {
|
||||
SshdPlugin.instance.getLogger().log(Level.WARNING, "Unhandled exception when tab completing", e);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
catch (ExecutionException e)
|
||||
{
|
||||
SshdPlugin.GetInstance().logger.warn("Unhandled exception when tab completing", e);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
return cursor;
|
||||
|
|
|
@ -5,7 +5,7 @@ import org.apache.sshd.server.command.CommandFactory;
|
|||
import org.apache.sshd.server.channel.ChannelSession;
|
||||
import org.apache.sshd.server.Environment;
|
||||
import org.apache.sshd.server.ExitCallback;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.spongepowered.api.Sponge;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -51,14 +51,21 @@ public class ConsoleCommandFactory implements CommandFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void start(ChannelSession cs, Environment environment) throws IOException {
|
||||
try {
|
||||
SshdPlugin.instance.getLogger()
|
||||
public void start(ChannelSession cs, Environment environment) throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
SshdPlugin.GetInstance().logger
|
||||
.info("[U: " + environment.getEnv().get(Environment.ENV_USER) + "] " + command);
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command);
|
||||
} catch (Exception e) {
|
||||
SshdPlugin.instance.getLogger().severe("Error processing command from SSH -" + e.getMessage());
|
||||
} finally {
|
||||
|
||||
Sponge.getCommandManager().process(Sponge.getServer().getConsole(), command);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
SshdPlugin.GetInstance().logger.error("Error processing command from SSH -" + e.getMessage());
|
||||
}
|
||||
finally
|
||||
{
|
||||
callback.onExit(0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,25 +4,17 @@ package com.ryanmichela.sshd;
|
|||
* Copyright 2013 Ryan Michela
|
||||
*/
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import com.ryanmichela.sshd.ChatColor;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Formatter;
|
||||
import java.util.logging.LogRecord;
|
||||
|
||||
public class ConsoleLogFormatter extends Formatter {
|
||||
|
||||
private SimpleDateFormat dateFormat;
|
||||
private static final Map<ChatColor, String> replacements = new EnumMap<ChatColor, String>(ChatColor.class);
|
||||
|
||||
public ConsoleLogFormatter() {
|
||||
this.dateFormat = new SimpleDateFormat("HH:mm:ss");
|
||||
}
|
||||
public class ConsoleLogFormatter
|
||||
{
|
||||
private static final Map<ChatColor, String> replacements = new EnumMap<ChatColor, String>(ChatColor.class);
|
||||
|
||||
public static String ColorizeString(String str)
|
||||
{
|
||||
|
@ -66,43 +58,5 @@ public class ConsoleLogFormatter extends Formatter {
|
|||
result += Ansi.ansi().reset().toString();
|
||||
return result;
|
||||
}
|
||||
|
||||
public String format(LogRecord logrecord)
|
||||
{
|
||||
try
|
||||
{
|
||||
Class.forName("org.bukkit.craftbukkit.command.ColouredConsoleSender");
|
||||
}
|
||||
catch (ClassNotFoundException ignored)
|
||||
{
|
||||
// MEANS WE'RE ON PAPER/TACO/OTHER SHIT
|
||||
colorize(logrecord);
|
||||
}
|
||||
StringBuilder stringbuilder = new StringBuilder();
|
||||
|
||||
stringbuilder.append(" [");
|
||||
stringbuilder.append(this.dateFormat.format(logrecord.getMillis())).append(" ");
|
||||
|
||||
stringbuilder.append(logrecord.getLevel().getName()).append("]: ");
|
||||
stringbuilder.append(this.formatMessage(logrecord));
|
||||
stringbuilder.append('\n');
|
||||
Throwable throwable = logrecord.getThrown();
|
||||
|
||||
if (throwable != null)
|
||||
{
|
||||
StringWriter stringwriter = new StringWriter();
|
||||
|
||||
throwable.printStackTrace(new PrintWriter(stringwriter));
|
||||
stringbuilder.append(stringwriter.toString());
|
||||
}
|
||||
|
||||
return stringbuilder.toString().replace("\n", "\r\n");
|
||||
}
|
||||
|
||||
private void colorize(LogRecord logrecord)
|
||||
{
|
||||
String result = ColorizeString(logrecord.getMessage());
|
||||
logrecord.setMessage(result);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package com.ryanmichela.sshd;
|
|||
import com.ryanmichela.sshd.ConsoleCommandCompleter;
|
||||
import com.ryanmichela.sshd.ConsoleLogFormatter;
|
||||
import com.ryanmichela.sshd.FlushyOutputStream;
|
||||
import com.ryanmichela.sshd.FlushyStreamHandler;
|
||||
import com.ryanmichela.sshd.SshTerminal;
|
||||
import com.ryanmichela.sshd.SshdPlugin;
|
||||
import com.ryanmichela.sshd.StreamHandlerAppender;
|
||||
|
@ -18,7 +17,12 @@ import org.apache.sshd.server.command.Command;
|
|||
import org.apache.sshd.server.channel.ChannelSession;
|
||||
import org.apache.sshd.server.Environment;
|
||||
import org.apache.sshd.server.ExitCallback;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.spongepowered.api.MinecraftVersion;
|
||||
import org.spongepowered.api.Platform;
|
||||
import org.spongepowered.api.Sponge;
|
||||
import org.spongepowered.api.command.CommandManager;
|
||||
import org.spongepowered.api.plugin.PluginContainer;
|
||||
import org.spongepowered.api.scheduler.SpongeExecutorService;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
|
@ -93,8 +97,7 @@ public class ConsoleShellFactory implements ShellFactory {
|
|||
this.ConsoleReader.setExpandEvents(true);
|
||||
this.ConsoleReader.addCompleter(new ConsoleCommandCompleter());
|
||||
|
||||
StreamHandler streamHandler = new FlushyStreamHandler(out, new ConsoleLogFormatter(), this.ConsoleReader);
|
||||
this.streamHandlerAppender = new StreamHandlerAppender(streamHandler);
|
||||
this.streamHandlerAppender = new StreamHandlerAppender(this.ConsoleReader);
|
||||
|
||||
((Logger)LogManager.getRootLogger()).addAppender(this.streamHandlerAppender);
|
||||
|
||||
|
@ -118,11 +121,15 @@ public class ConsoleShellFactory implements ShellFactory {
|
|||
{
|
||||
try
|
||||
{
|
||||
if (!SshdPlugin.instance.getConfig().getString("Mode").equals("RPC"))
|
||||
// Get the sponge command manager so we can execute commands.
|
||||
CommandManager CmdManager = Sponge.getCommandManager();
|
||||
SpongeExecutorService MinecraftExecutor = Sponge.getScheduler().createSyncExecutor(SshdPlugin.GetInstance());
|
||||
// Print the SSHD motd.
|
||||
if (!SshdPlugin.GetInstance().Mode.equals("RPC"))
|
||||
printPreamble(this.ConsoleReader);
|
||||
while (true)
|
||||
{
|
||||
String command = this.ConsoleReader.readLine("\r>", null);
|
||||
String command = this.ConsoleReader.readLine("\r> ", null);
|
||||
// The user sent CTRL+D to close the shell, terminate the session.
|
||||
if (command == null)
|
||||
break;
|
||||
|
@ -143,14 +150,13 @@ public class ConsoleShellFactory implements ShellFactory {
|
|||
// Hide the mkpasswd command input from other users.
|
||||
Boolean mkpasswd = command.split(" ")[0].equals("mkpasswd");
|
||||
|
||||
Bukkit.getScheduler().runTask(
|
||||
SshdPlugin.instance, () ->
|
||||
MinecraftExecutor.submit(() ->
|
||||
{
|
||||
if (SshdPlugin.instance.getConfig().getString("Mode").equals("RPC") && command.startsWith("rpc"))
|
||||
if (SshdPlugin.GetInstance().Mode.equals("RPC") && command.startsWith("rpc"))
|
||||
{
|
||||
// NO ECHO NO PREAMBLE AND SHIT
|
||||
String cmd = command.substring("rpc".length() + 1, command.length());
|
||||
Bukkit.dispatchCommand(this.SshdCommandSender, cmd);
|
||||
CmdManager.process(this.SshdCommandSender, cmd);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -159,31 +165,31 @@ public class ConsoleShellFactory implements ShellFactory {
|
|||
// our plugin and the connected client.
|
||||
if (!mkpasswd)
|
||||
{
|
||||
SshdPlugin.instance.getLogger().info("<" + this.Username + "> " + command);
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command);
|
||||
SshdPlugin.GetInstance().logger.info("<" + this.Username + "> " + command);
|
||||
CmdManager.process(Sponge.getServer().getConsole(), command);
|
||||
}
|
||||
else
|
||||
{
|
||||
Bukkit.dispatchCommand(this.SshdCommandSender, command);
|
||||
CmdManager.process(this.SshdCommandSender, command);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
SshdPlugin.instance.getLogger().log(Level.SEVERE, "Error processing command from SSH", e);
|
||||
SshdPlugin.GetInstance().logger.error("Error processing command from SSH", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
SshdPlugin.instance.getLogger().log(Level.INFO, this.Username + " disconnected from SSH.");
|
||||
SshdPlugin.GetInstance().logger.info(this.Username + " disconnected from SSH.");
|
||||
callback.onExit(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void printPreamble(ConsoleReader cr) throws IOException
|
||||
{
|
||||
File f = new File(SshdPlugin.instance.getDataFolder(), "motd.txt");
|
||||
File f = new File(SshdPlugin.GetInstance().ConfigDir.toFile(), "motd.txt");
|
||||
try
|
||||
{
|
||||
BufferedReader br = new BufferedReader(new FileReader(f));
|
||||
|
@ -194,16 +200,26 @@ public class ConsoleShellFactory implements ShellFactory {
|
|||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
SshdPlugin.instance.getLogger().log(Level.WARNING, "Could not open " + f + ": File does not exist.");
|
||||
SshdPlugin.GetInstance().logger.warn("Could not open " + f + ": File does not exist.");
|
||||
// Not showing the SSH motd is not a fatal failure, let the session continue.
|
||||
}
|
||||
|
||||
// Doesn't really guarantee our actual system hostname but
|
||||
// it's better than not having one at all.
|
||||
cr.println("Connected to: " + InetAddress.getLocalHost().getHostName() + " (" + Bukkit.getServer().getName() + ")\r");
|
||||
cr.println(ConsoleLogFormatter.ColorizeString(Bukkit.getServer().getMotd()).replaceAll("\n", "\r\n"));
|
||||
Platform p = Sponge.getPlatform();
|
||||
MinecraftVersion mv = p.getMinecraftVersion();
|
||||
PluginContainer pc = p.getContainer(Platform.Component.API);
|
||||
String str = String.format(
|
||||
"Connected to: %s -- Minecraft %s (%s %s)",
|
||||
InetAddress.getLocalHost().getHostName(),
|
||||
mv.getName(),
|
||||
pc.getName(),
|
||||
pc.getVersion().orElse("<Unknown>"));
|
||||
|
||||
cr.println(str + "\r");
|
||||
cr.println(ConsoleLogFormatter.ColorizeString(Sponge.getServer().getMotd().toPlain()).replaceAll("\n", "\r\n"));
|
||||
cr.println("\r");
|
||||
cr.println("Type 'exit' to exit the shell." + "\r");
|
||||
cr.println("Type 'exit' or CTRL+D to exit the shell." + "\r");
|
||||
cr.println("===============================================" + "\r");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
package com.ryanmichela.sshd;
|
||||
|
||||
import jline.console.ConsoleReader;
|
||||
import org.apache.sshd.common.SshException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.logging.*;
|
||||
|
||||
/**
|
||||
* Copyright 2013 Ryan Michela
|
||||
*/
|
||||
public class FlushyStreamHandler extends StreamHandler {
|
||||
|
||||
private ConsoleReader reader;
|
||||
|
||||
public FlushyStreamHandler(OutputStream out, Formatter formatter, ConsoleReader reader) {
|
||||
super(out, formatter);
|
||||
this.reader = reader;
|
||||
setLevel(Level.INFO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void publish(LogRecord record) {
|
||||
record.setMessage(record.getMessage().replace("\n", "\n\r"));
|
||||
super.publish(record);
|
||||
flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void flush() {
|
||||
try {
|
||||
reader.print(ConsoleReader.RESET_LINE + "");
|
||||
reader.flush();
|
||||
super.flush();
|
||||
try {
|
||||
reader.drawLine();
|
||||
} catch (Throwable ex) {
|
||||
reader.getCursorBuffer().clear();
|
||||
}
|
||||
reader.flush();
|
||||
super.flush();
|
||||
} catch (SshException ex) {
|
||||
// do nothing
|
||||
} catch (IOException ex) {
|
||||
Logger.getLogger(FlushyStreamHandler.class.getName()).log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,92 +1,121 @@
|
|||
package com.ryanmichela.sshd;
|
||||
|
||||
/*
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
*/
|
||||
import java.util.Arrays;
|
||||
|
||||
import com.ryanmichela.sshd.Cryptography;
|
||||
import com.ryanmichela.sshd.SshdPlugin;
|
||||
|
||||
class MkpasswdCommand implements CommandExecutor
|
||||
import org.spongepowered.api.Sponge;
|
||||
import org.spongepowered.api.command.CommandException;
|
||||
import org.spongepowered.api.command.CommandResult;
|
||||
import org.spongepowered.api.command.CommandSource;
|
||||
import org.spongepowered.api.command.args.CommandContext;
|
||||
import org.spongepowered.api.command.args.GenericArguments;
|
||||
import org.spongepowered.api.command.spec.CommandExecutor;
|
||||
import org.spongepowered.api.command.spec.CommandSpec;
|
||||
import org.spongepowered.api.entity.living.player.Player;
|
||||
import org.spongepowered.api.event.command.TabCompleteEvent;
|
||||
import org.spongepowered.api.text.Text;
|
||||
|
||||
public class MkpasswdCommand implements CommandExecutor
|
||||
{
|
||||
// Because Spigot's failed syntax API is really less than ideal (you should be required to add a
|
||||
// SendSyntax function override), we're just always going to return true even for syntax failures
|
||||
// as we will handle the syntax message internally. This also lets us send the messages more
|
||||
// securely to the client without people knowing we're using the command. This prevents password
|
||||
// or hash leakages from the user to other connected users. Plus this syntax will show how
|
||||
// to both use the command and what hashes we support which is important for people who don't
|
||||
// know how to RTFM. - Justin
|
||||
private void SendSyntax(CommandSender sender, boolean invalid)
|
||||
private static CommandSpec cmdspec;
|
||||
public static void BuildCommand()
|
||||
{
|
||||
if (invalid)
|
||||
sender.sendMessage("\u00A7cInvalid Syntax\u00A7r");
|
||||
sender.sendMessage("\u00A7a/mkpasswd <help|hash> <password>\u00A7r");
|
||||
sender.sendMessage("\u00A79Supported Hashes: SHA256, PBKDF2, BCRYPT, PLAIN\u00A7r");
|
||||
CommandSpec pbkdf2 = CommandSpec.builder()
|
||||
.description(Text.of("PBKDF2 hashed password"))
|
||||
.permission("sshd.mkpasswd.pbkdf2")
|
||||
.arguments(GenericArguments.remainingJoinedStrings(Text.of("password")))
|
||||
.executor((CommandSource source, CommandContext args) -> {
|
||||
try
|
||||
{
|
||||
source.sendMessage(Text.of("\u00A79Your Hash: " + Cryptography.PBKDF2_HashPassword(args.<String>getOne("password").get())));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
return CommandResult.success();
|
||||
})
|
||||
.build();
|
||||
|
||||
CommandSpec bcrypt = CommandSpec.builder()
|
||||
.description(Text.of("BCrypt hashed password"))
|
||||
.permission("sshd.mkpasswd.bcrypt")
|
||||
.arguments(GenericArguments.remainingJoinedStrings(Text.of("password")))
|
||||
.executor((CommandSource source, CommandContext args) -> {
|
||||
try
|
||||
{
|
||||
source.sendMessage(Text.of("\u00A79Your Hash: " + Cryptography.BCrypt_HashPassword(args.<String>getOne("password").get())));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
return CommandResult.success();
|
||||
})
|
||||
.build();
|
||||
|
||||
CommandSpec sha256 = CommandSpec.builder()
|
||||
.description(Text.of("SHA256 hashed password"))
|
||||
.permission("sshd.mkpasswd.sha256")
|
||||
.arguments(GenericArguments.remainingJoinedStrings(Text.of("password")))
|
||||
.executor((CommandSource source, CommandContext args) -> {
|
||||
try
|
||||
{
|
||||
source.sendMessage(Text.of("\u00A79Your Hash: " + Cryptography.SHA256_HashPassword(args.<String>getOne("password").get())));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
return CommandResult.success();
|
||||
})
|
||||
.build();
|
||||
|
||||
// The plain text "encryption" method
|
||||
CommandSpec plain = CommandSpec.builder()
|
||||
.description(Text.of("Plain text password (insecure)"))
|
||||
.permission("sshd.mkpasswd.plain")
|
||||
.arguments(GenericArguments.remainingJoinedStrings(Text.of("password")))
|
||||
.executor((CommandSource source, CommandContext args) -> {
|
||||
source.sendMessage(Text.of("\u00A79Your Hash: \u00A7cIt's literally your unhashed password."));
|
||||
return CommandResult.success();
|
||||
})
|
||||
.build();
|
||||
|
||||
// the root "mkpasswd" command
|
||||
cmdspec = CommandSpec.builder()
|
||||
.description(Text.of("Create an SSHd password using hashes"))
|
||||
.extendedDescription(Text.of("Supported Hashes: SHA256, PBKDF2, BCRYPT, PLAIN"))
|
||||
.permission("sshd.mkpasswd")
|
||||
.child(plain, "plain")
|
||||
.child(sha256, "sha256")
|
||||
.child(bcrypt, "bcrypt")
|
||||
.child(pbkdf2, "pbkdf2")
|
||||
.executor(new MkpasswdCommand())
|
||||
.build();
|
||||
|
||||
// Register our command with Sponge.
|
||||
Sponge.getCommandManager().register(SshdPlugin.GetInstance(), cmdspec, "mkpasswd");
|
||||
}
|
||||
|
||||
// so sponge needed this, still figuring out the sponge API ~ Zach
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args)
|
||||
public CommandResult execute(CommandSource src, CommandContext args) throws CommandException
|
||||
{
|
||||
// If we're not mkpasswd, just fuck off.
|
||||
if (!label.equalsIgnoreCase("mkpasswd"))
|
||||
return false;
|
||||
|
||||
String algoritm, password;
|
||||
try
|
||||
{
|
||||
// Stupid bukkit, we have to concatenate the arguments together if they're using
|
||||
// spaces in their passwords otherwise it won't be as strong as it should be.
|
||||
algoritm = args[0];
|
||||
password = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
|
||||
if (password.trim().isEmpty()) // Shortcut to the catch statement below.
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
catch (ArrayIndexOutOfBoundsException e)
|
||||
{
|
||||
// ignore it.
|
||||
this.SendSyntax(sender, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean hasperm = (sender instanceof Player) ? ((Player)sender).hasPermission("sshd.mkpasswd") : true;
|
||||
|
||||
if (hasperm)
|
||||
{
|
||||
try
|
||||
{
|
||||
String hash = "";
|
||||
// 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...");
|
||||
return true;
|
||||
}
|
||||
else if (algoritm.equalsIgnoreCase("pbkdf2"))
|
||||
hash = Cryptography.PBKDF2_HashPassword(password);
|
||||
else if (algoritm.equalsIgnoreCase("bcrypt"))
|
||||
hash = Cryptography.BCrypt_HashPassword(password);
|
||||
else if (algoritm.equalsIgnoreCase("sha256"))
|
||||
hash = Cryptography.SHA256_HashPassword(password);
|
||||
else
|
||||
{
|
||||
this.SendSyntax(sender, !algoritm.equalsIgnoreCase("help"));
|
||||
return true;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
// This command doesn't do anything.
|
||||
src.sendMessage(Text.of("\u00A7a/mkpasswd <hash> <password...>\u00A7r"));
|
||||
src.sendMessage(Text.of("\u00A79Supported Hashes: SHA256, PBKDF2, BCRYPT, PLAIN\u00A7r"));
|
||||
return CommandResult.success();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.ryanmichela.sshd;
|
||||
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.apache.sshd.common.config.keys.AuthorizedKeyEntry;
|
||||
import org.apache.sshd.common.config.keys.PublicKeyEntryResolver;
|
||||
import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
|
||||
|
@ -27,7 +26,7 @@ public class PublicKeyAuthenticator implements PublickeyAuthenticator
|
|||
{
|
||||
byte[] keyBytes = key.getEncoded();
|
||||
File keyFile = new File(authorizedKeysDir, username);
|
||||
Integer tries = SshdPlugin.instance.getConfig().getInt("LoginRetries");
|
||||
Integer tries = SshdPlugin.GetInstance().LoginRetries;
|
||||
|
||||
if (keyFile.exists())
|
||||
{
|
||||
|
@ -47,7 +46,7 @@ public class PublicKeyAuthenticator implements PublickeyAuthenticator
|
|||
}
|
||||
else
|
||||
{
|
||||
SshdPlugin.instance.getLogger().info(
|
||||
SshdPlugin.GetInstance().logger.info(
|
||||
username + " failed authentication via SSH session using key file " + keyFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
|
@ -60,7 +59,7 @@ public class PublicKeyAuthenticator implements PublickeyAuthenticator
|
|||
if (this.FailCounts.get(username) >= tries)
|
||||
{
|
||||
this.FailCounts.put(username, 0);
|
||||
SshdPlugin.instance.getLogger().info("Too many failures for " + username + ", disconnecting.");
|
||||
SshdPlugin.GetInstance().logger.info("Too many failures for " + username + ", disconnecting.");
|
||||
session.close(true);
|
||||
}
|
||||
|
||||
|
@ -68,12 +67,12 @@ public class PublicKeyAuthenticator implements PublickeyAuthenticator
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
SshdPlugin.instance.getLogger().severe("Failed to process public key " + keyFile.getAbsolutePath() + " " + e.getMessage());
|
||||
SshdPlugin.GetInstance().logger.error("Failed to process public key " + keyFile.getAbsolutePath() + " " + e.getMessage());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SshdPlugin.instance.getLogger().warning("Could not locate public key for " + username
|
||||
SshdPlugin.GetInstance().logger.error("Could not locate public key for " + username
|
||||
+ ". Make sure the user's key is named the same as their user name "
|
||||
+ "without a file extension.");
|
||||
}
|
||||
|
|
|
@ -1,96 +0,0 @@
|
|||
package com.ryanmichela.sshd;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
/**
|
||||
* Copyright 2013 Ryan Michela
|
||||
*/
|
||||
public class ReflectionUtil {
|
||||
|
||||
public static void setProtectedValue(Object o, String field, Object newValue) {
|
||||
setProtectedValue(o.getClass(), o, field, newValue);
|
||||
}
|
||||
|
||||
public static void setProtectedValue(Class c, String field, Object newValue) {
|
||||
setProtectedValue(c, null, field, newValue);
|
||||
}
|
||||
|
||||
public static void setProtectedValue(Class c, Object o, String field, Object newValue) {
|
||||
try {
|
||||
|
||||
Field f = c.getDeclaredField(field);
|
||||
|
||||
f.setAccessible(true);
|
||||
|
||||
Field modifiersField = Field.class.getDeclaredField("modifiers");
|
||||
modifiersField.setAccessible(true);
|
||||
modifiersField.setInt(f, f.getModifiers() & ~Modifier.FINAL);
|
||||
|
||||
f.set(o, newValue);
|
||||
} catch (NoSuchFieldException | IllegalAccessException ex) {
|
||||
System.out.println("*** " + c.getName() + ":" + ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T getProtectedValue(Object obj, String fieldName) {
|
||||
try {
|
||||
Class c = obj.getClass();
|
||||
while (c != Object.class) {
|
||||
Field[] fields = c.getDeclaredFields();
|
||||
for (Field f : fields) {
|
||||
if (f.getName() == fieldName) {
|
||||
f.setAccessible(true);
|
||||
return (T) f.get(obj);
|
||||
}
|
||||
}
|
||||
c = c.getSuperclass();
|
||||
}
|
||||
System.out.println("*** " + obj.getClass().getName() + ":No such field");
|
||||
return null;
|
||||
} catch (Exception ex) {
|
||||
System.out.println("*** " + obj.getClass().getName() + ":" + ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T getProtectedValue(Class c, String field) {
|
||||
try {
|
||||
Field f = c.getDeclaredField(field);
|
||||
f.setAccessible(true);
|
||||
return (T) f.get(c);
|
||||
} catch (Exception ex) {
|
||||
System.out.println("*** " + c.getName() + ":" + ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Object invokeProtectedMethod(Class c, String method, Object... args) {
|
||||
return invokeProtectedMethod(c, null, method, args);
|
||||
}
|
||||
|
||||
public static Object invokeProtectedMethod(Object o, String method, Object... args) {
|
||||
return invokeProtectedMethod(o.getClass(), o, method, args);
|
||||
}
|
||||
|
||||
public static Object invokeProtectedMethod(Class c, Object o, String method, Object... args) {
|
||||
try {
|
||||
Class[] pTypes = new Class[args.length];
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if (args[i] instanceof Integer) {
|
||||
pTypes[i] = int.class;
|
||||
} else {
|
||||
pTypes[i] = args[i].getClass();
|
||||
}
|
||||
}
|
||||
|
||||
Method m = c.getDeclaredMethod(method, pTypes);
|
||||
m.setAccessible(true);
|
||||
return m.invoke(o, args);
|
||||
} catch (Exception ex) {
|
||||
System.out.println("*** " + c.getName() + "." + method + "(): " + ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,18 @@
|
|||
package com.ryanmichela.sshd;
|
||||
|
||||
import com.ryanmichela.sshd.utils.Config;
|
||||
import org.spongepowered.api.Sponge;
|
||||
import org.spongepowered.api.command.spec.CommandSpec;
|
||||
import org.spongepowered.api.config.DefaultConfig;
|
||||
import org.spongepowered.api.config.ConfigDir;
|
||||
import org.spongepowered.api.plugin.Plugin;
|
||||
import org.spongepowered.api.event.Listener;
|
||||
import org.spongepowered.api.event.game.state.GameStartedServerEvent;
|
||||
|
||||
import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory;
|
||||
import org.apache.sshd.server.SshServer;
|
||||
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
|
||||
import org.apache.sshd.server.subsystem.sftp.SftpSubsystemFactory;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import com.ryanmichela.sshd.ConsoleShellFactory;
|
||||
import com.ryanmichela.sshd.MkpasswdCommand;
|
||||
|
@ -14,29 +22,71 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Collections;
|
||||
import java.util.logging.Level;
|
||||
|
||||
/**
|
||||
* Copyright 2013 Ryan Michela
|
||||
*/
|
||||
public
|
||||
class SshdPlugin extends JavaPlugin
|
||||
import com.google.inject.Inject;
|
||||
import org.slf4j.Logger;
|
||||
import org.spongepowered.api.text.Text;
|
||||
|
||||
@Plugin(
|
||||
id = "sshd",
|
||||
name = "Minecraft-SSHD",
|
||||
version = "1.3.7",
|
||||
description = "Sponge port for Minecraft-SSHD. SSH for your minecraft server!",
|
||||
authors={"Justin Crawford", "Zachery Coleman"}
|
||||
)
|
||||
public class SshdPlugin
|
||||
{
|
||||
String ListenAddress = "";
|
||||
Integer Port = 1025;
|
||||
String Mode = "";
|
||||
Boolean EnableSFTP = true;
|
||||
Integer LoginRetries = 3;
|
||||
String PasswordType = "";
|
||||
// Credentials
|
||||
|
||||
private SshServer sshd;
|
||||
public static SshdPlugin instance;
|
||||
private SshServer sshd;
|
||||
private static SshdPlugin instance;
|
||||
|
||||
@Override public void onLoad()
|
||||
@Inject
|
||||
public Logger logger;
|
||||
|
||||
@Inject
|
||||
@DefaultConfig(sharedRoot = false)
|
||||
public Path DefaultConfig;
|
||||
|
||||
@Inject
|
||||
@ConfigDir(sharedRoot = false)
|
||||
public Path ConfigDir;
|
||||
|
||||
public Config config;
|
||||
|
||||
@Listener
|
||||
public void onServerStart(GameStartedServerEvent event)
|
||||
{
|
||||
saveDefaultConfig();
|
||||
File authorizedKeys = new File(getDataFolder(), "authorized_keys");
|
||||
instance = this;
|
||||
// Parse our config
|
||||
config = new Config();
|
||||
config.setup();
|
||||
|
||||
// Make sure our authorized_keys folder exists
|
||||
File authorizedKeys = new File(this.ConfigDir.toFile(), "authorized_keys");
|
||||
if (!authorizedKeys.exists())
|
||||
authorizedKeys.mkdirs();
|
||||
|
||||
// Now include it in our dealio here
|
||||
this.Mode = config.configNode.getNode("Mode").getString();
|
||||
this.PasswordType = config.configNode.getNode("PasswordType").getString();
|
||||
this.ListenAddress = config.configNode.getNode("ListenAddress").getString();
|
||||
this.Port = config.configNode.getNode("Port").getInt();
|
||||
this.LoginRetries = config.configNode.getNode("LoginRetries").getInt();
|
||||
this.EnableSFTP = config.configNode.getNode("EnableSFTP").getBoolean();
|
||||
|
||||
try
|
||||
{
|
||||
File motd = new File(getDataFolder(), "motd.txt");
|
||||
File motd = new File(this.ConfigDir.toFile(), "motd.txt");
|
||||
if (!motd.exists())
|
||||
{
|
||||
InputStream link = (getClass().getResourceAsStream("/motd.txt"));
|
||||
|
@ -48,37 +98,25 @@ class SshdPlugin extends JavaPlugin
|
|||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// Don't go any lower than INFO or SSHD will cause a stack overflow exception.
|
||||
// SSHD will log that it wrote bites to the output stream, which writes
|
||||
// bytes to the output stream - ad nauseaum.
|
||||
getLogger().setLevel(Level.INFO);
|
||||
}
|
||||
|
||||
@Override public void onEnable()
|
||||
{
|
||||
instance = this;
|
||||
|
||||
sshd = SshServer.setUpDefaultServer();
|
||||
sshd.setPort(getConfig().getInt("Port", 1025));
|
||||
String host = getConfig().getString("ListenAddress", "all");
|
||||
sshd.setHost(host.equals("all") ? null : host);
|
||||
sshd.setPort(this.Port);
|
||||
sshd.setHost(this.ListenAddress.equals("all") ? null : this.ListenAddress);
|
||||
|
||||
File hostKey = new File(getDataFolder(), "hostkey");
|
||||
File authorizedKeys = new File(getDataFolder(), "authorized_keys");
|
||||
File hostKey = new File(this.ConfigDir.toFile(), "hostkey");
|
||||
|
||||
sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(hostKey.toPath()));
|
||||
sshd.setShellFactory(new ConsoleShellFactory());
|
||||
sshd.setPasswordAuthenticator(new ConfigPasswordAuthenticator());
|
||||
sshd.setPublickeyAuthenticator(new PublicKeyAuthenticator(authorizedKeys));
|
||||
|
||||
if (getConfig().getBoolean("EnableSFTP"))
|
||||
if (this.EnableSFTP)
|
||||
{
|
||||
sshd.setSubsystemFactories(Collections.singletonList(new SftpSubsystemFactory()));
|
||||
sshd.setFileSystemFactory(
|
||||
new VirtualFileSystemFactory(FileSystems.getDefault().getPath(getDataFolder().getAbsolutePath()).getParent().getParent()));
|
||||
sshd.setFileSystemFactory(new VirtualFileSystemFactory(this.ConfigDir.getParent().getParent()));
|
||||
}
|
||||
|
||||
this.getCommand("mkpasswd").setExecutor(new MkpasswdCommand());
|
||||
MkpasswdCommand.BuildCommand();
|
||||
|
||||
sshd.setCommandFactory(new ConsoleCommandFactory());
|
||||
try
|
||||
|
@ -87,19 +125,19 @@ class SshdPlugin extends JavaPlugin
|
|||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
getLogger().log(Level.SEVERE, "Failed to start SSH server! ", e);
|
||||
logger.error("Failed to start SSH server! ", e);
|
||||
}
|
||||
|
||||
logger.info("Loaded Minecraft-SSHD.");
|
||||
}
|
||||
|
||||
@Override public void onDisable()
|
||||
public static SshdPlugin GetInstance()
|
||||
{
|
||||
try
|
||||
{
|
||||
sshd.stop();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public Logger GetLogger()
|
||||
{
|
||||
return this.logger;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,48 +1,73 @@
|
|||
package com.ryanmichela.sshd;
|
||||
|
||||
import org.apache.logging.log4j.Level;
|
||||
import org.apache.logging.log4j.core.Appender;
|
||||
import org.apache.logging.log4j.core.ErrorHandler;
|
||||
import org.apache.logging.log4j.core.Layout;
|
||||
import org.apache.logging.log4j.core.LogEvent;
|
||||
import org.apache.logging.log4j.core.layout.PatternLayout;
|
||||
|
||||
import jline.console.ConsoleReader;
|
||||
import org.apache.sshd.common.SshException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.LogRecord;
|
||||
import java.util.logging.StreamHandler;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* Copyright 2014 Ryan Michela
|
||||
*/
|
||||
public class StreamHandlerAppender implements Appender {
|
||||
|
||||
private StreamHandler streamHandler;
|
||||
public class StreamHandlerAppender implements Appender
|
||||
{
|
||||
private ConsoleReader console;
|
||||
private UUID uuid;
|
||||
private PatternLayout MinecraftLayout = PatternLayout.newBuilder().withPattern("%highlightError{[%d{HH:mm:ss} %level] [%logger]: %minecraftFormatting{%msg}%xEx}").build();
|
||||
private PatternLayout MojangLayout = PatternLayout.newBuilder().withPattern("%highlightError{[%d{HH:mm:ss} %level]: %minecraftFormatting{%msg}%xEx}").build();
|
||||
|
||||
public StreamHandlerAppender(StreamHandler streamHandler) {
|
||||
this.streamHandler = streamHandler;
|
||||
public StreamHandlerAppender(ConsoleReader console)
|
||||
{
|
||||
this.console = console;
|
||||
uuid = UUID.randomUUID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void append(LogEvent logEvent) {
|
||||
java.util.logging.Level level;
|
||||
|
||||
if (logEvent.getLevel().equals(org.apache.logging.log4j.Level.DEBUG)) {
|
||||
level = java.util.logging.Level.FINE;
|
||||
} else if (logEvent.getLevel().equals(org.apache.logging.log4j.Level.INFO)) {
|
||||
level = java.util.logging.Level.INFO;
|
||||
} else if (logEvent.getLevel().equals(org.apache.logging.log4j.Level.WARN)) {
|
||||
level = java.util.logging.Level.WARNING;
|
||||
} else if (logEvent.getLevel().equals(org.apache.logging.log4j.Level.ERROR)) {
|
||||
level = java.util.logging.Level.SEVERE;
|
||||
} else {
|
||||
level = java.util.logging.Level.INFO;
|
||||
public void append(LogEvent logEvent)
|
||||
{
|
||||
if (logEvent.getLevel() == Level.DEBUG || logEvent.getLevel() == Level.TRACE)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
// Delete the jline's `> ` character
|
||||
this.console.print(ConsoleReader.BACKSPACE + "" + ConsoleReader.BACKSPACE);
|
||||
// Print our message
|
||||
if (logEvent.getLoggerName().matches("net\\.minecraft\\..*|com\\.mojang\\..*"))
|
||||
this.console.println(ConsoleLogFormatter.ColorizeString(this.MojangLayout.toSerializable(logEvent)).replaceAll("\n", "\r\n") + "\r");
|
||||
else
|
||||
this.console.println(ConsoleLogFormatter.ColorizeString(this.MinecraftLayout.toSerializable(logEvent)).replaceAll("\n", "\r\n") + "\r");
|
||||
// Reset the console (colors, formatting, etc)
|
||||
this.console.print(ConsoleReader.RESET_LINE + "");
|
||||
try
|
||||
{
|
||||
// Attempt to draw new console line
|
||||
this.console.drawLine();
|
||||
}
|
||||
catch (Throwable ex)
|
||||
{
|
||||
this.console.getCursorBuffer().clear();
|
||||
}
|
||||
// Push it to the end user.
|
||||
this.console.flush();
|
||||
}
|
||||
catch (SshException ex)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
String message = logEvent.getMessage().getFormattedMessage();
|
||||
|
||||
|
||||
LogRecord logRecord = new LogRecord(level, message);
|
||||
streamHandler.publish(logRecord);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,38 +1,50 @@
|
|||
package com.ryanmichela.sshd.implementations;
|
||||
|
||||
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 com.ryanmichela.sshd.ConsoleShellFactory;
|
||||
import com.ryanmichela.sshd.ConsoleLogFormatter;
|
||||
import org.spongepowered.api.command.source.ConsoleSource;
|
||||
import org.checkerframework.checker.nullness.Opt;
|
||||
import org.spongepowered.api.command.CommandSource;
|
||||
import org.spongepowered.api.text.Text;
|
||||
import org.spongepowered.api.text.channel.MessageChannel;
|
||||
import org.spongepowered.api.service.permission.Subject;
|
||||
import org.spongepowered.api.service.permission.SubjectCollection;
|
||||
import org.spongepowered.api.service.permission.SubjectData;
|
||||
import org.spongepowered.api.service.permission.SubjectReference;
|
||||
import org.spongepowered.api.service.context.Context;
|
||||
import org.spongepowered.api.util.Tristate;
|
||||
import jline.console.ConsoleReader;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import java.util.Optional;
|
||||
import java.util.List;
|
||||
|
||||
public class SSHDCommandSender implements ConsoleCommandSender, CommandSender
|
||||
// This is gonna be a mess.
|
||||
public class SSHDCommandSender implements ConsoleSource
|
||||
{
|
||||
private final PermissibleBase perm = new PermissibleBase(this);
|
||||
private final SSHDConversationTracker conversationTracker = new SSHDConversationTracker();
|
||||
private MessageChannel mc = MessageChannel.TO_CONSOLE;
|
||||
private Subject subjectDelegate;
|
||||
// Set by the upstream allocating function
|
||||
public ConsoleShellFactory.ConsoleShell console;
|
||||
private UUID uuid = UUID.randomUUID();
|
||||
|
||||
// This is an override for Sponge to work with the SSH consoles.
|
||||
@Override
|
||||
public void sendMessage(Text message)
|
||||
{
|
||||
this.sendRawMessage(message.toPlain());
|
||||
}
|
||||
|
||||
// Back port from Spigot/BungeeCord-style API calls.
|
||||
public void sendMessage(String message)
|
||||
{
|
||||
this.sendRawMessage(message + "\r");
|
||||
this.sendRawMessage(message);
|
||||
}
|
||||
|
||||
public void sendRawMessage(String message)
|
||||
|
@ -42,8 +54,9 @@ public class SSHDCommandSender implements ConsoleCommandSender, CommandSender
|
|||
return;
|
||||
try
|
||||
{
|
||||
this.console.ConsoleReader.println(ConsoleLogFormatter.ColorizeString(message).replace("\n", "\n\r"));
|
||||
this.console.ConsoleReader.print(this.console.ConsoleReader.RESET_LINE + "");
|
||||
this.console.ConsoleReader.print(ConsoleReader.BACKSPACE + "" + ConsoleReader.BACKSPACE);
|
||||
this.console.ConsoleReader.println(ConsoleLogFormatter.ColorizeString(message).replaceAll("\n", "\n\r") + "\r");
|
||||
this.console.ConsoleReader.print(ConsoleReader.RESET_LINE + "");
|
||||
this.console.ConsoleReader.flush();
|
||||
try
|
||||
{
|
||||
|
@ -57,96 +70,109 @@ public class SSHDCommandSender implements ConsoleCommandSender, CommandSender
|
|||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
SshdPlugin.instance.getLogger().log(Level.SEVERE, "Error sending message to SSHDCommandSender", e);
|
||||
SshdPlugin.GetInstance().logger.error("Error sending message to SSHDCommandSender", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendMessage(String[] messages) {
|
||||
public void sendMessage(String[] messages)
|
||||
{
|
||||
Arrays.asList(messages).forEach(this::sendMessage);
|
||||
}
|
||||
|
||||
public MessageChannel getMessageChannel()
|
||||
{
|
||||
return mc;
|
||||
}
|
||||
|
||||
public void setMessageChannel(MessageChannel channel)
|
||||
{
|
||||
mc = channel;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return "SSHD Console";
|
||||
}
|
||||
|
||||
public boolean isOp() {
|
||||
return true;
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return uuid.toString();
|
||||
}
|
||||
|
||||
public void setOp(boolean value) {
|
||||
throw new UnsupportedOperationException("Cannot change operator status of server console");
|
||||
@Override
|
||||
public Set<Context> getActiveContexts()
|
||||
{
|
||||
// No clue what any of this does but sponge needs it to work with this class. - Justin
|
||||
Set<Context> set = new HashSet<Context>();
|
||||
set.add(new Context(Context.USER_KEY, "SSHD"));
|
||||
return set;
|
||||
}
|
||||
|
||||
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() {
|
||||
@Override
|
||||
public boolean isSubjectDataPersisted()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
public Server getServer() {
|
||||
return Bukkit.getServer();
|
||||
@Override
|
||||
public boolean isChildOf(Set<Context> contexts, SubjectReference parent)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubjectData getTransientSubjectData()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubjectData getSubjectData()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tristate getPermissionValue(Set<Context> contexts, String permission)
|
||||
{
|
||||
// We're allowed to view all permissions.
|
||||
return Tristate.TRUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SubjectReference> getParents(Set<Context> contexts)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getOption(Set<Context> contexts, String key)
|
||||
{
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubjectCollection getContainingCollection()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<CommandSource> getCommandSource()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return Optional.of(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubjectReference asSubjectReference()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
package com.ryanmichela.sshd.implementations;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.conversations.Conversation;
|
||||
import org.bukkit.conversations.ConversationAbandonedEvent;
|
||||
import org.bukkit.conversations.ManuallyAbandonedConversationCanceller;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class SSHDConversationTracker {
|
||||
private LinkedList<Conversation> conversationQueue = new LinkedList<>();
|
||||
|
||||
synchronized boolean beginConversation(Conversation conversation) {
|
||||
if (!this.conversationQueue.contains(conversation)) {
|
||||
this.conversationQueue.addLast(conversation);
|
||||
if (this.conversationQueue.getFirst() == conversation) {
|
||||
conversation.begin();
|
||||
conversation.outputNextPrompt();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
synchronized void abandonConversation(Conversation conversation, ConversationAbandonedEvent details) {
|
||||
if (!this.conversationQueue.isEmpty()) {
|
||||
if (this.conversationQueue.getFirst() == conversation) {
|
||||
conversation.abandon(details);
|
||||
}
|
||||
|
||||
if (this.conversationQueue.contains(conversation)) {
|
||||
this.conversationQueue.remove(conversation);
|
||||
}
|
||||
|
||||
if (!this.conversationQueue.isEmpty()) {
|
||||
this.conversationQueue.getFirst().outputNextPrompt();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public synchronized void abandonAllConversations() {
|
||||
LinkedList<Conversation> oldQueue = this.conversationQueue;
|
||||
this.conversationQueue = new LinkedList<>();
|
||||
|
||||
for (Conversation conversation : oldQueue) {
|
||||
try {
|
||||
conversation.abandon(new ConversationAbandonedEvent(conversation, new ManuallyAbandonedConversationCanceller()));
|
||||
} catch (Throwable var5) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "Unexpected exception while abandoning a conversation", var5);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
synchronized void acceptConversationInput(String input) {
|
||||
if (this.isConversing()) {
|
||||
Conversation conversation = this.conversationQueue.getFirst();
|
||||
|
||||
try {
|
||||
conversation.acceptInput(input);
|
||||
} catch (Throwable var4) {
|
||||
conversation.getContext().getPlugin().getLogger().log(Level.WARNING, String.format("Plugin %s generated an exception whilst handling conversation input", conversation.getContext().getPlugin().getDescription().getFullName()), var4);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
synchronized boolean isConversing() {
|
||||
return !this.conversationQueue.isEmpty();
|
||||
}
|
||||
|
||||
public synchronized boolean isConversingModaly() {
|
||||
return this.isConversing() && this.conversationQueue.getFirst().isModal();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package com.ryanmichela.sshd.utils;
|
||||
|
||||
import ninja.leaping.configurate.loader.ConfigurationLoader;
|
||||
import ninja.leaping.configurate.commented.CommentedConfigurationNode;
|
||||
import ninja.leaping.configurate.hocon.HoconConfigurationLoader;
|
||||
import org.spongepowered.api.config.DefaultConfig;
|
||||
import com.google.inject.Inject;
|
||||
import com.ryanmichela.sshd.SshdPlugin;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class Config
|
||||
{
|
||||
// Give us a config!
|
||||
@Inject
|
||||
@DefaultConfig(sharedRoot = false)
|
||||
// idk what to do with this one.
|
||||
private ConfigurationLoader<CommentedConfigurationNode> configLoader = HoconConfigurationLoader.builder().setPath(SshdPlugin.GetInstance().DefaultConfig).build();
|
||||
|
||||
public CommentedConfigurationNode configNode;
|
||||
|
||||
public void setup()
|
||||
{
|
||||
// I'm not sure if this will even work, the sponge config API is confusing.
|
||||
if (!Files.exists(SshdPlugin.GetInstance().DefaultConfig))
|
||||
{
|
||||
try
|
||||
{
|
||||
Files.createFile(SshdPlugin.GetInstance().DefaultConfig);
|
||||
this.load();
|
||||
this.populate();
|
||||
this.save();
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
else
|
||||
this.load();
|
||||
}
|
||||
|
||||
public void load()
|
||||
{
|
||||
try
|
||||
{
|
||||
configNode = this.configLoader.load();
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void save()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.configLoader.save(this.configNode);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void populate()
|
||||
{
|
||||
this.configNode.getNode("ListenAddress").setValue("all").setComment
|
||||
("The IP addresses(s) the SSH server will listen on. Use a comma separated list for multiple addresses.\n" +
|
||||
"Leave as \"all\" for all addresses.");
|
||||
this.configNode.getNode("Port").setValue("1025").setComment(
|
||||
"The port the SSH server will listen on. Note that anything above 1024 will require you to run\n" +
|
||||
"the whole minecraft server with elevated privileges, this is not recommended and you should\n" +
|
||||
"use iptables to route packets from a lower port.");
|
||||
this.configNode.getNode("Mode").setValue("DEFAULT").setComment("Operational mode. Don't touch if you don't know what you're doing. Can be either DEFAULT or RPC");
|
||||
this.configNode.getNode("EnableSFTP").setValue("true").setComment(
|
||||
"Enable built-in SFTP server or not. You'll be able to connect and upload/download files via SFTP protocol.\n" +
|
||||
"Might be useful for testing purposes as well , i. e. docker containers.");
|
||||
this.configNode.getNode("LoginRetries").setValue("3").setComment(
|
||||
"Number of times a person can fail to use an SSH key or enter a password\n" +
|
||||
"before it terminates the connection.");
|
||||
|
||||
this.configNode.getNode("PasswordType").setValue("bcrypt").setComment
|
||||
("########################################################################################\n" +
|
||||
"By default, only public key authentication is enabled. This is the most secure mode.\n" +
|
||||
"To authorize a user to login with their public key, install their key using the\n" +
|
||||
"OpenSSH authorized_keys file format in the authorized_users directory. Name the key\n" +
|
||||
"file with the user's username and no extension. Note: If you want to let a user have\n" +
|
||||
"many keys, you can append the keys to their file in authorized_users.\n" +
|
||||
"########################################################################################\n" +
|
||||
"For less secure username and password based authentication, complete the sections below.\n" +
|
||||
"\n" +
|
||||
"Type of hashing to use for the passwords below.\n" +
|
||||
"Options are: PLAIN (insecure), bcrypt, pbkdf2, sha256\n" +
|
||||
"\n" +
|
||||
"You can use the console/in-game command `/mkpasswd [hash] PASSWORD` to\n" +
|
||||
"generate a password hash string then copy it for your passwords below.\n" +
|
||||
"You can also use `/mkpasswd help` to see what algorithms are supported.");
|
||||
|
||||
this.configNode.getNode("Credentials").setComment("Associate each username with a password hash (or the password if the PasswordType is set to PLAIN)");
|
||||
this.configNode.getNode("Credentials", "user1", "password").setValue("MySecretPassword");
|
||||
this.configNode.getNode("Credentials", "user2", "password").setValue("MyBestFriendsPassword");
|
||||
}
|
||||
}
|
|
@ -1,350 +0,0 @@
|
|||
package org.slf4j.impl;
|
||||
|
||||
import com.ryanmichela.sshd.SshdPlugin;
|
||||
import org.slf4j.ILoggerFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.Marker;
|
||||
import org.slf4j.helpers.FormattingTuple;
|
||||
import org.slf4j.helpers.MessageFormatter;
|
||||
|
||||
import java.util.logging.Level;
|
||||
|
||||
/**
|
||||
* Copyright 2013 Ryan Michela
|
||||
*/
|
||||
public class PluginSlf4jFactory implements ILoggerFactory {
|
||||
@Override
|
||||
public Logger getLogger(String name) {
|
||||
return new PluginSlf4jAdapter(name);
|
||||
}
|
||||
|
||||
public class PluginSlf4jAdapter implements Logger {
|
||||
private String name;
|
||||
|
||||
private boolean isEnabled(Level level) {
|
||||
return SshdPlugin.instance != null && SshdPlugin.instance.getLogger().isLoggable(level);
|
||||
}
|
||||
|
||||
private void log(Level level, String s, Object[] objects) {
|
||||
if (SshdPlugin.instance != null && isEnabled(level)) {
|
||||
FormattingTuple ft = MessageFormatter.arrayFormat(s, objects);
|
||||
SshdPlugin.instance.getLogger().log(level, ft.getMessage(), ft.getThrowable());
|
||||
}
|
||||
}
|
||||
|
||||
private void log(Level level, String s, Throwable throwable) {
|
||||
if (SshdPlugin.instance != null && isEnabled(level)) {
|
||||
SshdPlugin.instance.getLogger().log(level, s, throwable);
|
||||
}
|
||||
}
|
||||
|
||||
public PluginSlf4jAdapter(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTraceEnabled() {
|
||||
return isEnabled(Level.FINEST);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String s) {
|
||||
trace(s, new Object[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String s, Object o) {
|
||||
trace(s, new Object[]{o});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String s, Object o, Object o1) {
|
||||
trace(s, new Object[]{o, o1});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String s, Object[] objects) {
|
||||
log(Level.FINEST, s, objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(String s, Throwable throwable) {
|
||||
log(Level.FINEST, s, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTraceEnabled(Marker marker) {
|
||||
return isTraceEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Marker marker, String s) {
|
||||
trace(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Marker marker, String s, Object o) {
|
||||
trace(s, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Marker marker, String s, Object o, Object o1) {
|
||||
trace(s, o, o1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Marker marker, String s, Object[] objects) {
|
||||
trace(s, objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void trace(Marker marker, String s, Throwable throwable) {
|
||||
trace(s, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugEnabled() {
|
||||
return isEnabled(Level.FINE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String s) {
|
||||
debug(s, new Object[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String s, Object o) {
|
||||
debug(s, new Object[]{o});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String s, Object o, Object o1) {
|
||||
debug(s, new Object[]{o, o1});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String s, Object[] objects) {
|
||||
log(Level.FINE, s, objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(String s, Throwable throwable) {
|
||||
log(Level.FINE, s, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDebugEnabled(Marker marker) {
|
||||
return isDebugEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Marker marker, String s) {
|
||||
debug(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Marker marker, String s, Object o) {
|
||||
debug(s, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Marker marker, String s, Object o, Object o1) {
|
||||
debug(s, o, o1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Marker marker, String s, Object[] objects) {
|
||||
debug(s, objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void debug(Marker marker, String s, Throwable throwable) {
|
||||
debug(s, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInfoEnabled() {
|
||||
return isEnabled(Level.INFO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String s) {
|
||||
info(s, new Object[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String s, Object o) {
|
||||
info(s, new Object[]{o});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String s, Object o, Object o1) {
|
||||
info(s, new Object[]{o, o1});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String s, Object[] objects) {
|
||||
log(Level.INFO, s, objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(String s, Throwable throwable) {
|
||||
log(Level.INFO, s, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInfoEnabled(Marker marker) {
|
||||
return isInfoEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Marker marker, String s) {
|
||||
info(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Marker marker, String s, Object o) {
|
||||
info(s, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Marker marker, String s, Object o, Object o1) {
|
||||
info(s, o, o1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Marker marker, String s, Object[] objects) {
|
||||
info(s, objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void info(Marker marker, String s, Throwable throwable) {
|
||||
info(s, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWarnEnabled() {
|
||||
return isEnabled(Level.WARNING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String s) {
|
||||
warn(s, new Object[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String s, Object o) {
|
||||
warn(s, new Object[]{o});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String s, Object o, Object o1) {
|
||||
warn(s, new Object[]{o, o1});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String s, Object[] objects) {
|
||||
log(Level.WARNING, s, objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(String s, Throwable throwable) {
|
||||
log(Level.WARNING, s, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWarnEnabled(Marker marker) {
|
||||
return isWarnEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Marker marker, String s) {
|
||||
warn(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Marker marker, String s, Object o) {
|
||||
warn(s, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Marker marker, String s, Object o, Object o1) {
|
||||
warn(s, o, o1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Marker marker, String s, Object[] objects) {
|
||||
warn(s, objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void warn(Marker marker, String s, Throwable throwable) {
|
||||
warn(s, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isErrorEnabled() {
|
||||
return isEnabled(Level.SEVERE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String s) {
|
||||
error(s, new Object[]{});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String s, Object o) {
|
||||
error(s, new Object[]{o});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String s, Object o, Object o1) {
|
||||
error(s, new Object[]{o, o1});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String s, Object[] objects) {
|
||||
log(Level.SEVERE, s, objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(String s, Throwable throwable) {
|
||||
log(Level.SEVERE, s, throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isErrorEnabled(Marker marker) {
|
||||
return isErrorEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Marker marker, String s) {
|
||||
error(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Marker marker, String s, Object o) {
|
||||
error(s, o);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Marker marker, String s, Object o, Object o1) {
|
||||
error(s, o, o1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Marker marker, String s, Object[] objects) {
|
||||
error(s, objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void error(Marker marker, String s, Throwable throwable) {
|
||||
error(s, throwable);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
/**
|
||||
* Copyright (c) 2004-2011 QOS.ch
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*/
|
||||
package org.slf4j.impl;
|
||||
|
||||
import org.slf4j.ILoggerFactory;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.slf4j.spi.LoggerFactoryBinder;
|
||||
|
||||
/**
|
||||
* The binding of {@link LoggerFactory} class with an actual instance of
|
||||
* {@link ILoggerFactory} is performed using information returned by this class.
|
||||
*
|
||||
* @author Ceki Gülcü
|
||||
*/
|
||||
public class StaticLoggerBinder implements LoggerFactoryBinder {
|
||||
|
||||
/**
|
||||
* The unique instance of this class.
|
||||
*
|
||||
*/
|
||||
private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder();
|
||||
|
||||
/**
|
||||
* Return the singleton of this class.
|
||||
*
|
||||
* @return the StaticLoggerBinder singleton
|
||||
*/
|
||||
public static final StaticLoggerBinder getSingleton() {
|
||||
return SINGLETON;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Declare the version of the SLF4J API this implementation is compiled against.
|
||||
* The value of this field is usually modified with each release.
|
||||
*/
|
||||
// to avoid constant folding by the compiler, this field must *not* be final
|
||||
public static String REQUESTED_API_VERSION = "1.6.99"; // !final
|
||||
|
||||
|
||||
private static final String loggerFactoryClassStr = PluginSlf4jFactory.class.getName();
|
||||
|
||||
/** The ILoggerFactory instance returned by the {@link #getLoggerFactory} method
|
||||
* should always be the same object
|
||||
*/
|
||||
private final ILoggerFactory loggerFactory;
|
||||
|
||||
private StaticLoggerBinder() {
|
||||
// Note: JCL gets substituted at build time by an appropriate Ant task
|
||||
loggerFactory = new PluginSlf4jFactory();
|
||||
}
|
||||
|
||||
public ILoggerFactory getLoggerFactory() {
|
||||
return loggerFactory;
|
||||
}
|
||||
|
||||
public String getLoggerFactoryClassStr() {
|
||||
return loggerFactoryClassStr;
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
name: SSHD
|
||||
version: ${project.version}
|
||||
author: Ryan Michela, Haarolean, toxuin, Justin Crawford, Zachery Coleman
|
||||
main: com.ryanmichela.sshd.SshdPlugin
|
||||
load: STARTUP
|
||||
commands:
|
||||
mkpasswd:
|
||||
description: Make a SSHD password hash
|
||||
usage: /mkpasswd <hash|help> <password>
|
Loading…
Reference in New Issue